Using NPM with SystemJS

system-npm is an amazing plugin for SystemJS that enables you to load your NPM dependencies with zero configuration. Just load system-npm and then load your project; require your NPM dependencies just as if you were in Node.

To use system-npm with SystemJS you'll first want to install SystemJS into your project. In this post we're assuming you've included system.js and es6-module-loader.js in a vendor/ folder, but you can place it where-ever you want. Then simply add a script tag to your page to load SystemJS:

<script src="vendor/system.js"></script>

Installing

system-npm is installed through NPM (of course!):

npm install system-npm --save-dev

Configuring

Next you'll want to configure SystemJS to know where to load the plugin. Create a config.js file and add the appropriate config:

System.config({
    map: {
        "npm": "system-npm",
        "npm-extension": "system-npm/npm-extension"
    },
    paths: {
        "system-npm/*": "node_modules/system-npm/*.js"
    }
});

This tells SystemJS how to load system-npm. Add the configuration script to your page after SystemJS:

<script src="config.js"></script>

Load your app

Now that it is configured you can load your package.json using the plugin and then start up your applicaiton:

<script>
    System.import("package.json!npm").then(function(){
        System.import("app/app");
    });
</script>

Develop

From here you can develop as you wish, sharing the same dependencies between Node and the Browser. system-npm will load your package.json and use the metadata. If you want to limit it to only loading your client-side deps, you can specify this in your configuration:

System.config({
  npmDependencies: [
    "jquery",
    "backbone"
  ]
});

Doing this, system-npm will only load jquery and backbone as dependencies.

It's that simple. system-npm is a great way to instantly make your SystemJS projects nearly configuration-free.

Organizing your library project with StealJS

With StealJS you can easily set up an open-source library that fits with the way you like to organize your code. A common directory structure might look like this:

- src
  - main.js
  - dep.js
- test
  - test.html
  - test.js
package.json
Gruntfile.js

In order to keep a shallow folder structure we've divided the library's source code in src and its tests in test. The root directory only contains our package.json and a Gruntfile.js for builds.

With this structure you might try to install your module with NPM:

npm install my-module --save

And then load it in your project:

import myModule from "my-module";

However this will fail because your main is not pointing to right place. Imagine your main.js look like:

import dep from "my-module/dep";

Steal will look for dep.js in the project's root folder. To set an alternative root, correctly called the lib folder, set it in the package.json:

{
  "name": "my-module",
  "main": "dist/cjs/main.js",
  "system": {
    "main": "main",
    "directories": {
      "lib": "src"
    }
  }
}

This tells Steal that your library's code is nested under the src folder. This makes it easy to refer to your module by name in its internal code. With your test do the same thing:

import myModuleDep from "my-module/dep";

Will correctly load src/dep.js if that's the module you want to test.

Building

If you're only target Steal you can go ahead and publish your module on NPM. But if you want to reach users of other module loaders you should set up a build script. steal-tools makes this easy. For example if using Grunt:

grunt.initConfig({
  "steal-export": {
    dist: {
      system: {
        config: "package.json!npm"
      },
      outputs: {
        "+cjs": {},
        "+amd": {},
        "global-js": {]
      }
    }
  }
});

Then by simply running grunt steal-export will produce dist/cjs, dist/amd, and dist/global folders containing code that will run in RequireJS, Browserify, and as a browser global. Read the full guide on setting up an export for your project for more.

See bit-tabs for a full example of this directory structure in action.