Creating a Locker Service-compatible bundle with webpack

Note that the tools we use here include webpack 3.0, npm, and Node.js. To run the project, it is assumed that your machine has the latest Version of Node.js, npm, and webpack 3.0 installed.

At the time of writing this book, my npm Version is 5.6.0, Node.js Version is 9.50, and webpack Version is 3.8.1.

If you do not have them, then install them using brew for macOS with the following commands.

For Node.js and npm, use the following:

brew install node

To install webpack, use the following. The following command installs it locally for a specific project and version:

npm install --save-dev [email protected]

Let's take a step-by-step look at how to use an ES6 JavaScript open source plugin, make it locker-compliant, and build it into a resource bundle that can be used inside Lightning Components:

  1. Create an index.js file that imports the choices.js library: You will need a package.json file first that has all the node modules for dependencies and the dev dependencies for the project. The package.json is as follows:
{
"name": "choicesJS",
"version": "1.0.0",
"main": "src/index.js",
"author": "Mohith Shrivastava",
"license": "BSD-3-Clause",
"devDependencies": {
"@Salesforce/eslint-plugin-aura": "^1.0.0",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.1",
"css-loader": "^0.28.7",
"eslint": "^4.10.0",
"eslint-loader": "^1.9.0",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^1.1.5",
"imports-loader": "^0.7.1",
"loader-utils": "^1.1.0",
"url-loader": "^0.6.2",
"webpack": "^3.8.1"
},
"dependencies": {
"choices.js": "^3.0.2"
},
"scripts": {
"build": "webpack --config webpack.config.js"
}
"browserlist": "last 2 versions, ie 11"
}

Now, the index.js file will be in the src directory as following. We use TypeScript here, and later you will see our webpack is configured to transpile to ES5:

import 'choices.js/assets/styles/css/choices.css';
import Choices from 'choices.js';
export { Choices };
  1. Create a webpack config file: The complete webpack config file is located at https://github.com/PacktPublishing/Learning-Salesforce- Lightning-Application-Development/blob/master/chapter7/staticresources-src/webpack.config.js. We will take a step-by-step look at it:
    1. The entry point in webpack.config.js will be index.js:
// this is where our source code is stored
context: srcPath,
// single entry point
entry: {
app: './index.js',
}
  1. Output: The output will be in the staticresources folder of the SFDX project, so the code snippet to configure it is as follows:
output: {
// output file into SFDX staticresources location
path: distPath,
filename: 'app.resource',
libraryTarget: 'window',
library: 'StaticResource'
}
  1. Loaders: We are using the following loaders that are pre-built: 
Loaders Description
babel-loader

Transpile ES2015 to ES5.

url-loader

Load all CSS files and compile them into a single artifact, styles.resource.

import-loader

To switch off AMD by using define as false. Locker does not support the AMD format.

css-loader

Load all pictures and fonts and embed them into styles.resource.

 

We also have a custom loader that's built to remove the polyfill on the window object so that the library works under Locker Service.

The code for the custom loader is as follows, and is placed in a folder named loader:

const loaderUtils = require('loader-utils');

const lockerObjects = [
'CustomEvent',
'Event',
'Storage',
'Object',
'Node',
'Notification',
'RTCPeerConnection',
'CanvasRenderingContext2D',
'Navigator',
'HTMLIFrameElement',
'HTMLScriptElement',
];


module.exports = function UnpolyfillLoader (source) {
const header = 'const _lockerObjects = { ' +
lockerObjects.map(o => `'${o}': window.${o}`).join(', ') +
' }; ';
const footer = ' ' +
lockerObjects.map(o => `window.${o} = _lockerObjects.${o}`).join('; ') +
' ';
return header + source + footer;
}

The following code shows how webpack is configured to indicate the loaders: 

const webpack = require('webpack'),
path = require('path'),
ExtractTextPlugin = require('extract-text-webpack-plugin');

const srcPath = path.join(__dirname, 'src'),
distPath = path.join(__dirname, '../force-app/main/default/staticresources'),
extractCSS = new ExtractTextPlugin('styles.resource');

module.exports = {
module: {
rules: [
// Lint our ES6 code and transpile it into ES5 as a part of app.resource
{
test: /.js$/,
exclude: /node_modules/,
use: [{
loader: 'babel-loader',
options: {
presets: ['env'],
}
},
{ loader: "eslint-loader" },
]
},
// Load choices.js, remove polyfills' effects, and include it into app.resource
{
test: //choices.js/assets/scripts/dist/,
use: [ 'unpolyfill-loader', 'imports-loader?define=>false' ],
},
// Load all CSS files and compile them in a single artifact styles.resource
{
test: /.css$/,
use: ExtractTextPlugin.extract({
use: 'css-loader',
}),
},
// Load all pictures and fonts and embed them into styles.resource
{
test: /.(woff2?|ttf|eot|jpe?g|png|gif|svg)$/,
use: 'url-loader',
},
],
},
// resolve loaders from node_modules and our newly created "loaders" folder
resolveLoader: {
modules: [ 'node_modules', path.resolve(__dirname, 'loaders') ],
},
  1. Plugins: All the plugins that are needed are shown in the following snippet:
resolve: {
modules: ["node_modules"],
},
plugins: [
new webpack.NoEmitOnErrorsPlugin(),
extractCSS,
]
  1. Use the eslint plugin aura for finding any linting and code issues. The npm module is located at https://www.npmjs.com/package/@Salesforce/eslint-plugin-aura. Create a .eslintrc.yml file for the project in the src folder with the following code snippet:
plugins:
- "@Salesforce/eslint-plugin-aura"
extends:
- "plugin:@Salesforce/eslint-plugin-aura/recommended"
parserOptions:
ecmaVersion: 6
sourceType: module
  1. Build the bundle using the npm build command: Running npm build runs webpack and produces bundles named app.resource and styles.resource:
npm build
  1. Include the library in Lightning Components using the ltng:require tag, and load scripts and styles. The working code is as follows:
<aura:component >
<ltng:require styles="{!$Resource.styles}" scripts="{!$Resource.app}" afterScriptsLoaded="{!c.jsLoaded}" />
<div>
<input type="text" aura:id="choices" />
</div>
</aura:component>

  The controller code is as follows:

({
jsLoaded : function(component, event, helper) {
console.log(window);
console.log(window.StaticResource);
const choices = new StaticResource.Choices(component.find('choices').getElement(), {
items: [ 'India', 'Australlia', 'China' ]
})
}
})

If your code is working, the component on the test app will look like the following screenshot:

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.104.95