The bundles themselves are configured in the webpack.config.js
file. By default, the skeleton defines three entry bundles:
aurelia-bootstrap
: Contains Aurelia's bootstrapper, the default polyfills, Aurelia's browser platform abstraction, and the Bluebird Promise libraryaurelia
: Contains all Aurelia's default librariesapp
: Contains all application modules
In addition to the modules listed as its direct content, a bundle will contain all its contents' dependencies which are not included in another bundle. For example, in the skeleton's sample, the Bootstrap JS files are included in the app
bundle, because it is not included in any other bundle, and modules included in the app
bundle import it.
If you would like, for example, the aurelia
bundle to contain all external libraries, you should add bootstrap
to the list of modules included in it:
webpack.config.js
//Omitted snippet...
const coreBundles = {
bootstrap: [
//Omitted snippet...
],
aurelia: [
//Omitted snippet...
'aurelia-templating-binding',
'aurelia-templating-router',
'aurelia-templating-resources',
'bootstrap'
]
}
//Omitted snippet...
If you run the sample application at this point, Bootstrap's JS files should now be included in the aurelia
bundle instead of the app
bundle.
All bundles defined in the skeleton's sample application are entry bundles, which means those bundles are loaded directly by the index.html
file. All this code is loaded upfront, before the application starts.
As discussed in Chapter 10 , Bundling for Production, depending on your application's usage patterns and how it is structured, it may be better performance-wise to have different parts of the application bundled separately, and to have some of those bundles loaded only when needed.
Configuration of lazy-loaded bundles is done in the package.json
file:
{ //Omitted snippet... "aurelia": { "build": { "resources": [ { "bundle": "contacts", "path": [ "contacts/components/creation", "contacts/components/details", "contacts/components/edition", "contacts/components/form", "contacts/components/list", "contacts/components/photo", "contacts/models/address", "contacts/models/contact", "contacts/models/email-address", "contacts/models/phone-number", "contacts/models/social-profile", "contacts/main" ], "lazy": true } ] } } //Omitted snippet... }
In this example, we bundle all components and models from the contacts
feature of our contacts management application in a distinct, lazy-loaded bundle. With this configuration, the contacts
bundle would be loaded from the server only when a user navigates to one of the contacts' route components.
As for dependency inclusion, a lazy-loaded bundle will behave just like an entry bundle. In addition to the modules listed in its configuration, a lazy-loaded bundle will also contain all dependencies that were not already included in any of the entry bundles. This means that if you import
stuff from an external library only inside a module that is included in a given bundle and nowhere else in your application, and if you don't include this external library in one of the entry bundles, the library will be included in your lazy-loaded bundle. This is an important thing to consider when optimizing your application's bundling.
The Webpack skeleton uses an environment variable named NODE_ENV
in order to customize the bundling process based on the context. This environment variable is set to either development
, test
, or production
by the tasks described in package.json
.
If you take a look in the webpack.config.js
file, you will see a switch
statement which generates a Webpack configuration object based on the environment. This is where you can customize bundling depending on the environment.
For example, if you use the aurelia-i18n
plugin, you may want to copy the locales
directory to the dist
directory when you build your application. The simplest way to do this is to add the following line to both production and development configurations:
webpack.config.js
//Omitted snippet... config = generateConfig( baseConfig, //Omitted snippet... require('@easy-webpack/config-copy-files') ({patterns: [{ from: 'favicon.ico', to: 'favicon.ico' }]}), require('@easy-webpack/config-copy-files') ({patterns: [{ from: 'locales', to: 'locales' }]}), //Omitted snippet... ); //Omitted snippet...
Additionally, if you want to use the aurelia-testing
plugin, either to use the component tester in your unit tests or to use the view-spy
and compile-spy
attributes for debugging purposes, you should install it using NPM and add it to the aurelia
bundle for both test
and development
environments:
webpack.config.js
//Omitted snippet...
coreBundles.aurelia.push('aurelia-testing');
config = generateConfig(
baseConfig,
//Omitted snippet...
);
//Omitted snippet...
Configuring Webpack can be complicated and intimidating at first. The Webpack skeleton uses easy-webpack
(https://github.com/easy-webpack/core) to simplify this configuration process. Another huge advantage of using easy-webpack
is that it enforces community standards, and it makes reusing complex snippets of configuration pretty easy.
As such, you can use one of the many configuration modules available at https://github.com/easy-webpack or others, or even your own, to customize further Webpack's configuration.