What does systemjs.config.js do in angular 2 packaging structure?

It allows to configure SystemJS to load modules compiled using the TypeScript compiler. For anonymous modules (one module per JS file), it allows to map the name of modules to JS files that actually contains the module JavaScript code.

Here is a sample. If I try to import the module named app/test, SystemJS will do:

  • Try to find a preregistered module (with System.register('app/test', ...
  • If not, it will look into its configuration to build the request to execute to load the corresponding file:
    • there is a map entry for app
    • there is a packages entry for app with defaultExtension = js
  • The request will be http://localhost:3000/app/test.js. If you have map: { app: dist }, the request would be http://localhost:3000/dist/test.js

The systemjs.config.js defines configuration for Path Normalization in SystemJS. You load something using SystemJS like this:

System.import('app/main.js')

This causes SystemJS to attempt to load your app, starting with the file app/main.js. The very first thing that SystemJS does however is to normalize the path (app/main.js), which means that it translates the path according to the rules in systemjs.config.js.

Systemjs.config.js defines different types of alias, for anything that's being imported by SystemJS:


map

The map section has two uses:

path aliasing

In an app where SystemJS is being used to load the modules, the map section is used to alias a part of the path, or to tell SystemJS where a particular named module is actually located. For example you may be loading your app using SystemJS like this:

System.import('app/main.js')

Now, say you actually want to locate your app files in:

/assets/js/app.

You can define this in the 'map' section in systemjs.config.js:

// map tells the System loader where to look for things
map: {
  'app': '/assets/js/app'
}

SystemJS will then look for your main file at:

/assets/js/app/main.js

identifying where to locate modules

The main fundamental purpose of SystemJS is to provide a module system that caters for the lack of universal ES module support in browsers, and one of the ways it does this is to use the 'map' section of systemjs.config.js to identify where to look for modules.

For any modules that are being imported inside your app using the standard ES 'import' statements, the map section identifies where SystemJS will find them (after your app has been loaded using SystemJS). Here's a common example:

    // map tells the System loader where to look for things
    map: {
        // angular bundles
        '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
        '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
        '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',

This means that when you first do this in your root module:

import { NgModule } from '@angular/core';

... SystemJS will handle the import by looking for the Angular core library in it's default location (assuming it's being installed using npm):

/node_modules/@angular/core/bundles/core.umd.js

Now, you may be wondering how 'npm:' is translated to '/node_modules', and that's what the 'paths' section of systemjs.config.js does:


paths

This section defines aliases for parts of the module paths that are defined under 'map'. The way that 'npm' can be aliased in the example above is like this:

paths: {
  // paths serve as alias
  'npm:': '/node_modules/'
}

What this will do is replace any occurrence of 'npm', in any path that you've added to the 'map' section, and it will be replaced with the string '/node_modules/' .

Official documentation: https://github.com/systemjs/systemjs/blob/master/docs/config-api.md#paths (dead)


packages

From the docs:

Packages provide a convenience for setting meta and map configuration that is specific to a common path.

For example, if you want to load your app like this:

System.import('app')

Then you can add this section for 'packages':

    // packages tells the System loader how to load when no filename and/or no extension
    packages: {
        app: {
            main: 'index.js'
            defaultExtension: 'js',
            meta: {
                './*.js': {
                    loader: false,
                }
            }
        }

Here's the breakdown:

main: 'index.js'

The main entry point for a package or path alias (if it hasn't already been supplied in the 'map' section)

defaultExtension: 'js'

The file extension to assume (if it isn't already supplied). In this case, look for a .js file if no file type is specified.

meta: {
    './*.js': {
        loader: false,
    }
}

Information that SystemJS needs to determine how to load modules correctly. In this case, don't invoke the module loader for any '.js' files in our app (you would need this if you're using TypeScript - you only want SystemJS to load modules when you transpile the TypeScript, and you need to ignore the transpiled .js files)

(see the docs for more info about 'meta' - https://github.com/systemjs/systemjs/blob/master/docs/config-api.md#meta (dead))

Also see the official documentation here for a full explanation of the 'packages' section:

https://github.com/systemjs/systemjs/blob/master/docs/config-api.md#packages (dead)

Tags:

Angular