The Aurelia CLI includes a built-in bundler that uses RequireJS or SystemJS, offering an alternative to Webpack for managing module bundling. This bundler provides flexibility and ease of use, especially for developers preferring a more straightforward setup without the complexity of Webpack.
The CLI's built-in bundler is designed to simplify the bundling process by automatically handling module dependencies and optimizing the application for production. It supports both RequireJS and SystemJS module loaders, allowing developers to choose based on their project requirements.
To create a new project using the CLI's built-in bundler:
-
Initialize a New Project:
au new appName
-
Choose Configuration Options:
- Custom Setup: Select the Custom option when prompted.
- Bundler Selection: Choose between CLI's built-in bundler with RequireJS or CLI's built-in bundler with SystemJS.
- Transpiler: Select your preferred transpiler (Babel or TypeScript).
- CSS Preprocessor: Choose a CSS preprocessor if needed (e.g., Sass, Less).
-
Install Dependencies: The CLI will prompt to install the necessary dependencies. Confirm to proceed:
npm install
or
yarn install
After setup, your project will include the following key directories and files:
- aurelia_project/: Contains configuration files and Gulp tasks.
- tasks/: Holds Gulp task definitions.
- aurelia.json: Main configuration file for the bundler.
- src/: Your application's source code.
- package.json: Lists project dependencies and scripts.
Efficient dependency management is crucial for maintaining a scalable and maintainable project. The built-in bundler in Aurelia CLI simplifies this by offering both automatic and manual dependency tracing.
The built-in bundler automatically traces JavaScript dependencies, supporting various module formats:
-
Module Formats Supported:
- CommonJS
- AMD
- UMD
- Native ES Modules
-
Core Node.js Module Stubbing: The bundler stubs core Node.js modules to ensure browser compatibility, using the same stubs as Webpack and Browserify.
-
Aurelia View Template Tracing: Dependencies specified in Aurelia view templates using
<require>
are automatically traced and bundled. -
Automatic Installation: For ESNext applications, the bundler can automatically install missing NPM packages during development using the
--auto-install
flag:au run --auto-install
Warning:
The `--auto-install` flag is not supported for TypeScript projects due to TypeScript's compilation behavior.
While auto-tracing handles most dependencies, certain scenarios require manual intervention:
-
Modules Not Explicitly Required: Some modules may not be directly imported into your code. To include them in the bundle, specify them in the
dependencies
section ofaurelia.json
:"dependencies": [ "aurelia-bootstrapper", "aurelia-loader-default", "aurelia-pal-browser", { "name": "aurelia-testing", "env": "dev" }, "text" ]
-
Legacy Modules Without Module Support: For packages that do not support any module format, use the
prepend
orshim
configurations to integrate them:-
Prepend: Add the script paths in the
prepend
array to include them before the module loader:"bundles": [ { "name": "vendor-bundle.js", "prepend": [ "node_modules/jquery/dist/jquery.min.js", "node_modules/requirejs/require.js" ], "dependencies": [ /* ... */ ] } ]
-
Shim: Wrap the legacy scripts as AMD modules:
"dependencies": [ { "name": "tempusdominus-bootstrap-4", "deps": ["jquery", "bootstrap", "popper.js", "moment"], "wrapShim": true } ]
-
-
Conditional Bundling: Handle environment-specific dependencies by specifying the
env
property:{ "name": "aurelia-testing", "env": "dev" }
The built-in bundler offers advanced customization options to cater to complex project requirements. These include modifying module tracing behavior and globally configuring shim settings.
Customize how the bundler handles module tracing by implementing the onRequiringModule
callback in aurelia_project/tasks/build.js
:
function writeBundles() {
return buildCLI.dest({
onRequiringModule: function(moduleId) {
// Custom logic before tracing a module
if (moduleId === 'client-info') return false; // Ignore this module
if (moduleId === 'lodash') return ['lodash/core']; // Include specific sub-modules
if (moduleId === 'jquery') return `define(function() { return window.jQuery });`; // Supply module implementation directly
}
});
}
Usage Scenarios:
- Ignore Specific Modules: Prevent the bundler from including certain modules.
- Bundle Additional Dependencies: Manually include dependencies that are not auto-traced.
- Supply Module Implementations: Provide custom module implementations that are especially useful for legacy libraries.
Apply wrapShim
settings globally to all shimmed dependencies by modifying aurelia.json
:
"build": {
"loader": {
"type": "require",
"configTarget": "vendor-bundle.js",
"includeBundleMetadataInConfig": "auto",
"config": {
"wrapShim": true
}
}
}
{% hint style="info" %}
The wrapShim
option delays the execution of legacy code until the module is loaded, ensuring proper initialization.
{% endhint %}
Alias NPM packages to use local copies or alternative versions by specifying the path
and main
properties:
{
"name": "vscode",
"path": "../node_modules/monaco-languageclient/lib",
"main": "vscode-compatibility"
}
Usage:
- Useful for projects that require patched versions of libraries or local modifications.
Optimize bundle size by enabling lazy loading for certain packages:
{
"name": "lodash",
"path": "../lodash",
"lazyMain": true
}
Behavior:
- Only the modules explicitly imported (e.g.,
import { map } from 'lodash/map';
) are bundled. - The main file is bundled only when
import _ from 'lodash';
is used.
Leverage the flexibility of RequireJS and SystemJS to implement advanced bundling strategies.
Include scripts before the module loader to integrate non-module libraries:
"bundles": [
{
"name": "vendor-bundle.js",
"prepend": [
"node_modules/jquery/dist/jquery.min.js",
"node_modules/moment/min/moment-with-locales.min.js",
"node_modules/popper.js/dist/umd/popper.min.js",
"node_modules/bootstrap/dist/js/bootstrap.min.js",
"node_modules/tempusdominus-bootstrap-4/build/js/tempusdominus-bootstrap-4.min.js",
"node_modules/requirejs/require.js"
],
"dependencies": [ /* ... */ ]
}
]
Example Usage: Integrating tempusdominus-bootstrap-4
with dependencies:
// main.ts
import * as moment from 'moment';
window.moment = moment;
// app.ts
import * as $ from 'jquery';
import 'tempusdominus-bootstrap-4';
export class App {
value = moment();
attached() {
$('#datetimepicker1').datetimepicker({
date: this.value
});
$('#datetimepicker1').on('change.datetimepicker', e => {
this.value = e.date;
});
}
detached() {
$('#datetimepicker1').datetimepicker('destroy');
}
}
<!-- app.html -->
<template>
<require from="font-awesome/css/font-awesome.min.css"></require>
<require from="bootstrap/css/bootstrap.min.css"></require>
<require from="tempusdominus-bootstrap-4/build/css/tempusdominus-bootstrap-4.min.css"></require>
<div class="container">
<div class="row">
<div class="col-sm-6">
<p>Value: ${value}</p>
<div class="form-group">
<div class="input-group date" id="datetimepicker1" data-target-input="nearest">
<input type="text" class="form-control datetimepicker-input" data-target="#datetimepicker1">
<div class="input-group-append" data-target="#datetimepicker1" data-toggle="datetimepicker">
<div class="input-group-text"><i class="fa fa-calendar"></i></div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
{% hint style="warning" %}
Avoid importing $
from 'jquery' after it has been prepended to prevent duplicate instances.
{% endhint %}
Wrap legacy libraries that do not support module loaders using shims:
"dependencies": [
{
"name": "tempusdominus-bootstrap-4",
"deps": ["jquery", "bootstrap", "popper.js", "moment"],
"wrapShim": true
}
]
Example: Exposing moment
globally for legacy compatibility:
// main.ts
import * as moment from 'moment';
window.moment = moment;
// app.ts
import * as $ from 'jquery';
import 'tempusdominus-bootstrap-4';
{% hint style="warning" %}
Use the wrapShim
option to delay the execution of legacy scripts until all dependencies are loaded.
{% endhint %}
The following recipes demonstrate common integration scenarios with the CLI's built-in bundler, including popular libraries and handling specific requirements.
-
Install jQuery:
npm install jquery
or
yarn add jquery
-
Import jQuery in your TypeScript or JavaScript files:
import * as $ from 'jquery';
-
Install Normalize.css:
npm install normalize.css
or
yarn add normalize.css
-
Include in Your HTML Templates:
<template> <require from="normalize.css"></require> </template>
-
Install Bootstrap and Dependencies:
npm install jquery bootstrap popper.js
or
yarn add jquery bootstrap popper.js
-
Import Bootstrap JavaScript in
main.ts
:import 'bootstrap';
-
Include Bootstrap CSS in your HTML templates:
<template> <require from="bootstrap/css/bootstrap.min.css"></require> </template>
-
Initialize a New Project with Sass:
au new demo
- Choose Custom setup.
- Select CLI's built-in bundler with RequireJS or SystemJS.
- Choose Babel or TypeScript.
- Select Sass as the CSS preprocessor.
-
Install Dependencies:
npm install jquery bootstrap popper.js
or
yarn add jquery bootstrap popper.js
-
Customize Bootstrap Variables in
app.scss
:// app.scss $grid-columns: 24; // Customize to use 24 columns @import '../node_modules/bootstrap/scss/bootstrap';
-
Include Compiled CSS in
app.html
:<template> <require from="./app.css"></require> </template>
{% hint style="info" %}
Unlike Webpack, the built-in bundler processes Sass files before bundling. Use .css
in <require>
statements.
{% endhint %}
-
Install Bootstrap v3 and Dependencies:
npm install jquery [email protected]
or
yarn add jquery [email protected]
-
Configure
aurelia.json
:"bundles": [ { "name": "vendor-bundle.js", "prepend": [ "node_modules/jquery/dist/jquery.min.js", "node_modules/requirejs/require.js" ], "dependencies": [ "aurelia-bootstrapper", "aurelia-loader-default", "aurelia-pal-browser", { "name": "bootstrap", "deps": ["jquery"], "path": "../node_modules/bootstrap", "main": "dist/js/bootstrap.min" } ] } ], "copyFiles": { "node_modules/bootstrap/dist/fonts/*": "bootstrap/fonts" }
-
Import Bootstrap JavaScript in
main.ts
:import 'bootstrap';
-
Include Bootstrap CSS in
app.html
:<template> <require from="bootstrap/css/bootstrap.min.css"></require> </template>
{% hint style="info" %}
Both bootstrap/css/bootstrap.min.css
and bootstrap/dist/css/bootstrap.min.css
are valid paths. Ensure the copyFiles
target path matches your CSS inclusion.
{% endhint %}
-
Install Font Awesome:
npm install @fortawesome/fontawesome-free
or
yarn add @fortawesome/fontawesome-free
-
Configure
aurelia.json
:"copyFiles": { "node_modules/@fortawesome/fontawesome-free/webfonts/*": "@fortawesome/fontawesome-free/webfonts" }
-
Include Font Awesome CSS in
app.html
:<template> <require from="@fortawesome/fontawesome-free/css/all.min.css"></require> <require from="@fortawesome/fontawesome-free/css/v4-shims.min.css"></require> <!-- Optional for v4 compatibility --> <i class="fas fa-cube"></i> </template>
-
Install Font Awesome v4:
npm install font-awesome
or
yarn add font-awesome
-
Configure
aurelia.json
:"copyFiles": { "node_modules/font-awesome/fonts/*": "font-awesome/fonts" }
-
Include Font Awesome CSS in
app.html
:<template> <require from="font-awesome/css/font-awesome.min.css"></require> <i class="fa fa-cube"></i> </template>
-
Install Foundation and Dependencies:
npm install jquery what-input foundation-sites
or
yarn add jquery what-input foundation-sites
-
Import Foundation JavaScript in
main.ts
:import 'what-input'; import 'foundation-sites';
-
Configure
app.ts
:import * as $ from 'jquery'; import * as Foundation from 'foundation-sites'; export class App { tooltip: any; attached() { this.tooltip = new Foundation.Tooltip($('#demo')); } detached() { if (this.tooltip) { this.tooltip.destroy(); this.tooltip = null; } } }
-
Include Foundation CSS in
app.html
:<template> <require from="foundation-sites/css/foundation.min.css"></require> <span ref="demo" data-tooltip class="top" tabindex="2" title="Fancy word for a beetle.">demo</span> </template>
-
Install Materialize and Dependencies:
npm install jquery materialize-css
or
yarn add jquery materialize-css
-
Configure
app.ts
:import * as materialize from 'materialize-css'; export class App { modal: HTMLElement; attached() { materialize.Modal.init(this.modal); } detached() { const instance = materialize.Modal.getInstance(this.modal); if (instance) instance.destroy(); } }
-
Include Materialize CSS in
app.html
:<template> <require from="materialize-css/css/materialize.min.css"></require> <a class="waves-effect waves-light btn modal-trigger" href="#modal1">Modal</a> <div ref="modal" id="modal1" class="modal"> <div class="modal-content"> <h4>Modal Header</h4> <p>A bunch of text</p> </div> <div class="modal-footer"> <a href="#!" class="modal-close waves-effect waves-green btn-flat">Agree</a> </div> </div> </template>
-
Install TypeORM:
npm install typeorm
or
yarn add typeorm
-
Configure
aurelia.json
:"bundles": [ { "name": "vendor-bundle.js", "prepend": [ /* ... */ ], "dependencies": [ /* ... */ { "name": "typeorm", "path": "../node_modules/typeorm", "main": "typeorm-model-shim" } ] } ], "paths": { "entities": "../../server/src/entity" }
-
Adjust
tsconfig.json
:{ "compilerOptions": { /* ... */ "paths": { "entities/*": ["../../server/src/entity/*"] }, "baseUrl": "src" } }
-
Usage in Code:
import { Entity, PrimaryGeneratedColumn, Column } from 'entities/customer'; @Entity() export class Customer { @PrimaryGeneratedColumn() id: number; @Column() name: string; }
{% hint style="info" %}
Ensure that the aurelia.json
paths align with your server-side entity locations to maintain consistency between frontend and backend models.
{% endhint %}
Resources not handled by JavaScript module loaders, such as fonts and images, need to be copied to the appropriate output directories.
-
Configure
aurelia.json
:"copyFiles": { "node_modules/font-awesome/fonts/*": "font-awesome/fonts", "node_modules/some-library/images/*": "some-library/images" }
-
Usage in CSS:
/* Example in CSS */ @font-face { font-family: 'FontAwesome'; src: url('font-awesome/fonts/fontawesome-webfont.woff2') format('woff2'), url('font-awesome/fonts/fontawesome-webfont.woff') format('woff'); font-weight: normal; font-style: normal; }
{% hint style="info" %} Ensure that all copied files are referenced correctly in your CSS or HTML to load resources at runtime. {% endhint %}
Simplify import statements by defining path mappings in aurelia.json
and tsconfig.json
.
-
Configure
aurelia.json
:"paths": { "root": "src", "resources": "resources", "elements": "resources/elements", "attributes": "resources/attributes", "valueConverters": "resources/value-converters", "bindingBehaviors": "resources/binding-behaviors", "models": "common/models" }
-
Configure
tsconfig.json
:{ "compilerOptions": { /* ... */ "paths": { "models/*": ["src/common/models/*"] }, "baseUrl": "." } }
-
Usage in Imports:
import { Customer } from 'models/customer';
{% hint style="info" %}
Restart your editor after updating tsconfig.json
to ensure path mappings are recognized.
{% endhint %}
Manage and import styles effectively within your Aurelia application.
-
Without CSS Preprocessor:
<template> <require from="./styles.css"></require> </template>
-
With CSS Preprocessor (e.g., Sass):
-
Write styles in
.scss
files. -
Import compiled
.css
files in your HTML templates:<template> <require from="./styles.css"></require> </template>
-
{% hint style="info" %}
Unlike Webpack, the built-in bundler processes styles before bundling. Always reference the compiled .css
files in your templates.
{% endhint %}
Keep your project's dependencies up-to-date to leverage improvements and patches.
-
Updating a Single Library:
npm install <library-name>@latest
or
yarn add <library-name>@latest
-
Updating Multiple Libraries:
-
Define an Update Script in
package.json
:"scripts": { "au-update": "npm install aurelia-binding@latest aurelia-bootstrapper@latest ..." }
-
Run the Update:
npm run au-update
or
yarn run au-update
-
{% hint style="info" %} Ensure updated libraries are compatible with Aurelia version 1 to prevent integration issues. {% endhint %}
Optimize your application's performance by minifying JavaScript during production builds.
-
Default Minification Settings in
aurelia.json
:"options": { "minify": "stage & prod", "sourcemaps": "dev & stage" }
-
Custom Minification Options:
"options": { "minify": { "dev": false, "default": { "indent_level": 2 }, "stage & prod": { "max-line-len": 100000 } } }
- Minifier Used: Terser (terser GitHub) supports options compatible with UglifyJS2 and Uglify-ES.
{% hint style="info" %} Adjust minification options to balance between build performance and code optimization based on your project needs. {% endhint %}