CLI
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.
CLI’s Built-in Bundler
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.
Setting Up the Built-in Bundler
To create a new project using the CLI's built-in bundler:
Initialize a New Project:
au new appNameChoose 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 installor
yarn install
Project Structure
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.
Dependency Management
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.
Auto 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-installflag:au run --auto-installWarning:
The `--auto-install` flag is not supported for TypeScript projects due to TypeScript's compilation behavior.
Manual Tracing
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
dependenciessection 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
prependorshimconfigurations to integrate them:Prepend: Add the script paths in the
prependarray 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
envproperty:{ "name": "aurelia-testing", "env": "dev" }
Advanced Usage
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.
onRequiringModule Callback
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.
Global wrapShim Configuration
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
}
}
}NPM Package Alias
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.
Lazy Bundling of Main Files
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.
CLI + Built-in Bundler Advanced
Leverage the flexibility of RequireJS and SystemJS to implement advanced bundling strategies.
Prepend Configuration
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>Avoid importing $ from 'jquery' after it has been prepended to prevent duplicate instances.
Shim Configuration
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';Use the wrapShim option to delay the execution of legacy scripts until all dependencies are loaded.
CLI’s Built-in Bundler Cookbook
The following recipes demonstrate common integration scenarios with the CLI's built-in bundler, including popular libraries and handling specific requirements.
jQuery Integration
Install jQuery:
npm install jqueryor
yarn add jqueryImport jQuery in your TypeScript or JavaScript files:
import * as $ from 'jquery';
Normalize.css
Install Normalize.css:
npm install normalize.cssor
yarn add normalize.cssInclude in Your HTML Templates:
<template> <require from="normalize.css"></require> </template>
Bootstrap CSS v4
Install Bootstrap and Dependencies:
npm install jquery bootstrap popper.jsor
yarn add jquery bootstrap popper.jsImport Bootstrap JavaScript in
main.ts:import 'bootstrap';Include Bootstrap CSS in your HTML templates:
<template> <require from="bootstrap/css/bootstrap.min.css"></require> </template>
Customize Bootstrap CSS v4
Initialize a New Project with Sass:
au new demoChoose 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.jsor
yarn add jquery bootstrap popper.jsCustomize 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>
Bootstrap CSS v3 (Legacy)
Install Bootstrap v3 and Dependencies:
npm install jquery bootstrap@3.3.7or
yarn add jquery bootstrap@3.3.7Configure
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>
Font Awesome v5 Free
Install Font Awesome:
npm install @fortawesome/fontawesome-freeor
yarn add @fortawesome/fontawesome-freeConfigure
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>
Font Awesome v4
Install Font Awesome v4:
npm install font-awesomeor
yarn add font-awesomeConfigure
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>
Foundation CSS v6
Install Foundation and Dependencies:
npm install jquery what-input foundation-sitesor
yarn add jquery what-input foundation-sitesImport 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>
Materialize CSS v1
Install Materialize and Dependencies:
npm install jquery materialize-cssor
yarn add jquery materialize-cssConfigure
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>
TypeORM with Shimmed Decorators
Install TypeORM:
npm install typeormor
yarn add typeormConfigure
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; }
Copying Other Files (e.g., Fonts)
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; }
Path Mappings
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';
Styling Your Application
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
.scssfiles.Import compiled
.cssfiles in your HTML templates:<template> <require from="./styles.css"></require> </template>
Updating Libraries
Keep your project's dependencies up-to-date to leverage improvements and patches.
Updating a Single Library:
npm install <library-name>@latestor
yarn add <library-name>@latestUpdating 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-updateor
yarn run au-update
JavaScript Minification
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.
Last updated
Was this helpful?