☁️ SFDX SPA StaticResource Bundler Guide 🚀
Guided tutorials/examples of how to implement SPA (Single Page Applications) w/ your salesforce sfdx project.
- Salesforce guide on getting your local machine setup with vscode, sfdx cli, etc. here
- What is salesforce sfdx?
- What are staticresources?
- What is a spa (single page application)?
The point of this guide is showcase strategies across different tools/scaffolding/frameworks, how to bundle and deploy to salesforce. Additionally when possible automate this process 🔥
When building SPA's on salesforce, our main objective is to:
- Build our applications in modern javascript/typescript etc.
- Run our build tooling to transpile (convert to old syntax), bundle and minify our source code to the
force-app/main/default/staticresource/
directory. - Deploy our development/production builds to our salesforce orgs/or package them.
There are several open source build-tooling options available out there but webpack and rollup seem to be the most predominant/favorabale. If not possible w/ chosen scaffolding can always resort to scripting. In the examples we'll be using webpack but similar results can be accomplished with rollup
.
frontend-app
├── README.md
├── package.json
├── node_modules
├── src
| ├── app.js
| ├── components
| └── library
app.js Example Source code (react)
class Square extends React.Component {
render() {
return <button className="square">{this.props.value}</button>;
}
}
frontend-app
├── README.md
├── package.json
├── node_modules
├── dist
│ ├── 0.bundle.js
│ ├── app.bundle.js
| └── app.css
├── src
| ├── app.js
| ├── components
| └── library
app.bundle.js Transpiled/Bundled code
var Square = /*#__PURE__*/ function (_React$Component) {
_inherits(Square, _React$Component);
var _super = _createSuper(Square);
function Square() {
_classCallCheck(this, Square);
return _super.apply(this, arguments);
}
_createClass(Square, [
{
key: "render",
value: function render() {
return /*#__PURE__*/ React.createElement(
"button",
{
className: "square",
},
this.props.value
);
},
},
]);
return Square;
};
- Create a sfdx project
- Create our frontend project in a new sub-directory
- Setup the project tooling where we'll point the build destination in our
staticresources
dir - Create a
[foldername].resource-meta.xml
file for each direct child folder/file inside of ourstaticresources
directory. (Either during the build process or post build) - 🔥 Finally deploy those files to your salesforce org 🔥
Step 1: Create a sfdx project
In the terminal type in
sfdx force:project:create --projectname salesforce-project
:filefolder: _Sfdx project we just created
salesforce-project
├── README.md
├── sfdx-project.json
├── .sfdx
├── .vscode
│ ├── extensions.json
│ └── settings.json
├── force-app
| └── main
| └── default
| ├── aura
| ├── classes
| ├── objects
| └── staticresources
├── manifest
| └── package.xml
In order to deploy later on you'll need to authorize your salesforce dev/hub org.
Step 2: Create and setup our frontend project inside of our root salesforce-project
mkdir src
and then change into that new directory
cd src
This is when you can decide if you want to setup a scaffolding/framework of your choosing. For sake of demonstration we'll go w/ a vanilla 🍦 js example.
Create our npm package.json to track our dependencies and add our scripts
npm init -y
Create a index.js file inside of the src
directory
/* If want to include polyfills */
import "core-js/stable";
import "regenerator-runtime/runtime";
const app = () => {
const root = document.createElement("div");
root.innerHtml = `Hello World`;
return root;
};
document.body.appendChild(app());
Step 3: Setup our projects tooling with webpack
Install dev dependencies
npm install --save-dev webpack webpack-cli babel-loader @babel/core @babel/preset-env
Install dependencies
npm install --save core-js@3
# Inside of root directory
touch webpack.config.js
Setup our webpack config, can copy and paste from below
webpack.config.js
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "[name].bundle.js",
// will output all assets that run through webpack in our staticresources directory
path: path.resolve(__dirname, "force-app/main/default/staticresources/app"),
},
/*
When webpack runs, it'll read the contents of your files. When it encounters either a `import` or a `require` statement, it will run the regex test rule to determine to run each loader
on the current file. So example below, all js files will run through babel so we can use the latest and greatest syntax features. However you will need add polyfills to work in older browsers
*/
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: [
"@babel/preset-env",
{
useBuiltIns: "usage",
corejs: 3,
},
],
},
},
},
],
};
Modify the package.json (in your src
directory) file and add a script
"scripts": {
"build": "webpack --config webpack.config.js"
}
Step 4: Create our [foldername].resource-meta.xml
file
We then place these files and assets in our local sfdx staticresources
project directory along w/ a [foldername].resource-meta.xml
file.
app.resource-meta.xml
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<StaticResource xmlns="http://soap.sforce.com/2006/04/metadata">
<cacheControl>Public</cacheControl>
<contentType>application/zip</contentType>
</StaticResource>
This file is needed so salesforce knows how to compress and store them in the salesforce provided cdn to use throughout your visualforce pages and lightning components.
Run the script, either through the terminal or if using vscode can click on npm scripts button
npm run build
📁 What the current project should look like
salesforce-project
├── README.md
├── sfdx-project.json
├── .sfdx
├── .vscode
│ ├── extensions.json
│ └── settings.json
├── force-app
| └── main
| └── default
| ├── aura
| ├── classes
| ├── objects
| └── staticresources
| ├── app ** WHERE our Bundled Assets Will Go
| └── app.resource-meta.xml
├── src
| ├── node_modules
| ├── package.json
| └── index.js
├── manifest
| └── package.xml
Step 5: Deploy to your salesforce Org (make sure you authenticated an org)
run in your terminal
sfdx force:source:deploy -p force-app/main/default/staticresources/app
If you wish to automate the above tutorial, take a look at the Vanilla Project Webpack example.
quick note
Staticresources have a 5mb limit per folder and a 250mb limit org wide. With this limitation and to avoid issues down the line, the examples/guides are strutured to only include production/shipping code in the staticresource folders. Read more here.
If you prefer to set up your own JavaScript toolchain from scratch.
If you prefer lightning-web-components (Open Source)
as your frontend framework of choice and create-lwc-app
for your project scaffolding 🔥
Coming Soon
- Can create a similar scaffolding to create-react-app starting from the vanilla project example. Guide on creating your own project tooling
Submit a pull request to contribute
or
Submit a issue if you would like to see more examples or update current ones