-
Notifications
You must be signed in to change notification settings - Fork 5
Dynamic behaviors
Dynamic behaviors are powered by Webpack Dynamic Imports. If you want to use dynamic behaviors, you need a little more Webpack config to tell manageBehaviors
and Webpack how to find dynamic behaviors so it can chunk and import them.
Dynamic behaviors are currently not supported by Vite due to some limitations from Rollup.
Firstly, lets assume the following folder structure:
.
+-- /src/
| +-- application.js
| +-- behaviors.js
| +-- /behaviors/
| +-- accordion.js
| +-- readMore.js
That is, all your behavior JS files are in the same folder.
The file names of your behaviors must match the behavior name - so if your behavior is called accordion
your behavior JS filename will be accordion.js
. When you run Webpack in production mode you may notice that it creates a chunk with a name like 845.js
- don't rename this, Webpack keeps a manifest internally for dynamic loading.
$ npm install webpack-watch-files-plugin
Why? Dynamically imported behaviors aren't imported into the main application JS and so Webpack's watcher may not pick up on changes to dynamically imported behaviors, this WatchExternalFilesPlugin
makes watching of dynamically imported behaviors more reliable.
We need to send through some additional process.env
variables:
new webpack.DefinePlugin({
'process.env.BEHAVIORS_PATH': JSON.stringify('/src/behaviors/'), // required for dynamically loaded behaviors, tells A17-Behaviors where your behavior JS files live
'process.env.BEHAVIORS_EXTENSION': JSON.stringify('js') // required for dynamically loaded behaviors, tells A17-Behaviors what your JS file extension is
}),
So, our webpack.common.js
would be something like:
const path = require('path');
const webpack = require('webpack');
const WatchExternalFilesPlugin = require('webpack-watch-files-plugin').default;
module.exports = {
entry: {
application: './src/application.js',
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'public'),
clean: true,
publicPath: process.env.ASSET_PATH || '/'
},
plugins: [
new WatchExternalFilesPlugin({
files: ['./src/behaviors/*.js']
}),
new webpack.DefinePlugin({
'process.env.BEHAVIORS_PATH': JSON.stringify('/src/behaviors/'),
'process.env.BEHAVIORS_EXTENSION': JSON.stringify('js')
}),
]
};
This will make process.env.BEHAVIORS_PATH
and process.env.BEHAVIORS_EXTENSION
available as variables within your application JavaScript.
And now Webpack will create chunks of all the behaviors in /src/behaviors/
ready for importing when required by manageBehaviors
. This may include critical behaviors already included in the main bundle which may mean your build task takes a fraction longer than it has to. So, you could instead scope your behaviors into different folders:
.
+-- /src/
| +-- application.js
| +-- behaviors.js
| +--
| +-- /behaviors-critical/
| +-- accordion.js
| +-- /behaviors-dynamic/
| +-- readMore.js
Then point 'process.env.BEHAVIORS_PATH'
to JSON.stringify('/src/behaviors-dynamic/')
and make sure your references in behaviors.js
point to /behaviors-critical/
.
What if all your behavior JS files aren't located in one single folder, but instead you have multiple component files and you want to use dynamic imports?
Eg:
.
+-- /components/
| +-- /accordion/
| +-- accordion.js
| +-- /readMore/
| +-- readMore.js
+-- /src/
| +-- application.js
| +-- behaviors.js
Well, in this case, you have 2 options.
- Alias behaviors
- Specify
process.env.BEHAVIORS_COMPONENT_PATHS
The simplist method is to use the Webpack config above and make behavior alises:
.
+-- /components/
| +-- /accordion/
| +-- accordion.js
| +-- /readMore/
| +-- readMore.js
|
+-- /src/
| +-- application.js
| +-- behaviors.js
| +--
| +-- /behaviors/
| +-- accordion.js
| +-- readMore.js
Where /src/behaviors/accordion.js
contains:
import accordion from '../../components/accordion/accordion';
export default accordion;
And now Webpack will create chunks of all the behaviors as though all your behavior src files lived in the same folder, you can split between critical and dynamic as needed.
Since v0.1.8
you can also specify process.env.BEHAVIORS_COMPONENT_PATHS
within your Webpack config.
Your file structure:
.
+-- /components/
| +-- /accordion/
| +-- accordion.js
| +-- /readMore/
| +-- readMore.js
+-- /src/
| +-- application.js
| +-- behaviors.js
Specifying process.env.BEHAVIORS_COMPONENT_PATHS
:
const path = require('path');
const webpack = require('webpack');
const WatchExternalFilesPlugin = require('webpack-watch-files-plugin').default;
module.exports = {
entry: {
application: './src/application.js',
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'public'),
clean: true,
publicPath: process.env.ASSET_PATH || '/'
},
plugins: [
new WatchExternalFilesPlugin({
files: ['./components/**/*.js']
}),
new webpack.DefinePlugin({
'process.env.BEHAVIORS_EXTENSION': JSON.stringify('js')
'process.env.BEHAVIORS_PATH': JSON.stringify('/components/'),
'process.env.BEHAVIORS_COMPONENT_PATHS': {
'accordion': JSON.stringify('accordion/'),
'readMore': JSON.stringify('readMore/')
},
}),
]
};
And now Webpack will create chunks of all the JavaScript files it finds in /components/
ready for importing when required by manageBehaviors
; with the caveat being that this may include making chunks for JavaScript files you don't want chunks generating for and so your build task may take a fraction longer than necessary but now we don't have the same option splitting critical from dynamic behaviors.