Get the Newsletter

CLI's built-in Bundler

Basics features of the Aurelia CLI's built-in Bundler.

Introduction

This page is specifically for people using the CLI's built-in Bundler (with RequireJS or SystemJS).

To choose the built-in bundler, create an app with au new appName, choose 3. Custom, then choose 2. CLI's built-in bundler with RequireJS or 3. CLI's built-in bundler with SystemJS.

If you're using Webpack then the Webpack section is what you want to read.

ASP.NET Core

If you would like to use ASP.NET Core, first begin by using Visual Studio to create your ASP.NET Core project. Select whatever options make the most sense based on your .NET project plans. After you have created the project, open a command line and change directory into your web project's project folder. This is the folder that contains the .xproj file. From within this folder, you can execute the following command au new --here which will setup Aurelia "here" inside this project folder. You will be prompted to choose the platform you want. Simply select "ASP.NET Core". Follow the prompts for the rest of the process, just like above.

Since Aurelia-CLI should be in charge of building your client-side code, make sure before running the new command from Aurelia-CLI you add <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked> to your .xproj file inside the first <PropertyGroup></PropertyGroup> you find to stop Visual Studio from compiling the .ts files in your project. If you build your solution before doing this, Visual Studio will compile your .ts files breaking some of the Aurelia-CLI commands.

When developing an ASP.NET Core application you will want to set the ASPNETCORE_ENVIRONMENT environment variable. Detailed instructions can be found on the Microsoft Docs .

Running the application

This section does not apply to ASP.NET JavascriptServices

Running an Aurelia-CLI application is simple: au run and you're on your way. But it's good to be aware of other flags that can be supplied to the au run command. au --help shows you all supported flags.

Deploying Your App

Run build command au build --env prod, then copy following items to the main deployment folder on your server:

  1. index.html
  2. /scripts
  3. any other folders (for example fonts folder) generated by copyFiles. See "Copy Other Files" below.

Unit Testing

If you selected a project setup that includes unit tests, you can run your tests with au test. If you would like to adopt a tdd-based workflow, writing code and tests with continual test evaluation, you can use the --watch flag. For example: au test --watch.

If you choose jest as the unit test runner, use au jest to run your tests.

Build Revisions

To create builds with revision numbers, you must set rev to be true under the build options. This will cause a unique revision number to be added to the bundled files. For example:

    
  "options": {
    "minify": "stage & prod",
    "sourcemaps": "dev & stage",
    "rev": true
  }
  
  

You are also able to set specific flags so that build revisions only take place while staging or in production. For example:

    
  "options": {
    "minify": "stage & prod",
    "sourcemaps": "dev & stage",
    "rev": "stage & prod"
  }
  
  

Now, if you were to run au build --env prod, the output would contain build revisions, while au build --env dev would not. Setting the build revisions to only compile while in production can help the development process, since it keeps your workspace clean of various build revisions.

Caching

For a new app, the cache is turned on for dev and stage environments. If you want to turn on cache for all environments, change the setting to "cache": true.

    
  "options": {
    "minify": "stage & prod",
    "sourcemaps": "dev & stage",
    "rev": false,
    "cache": "dev & stage"
  }
  
  

The cache setting controls two caching behaviors to speed up consecutive builds.

  1. caches tracing result. This cache is centralized in OS temp directory and shared among all apps using CLI bundler.
  2. for an ESNext app, aurelia_project/tasks/transpile.js caches babel transpiling result using gulp-cache. The transpiling cache is dedicated per app per environment, not shared with other apps.

No transpiling cache for TypeScript app

We have not found a way to get gulp-typescript working with gulp-cache.

To reset cache, run au clear-cache. This command clears up all caches created by either CLI bundler or gulp-cache. Note it clears caches of all CLI bundler apps, not just the app you are working on.

Modifying The Index File

In order for your index.html file to be updated to load up the correct revisioned bundle, you must ensure that the "index" property located in build/targets section is correctly pointing to the index.html (or starting page) for your project. For example:

    
  "build": {
    "targets": [
      {
        "id": "web",
        "displayName": "Web",
        "output": "scripts",
        "index": "index.html"
      }
    ]
  }
  
  

Bundling And Code Splitting

By default, the CLI bundler creates two bundles, an app-bundle.js, and a vendor-bundle.js. This is code splitting out of the box.

An example of the default app-bundle.js looks like this:

    
  {
    "name": "app-bundle.js",
    "source": [
      "**/*.{js, css,html}"
    ]
  }
  
  

In this setup, we've named the bundle app-bundle.js, and have defined what's included by setting the source property to be an array of patterns that match to file paths (the patterns are using glob patterns, minimatch to be specific, to find files that match). Optionally, you can define an exclude list by setting the source property to be an object containing both an include and exclude array of patterns. This is helpful when you're trying to split your app into multiple bundles.

    
  {
    "name": "app-bundle.js",
    "source": {
      "include": [
        "**/*.{js, css,html}"
      ],
      "exclude": [
        "**/sub-module/**/*",
      ]
    }
  },
  {
    "name": "sub-module-bundle.js",
    "source": [
      "**/sub-module/**/*",
    ]
  }
  
  

Adding Client Libraries to Your Project

Just do npm install <library> (or yarn add <library>). CLI Bundler supports any npm package in either CommonJS, AMD, UMD, or Native ES Module format.

Sometimes, you will encounter some JavaScript lib that doesn't support any module format. You would need manual configuration, read dependency management for more details.

For Long Time CLI Bundler Users

au import and au install commands are deprecated. Latest CLI Bundler does almost everything automatically without the need of explicit configuration in aurelia_project/aurelia.json.

UMD is a module format supports both CommonJS and AMD, falls back to global namespace when no module loader is available. Npm packages that designed to work in both Node.js and browser environments are normally shipped in this format.

Copy Other Files (e.g. fonts)

CLI Bundler auto bundles JS/HTML/CSS files into AMD modules format. But it cannot help on other resources like font files and images which are required by CSS at runtime.

Resources like fonts and images are not handled by JavaScript module loader, they need to be present at the URL at runtime. So we need to copy the necessary font files and images to the right folder.

CLI has a built-in feature to facilitate this task. To copy files, we declare these files in the copyFiles property, after the bundles property in aurelia_project/aurelia.json.

For instance, this is how you make font-awesome v4 works.

    
  "bundles": [ ... ],
  "copyFiles": {
    "node_modules/font-awesome/fonts/*": "font-awesome/fonts"
  }
  
  

The target folder of copyFiles matches the way you require font-awesome.css

    
  <require from="font-awesome/css/font-awesome.css"></require>
  
  

Remember to deploy font-awesome/fonts folder along with your JavaScript bundles to production.

copyFiles also works on a single file without using wild-card.

    
  "copyFiles": {
    "node_modules/font-awesome/fonts/fontawesome-webfont.woff": "font-awesome/fonts",
    "node_modules/font-awesome/fonts/fontawesome-webfont.woff2": "font-awesome/fonts"
  }
  
  

Setting the baseUrl

Sometimes you may want to keep the scripts folder somewhere other than the default location or move the index.html file a few folders up from the project root. In that case, it is possible to set the baseUrl property so that the build system uses the correct paths and that bundles get loaded correctly in the browser. The baseUrl property should be set in both the platform object as well as the build.targets object:

    
  "build": {
    "targets": [
      {
        "id": "web",
        "displayName": "Web",
        "port": 9000,
        "index": "index.html",
        "baseDir": ".",
        "output": "some/dir/scripts",
        "baseUrl": "some/dir/scripts"
      }
    ]
  },
  "platform": {
    "id": "web",
    "displayName": "Web",
    "port": 9000,
    "index": "index.html",
    "baseDir": ".",
    "output": "some/dir/scripts",
    "baseUrl": "some/dir/scripts"
  },
  
  

The script tag for the bundle in index.html file needs to point to the modified location of the scripts folder as well: <script src="some/dir/scripts/vendor-bundle.js" data-main="aurelia-bootstrapper"></script>

Styling your Application

There are many ways to style components in Aurelia. The CLI sets up your project to only process styles inside your application's src folder. Those styles can then be imported into a view using Aurelia's require element.

  • If you aren't using any CSS preprocessor, you write CSS and then simply require it in the view like this:
    
  <require from="./styles.css"></require>
  
  

For projects that use a CSS preprocessor (chosen from the au new app-name options):

  • Write your styles in the format you chose (styl, sass, less ...).
  • Require the style by [filename].css instead of [filename].[extension]. This is because, before CLI bundler sees the style file, it is transpiled by a gulp task into a CSS format file.

Difference with Webpack

Webpack behaves differently, it controls the whole css compilation. With Webpack, you need <require from="./styles.scss"></require> if your source file is styles.scss.

    
  <require from="./main.css"></require>
  
  

Bear in mind that you can always configure things any way you want by modifying the tasks in the aurelia_project/tasks folder. For styling purposes, you can modify the process-css.js file.

Updating A Single Library

To update a single library use the command npm install library-name where library-name is the library that you wish to update.

Updating Multiple Libraries

  • Add the following section to the project's package.json file
    
  "scripts": {
    "au-update": "npm install aurelia-binding@latest aurelia-bootstrapper@latest ...
  }
  
  
  • List the libraries on a single line separated by a space.
  • Include all of the libraries from the dependencies section of aurelia.json that you want to update.
  • Use the command npm run au-update to update all of the libraries in the au-update list above.

Javascript Minification

The CLI will minify Javascript out of the box for the staging and production environments:

    
  "options": {
    "minify": "stage & prod",
    "sourcemaps": "dev & stage"
  },
  
  

These options can be found in the "build"."options" section of aurelia.json. If you wish to specify the options that are used in the minification process, then replace "minify": "stage & prod" with:

    
  "minify": {
    "dev": false,
    "default": {
      "indent_level": 2
    },
    "stage & prod": {
      "max-line-len": 100000
    }
  },
  
  

The Aurelia-CLI uses terser (reincarnation of uglify-es) for minification, so any option that terser supports (compatible with UglifyJS2 and uglify-es) are also supported by the Aurelia-CLI. With the above configuration, minification will occur for the stage and prod environments, but not for the dev environment. For the stage and prod environments, both the indent_level as well as the max-line-len option are passed to the minifier. The default key is optional but allows you to reduce code duplication when multiple environments have similar options.

Path mappings

Do you have import statements that look like import {Customer} from '../../../common/models/customer'; ?

Consider creating a path mapping for the src/common/models folder, so that you can do: import {Customer} from 'models/customer';.

Open up aurelia.json, add "models": "common/models" to the paths object:

    
    "paths": {
      "root": "src",
      "resources": "resources",
      "elements": "resources/elements",
      "attributes": "resources/attributes",
      "valueConverters": "resources/value-converters",
      "bindingBehaviors": "resources/binding-behaviors",
      "models": "common/models"
    },
  
  

That should make it work at runtime, but if you use Typescript it's going to tell you that it can't find models/customer. To fix that, open up tsconfig.json, in the compilerOptions add a paths and baseUrl property:

    
  "paths": {
    "models/*": ["src/common/models/*"]
  },
  "baseUrl": "."
  
  

You might have to restart your editor to see the effect of these changes.