diff --git a/README.md b/README.md index 6a588e6f..ac1b2c0e 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ SystemJS ======== -Spec-compliant universal module loader - loads ES6 modules, AMD, CommonJS and global scripts. +Universal dynamic module loader - loads ES6 modules, AMD, CommonJS and global scripts in the browser and NodeJS. -Designed as a collection of small extensions to the ES6 specification System loader, which can also be applied individually. +Designed as a collection of extensions to the [ES6 module loader](https://github.com/ModuleLoader/es6-module-loader) which can also be applied individually. -* Loads any module format, by detecting the format automatically. Modules can also [specify their format with meta config](#meta-configuration). -* Provides comprehensive and exact replications of AMD, CommonJS and ES6 circular reference handling. +* [Loads any module format](https://github.com/systemjs/systemjs/wiki/Module-Format-Support). +* Provides comprehensive and exact replications of AMD, CommonJS and ES6 [circular reference handling](https://github.com/ModuleLoader/es6-module-loader/wiki/Circular-References-&-Bindings). * Loads [ES6 modules compiled into the `System.register` form for production](#es6-systemregister-compilation), maintaining full circular references support. * Supports RequireJS-style [map](#map-configuration), [paths](https://github.com/ModuleLoader/es6-module-loader#paths-implementation), [bundles](#bundles), [shim](#global-module-format-support) and [plugins](#plugins). * Tracks package versions, and resolves semver-compatibile requests through [package version syntax](#versions) - `package@x.y.z`, `package^@x.y.z`. @@ -18,7 +18,20 @@ Runs in IE8+ and NodeJS. For discussion, [see the Google Group](https://groups.google.com/group/systemjs). -Basic Configuration +Documentation +--- + +* [Loader Configuration](https://github.com/ModuleLoader/es6-module-loader/wiki/Configuring-the-Loader) +* [Map Configuration](https://github.com/systemjs/systemjs/wiki/Map-Configuration) +* [Meta Configuration](https://github.com/systemjs/systemjs/wiki/Meta-Configuration) +* [Module Format Support](https://github.com/systemjs/systemjs/wiki/Module-Format-Support) +* [Relative Dynamic Loading](https://github.com/systemjs/systemjs/wiki/Relative-Dynamic-Loading) +* [Versions Extension](https://github.com/systemjs/systemjs/wiki/Versions-Extension) +* [Production Workflows](https://github.com/systemjs/systemjs/wiki/Production-Workflows) +* [Creating Plugins](https://github.com/systemjs/systemjs/wiki/Creating-a-Plugin) +* [Creating a Custom Module Format](https://github.com/systemjs/systemjs/wiki/Creating-a-Custom-Format-Extension) + +Getting Started --- ### Setup @@ -43,7 +56,7 @@ index.html: System.config({ // set all requires to "lib" for library code - baseURL: '/lib', + baseURL: '/lib/', // set "app" as an exception for our application code paths: { @@ -102,222 +115,12 @@ To build for production, see the [System.register build workflow](#es6-systemreg For further infomation on ES6 module loading, see the [ES6 Module Loader polyfill documentation](https://github.com/ModuleLoader/es6-module-loader). -### Loading Other Formats - -When loading from CommonJS, AMD or globals, SystemJS will detect the format automatically. - -Any module type can be loaded from any other type. - -When loading CommonJS, AMD or globals from ES6, use the `default` import syntax: - -app/es6-loading-commonjs: -```javascript -import _ from './underscore'; -``` - -Where underscore.js is located in the same folder. - -Features ---- - -### Map Configuration - -Map configuration alters the module name at the normalization stage. It is useful for creating aliases: - -```javascript - System.map['jquery'] = 'location/for/jquery'; - - System.import('jquery') // -> 'location/for/jquery' - System.import('jquery/submodule') // -> `location/for/jquery/submodule' -``` - -Contexual map configuration can also be used to provide maps only for certain modules, which is useful for version mappings: - -```javascript - System.map['some-module'] = { - jquery: 'jquery@2.0.3' - }; - - // some-module.js now gets 'jquery@2.0.3' - // everything else still gets 'location/for/jquery' -``` - -Contextual maps apply from the most specific module name match only. - -### Meta Configuration - -The ES6 module loader uses a special `metadata` object that is passed between hooks. - -An example of meta config is the module format of a module, which is stored at `metadata.format`. - -The meta extension opens up this object for setting defaults through `System.meta` as well as inline module syntax. - -In this way, we can specify the module format of a module through config: - -```javascript - System.meta['some/module'] = { - format: 'amd' - }; - - System.import('some/module') // always loaded as AMD even if it is a UMD module -``` - -Or the module can even specify its own meta: - -some/module.js -```javascript - "format amd"; - - if (typeof module != 'undefined' && module.exports) - module.exports = 'cjs'; - else - define(function() { return 'amd' }); -``` - -Since it is impossible to write 100% accurate module detection, this inline `format` hint provides a useful way of informing the module format of a module. - -The format options are - `register`, `es6`, `amd`, `cjs`, `global`. - -### Global Module Format Support - -When a module is loaded as a global, the global object is detected automatically from the change in the `window` properties: - -app/sample-global.js -```javascript - hello = 'world'; -``` - -```javascript - System.import('app/sample-global').then(function(m) { - m == 'world'; - }); -``` - -When multiple global properties are detected, the module object becomes the collection of those objects: - -app/multi-global.js -```javascript - first = 'global1'; - var second = 'global2'; -``` - -```javascript -System.import('app/multi-global').then(function(m) { - m.first == 'global1'; - m.second == 'global2'; -}); -``` - -Global dependencies can be specified with the `deps` [meta config](#meta-configuration): - -app/another-global.js -```javascript - $(document).fn(); - this.is = 'a global dependent on jQuery'; -``` - -```javascript - System.meta['app/another-global'] = { deps: ['jquery'] }; -``` - -Note that the name used in `System.meta` must be the fully normalized name that is returned by `Promise.resolve(System.normalize('module-name')).then(console.log.bind(console))`. - -The `exports` meta config can also be set (using inline meta as an example): - -app/more-global.js -```javascript - "format global"; - "deps jquery"; - "exports my.export"; - - (function(global) { - global.my = { - export: 'value' - }; - $(document).fn(); - })(typeof window != 'undefined' ? window : global); -``` - -There is also supports for the `init` function meta config just like RequireJS as well. - -**IE8 Support** - -In IE8, automatic global detection does not work for globals declared as variables or implicitly: - -```javascript - var someGlobal = 'IE8 wont detect this'; - anotherGlobal = 'unless using an explicit shim'; -``` - -IF IE8 support is needed, these exports will need to be declared manually with configuration. - -### Versions - -An optional syntax for version support can be used: `moduleName@version`. - -For example, consider an app which wants to specify the jQuery version through config: - -```javascript - System.versions['jquery'] = '2.0.3'; -``` - -Now an import of the form: - -```javascript - System.import('jquery'); -``` - -will load a load will be made to the file `/lib/jquery@2.0.3.js`. - -This centralises the version management to the configuration file, which is key to handling versions with correct caching. - -For multi-version support, provide an array of versions: - -```javascript - System.versions['jquery'] = ['2.0.3', '1.8.3']; -``` - -These correspond to `/lib/jquery@2.0.3.js` and `/lib/jquery@1.8.3.js`. - -Semver-compatible requires of any of the following forms can be used: - -```javascript - System.import('jquery') // -> /lib/jquery@2.0.3.js - System.import('jquery@2') // -> /lib/jquery@2.0.3.js - System.import('jquery@2.0') // -> /lib/jquery@2.0.3.js - - System.import('jquery@1') // -> /lib/jquery@1.8.3.js - System.import('jquery@1.8') // -> /lib/jquery@1.8.3.js - System.import('jquery@1.8.2') // -> /lib/jquery@1.8.2.js - - // semver compatible form (caret operator ^) - System.import('jquery@^2') // -> /lib/jquery@2.0.3.js - System.import('jquery@^1.8.2') // -> /lib/jquery@1.8.3.js - System.import('jquery@^1.8') // -> /lib/jquery@1.8.3.js -``` - -### Relative Dynamic Loading - -Modules can check their own name from the global variable `__moduleName`. `__moduleAddress` is also available. - -This allows easy relative dynamic loading, allowing modules to load additional functionality after the initial load: - -```javascript -export function moreFunctionality() { - return System.import('./extrafunctionality', { name: __moduleName }); -} -``` - -This can be useful for modules that may only know during runtime which functionality they need to load. +[For further details about SystemJS module format support, see the wiki page](https://github.com/systemjs/systemjs/wiki/Module-Format-Support). ### Plugins Plugins handle alternative loading scenarios, including loading assets such as CSS or images, and providing custom transpilation scenarios. -Plugins are indicated by `!` syntax, which unlike RequireJS is appended at the end of the module name, not the beginning. - -The plugin name is just a module name itself, and if not specified, is assumed to be the extension name of the module. - Supported Plugins: * [CSS](https://github.com/systemjs/plugin-css) `System.import('my/file.css!')` @@ -325,113 +128,15 @@ Supported Plugins: * [JSON](https://github.com/systemjs/plugin-json) `System.import('some/data.json!').then(function(json){})` * [Text](https://github.com/systemjs/plugin-text) `System.import('some/text.txt!text').then(function(text) {})` -Additional Plugins: +Additional Community Plugins: * [JSX](https://github.com/floatdrop/plugin-jsx) `System.import('template.jsx!')` * [Markdown](https://github.com/guybedford/plugin-md) `System.import('app/some/project/README.md!').then(function(html) {})` * [WebFont](https://github.com/guybedford/plugin-font) `System.import('google Port Lligat Slab, Droid Sans !font')` -Creating custom plugins can be quite simple. See the plugins above, and [read the guide here](https://github.com/systemjs/systemjs/wiki/Creating-a-Plugin). +Additional plugin submissions to the above are welcome. -### ES6 System.register Compilation - -If writing an application in ES6, we can compile into ES5 with Traceur: - -``` - npm install traceur -g -``` - -``` - traceur --dir app app-built --modules=instantiate -``` - -This will compile all ES6 files in the directory `app` into corresponding ES5 `System.register` files in `app-built`. - -The `instantiate` modules option writes the modules out using a `System.register` call, which is supported by SystemJS. - -Then include [`traceur-runtime.js`](https://raw.githubusercontent.com/jmcriffey/bower-traceur/0.0.72/traceur-runtimr.js) (also found inside traceur's `bin` folder when installed via npm) before es6-module-loader.js: - -```html - - - -``` - -We can then use map or paths config to ensure that `app/main` gets directed to the new folder. Alternatively rename `app-built` to replace `app`. - -Now the application will continue to behave identically without needing to compile ES6 in the browser. - -### Compiling ES6 to ES5 and AMD - -The same method above can also be used to compile ES6 into AMD with `--modules=amd`. - -We can then use the r.js optimizer to create a bundle with named defines, which are supported by SystemJS. - -Note that the ES6 live bindings and circular references don't work in AMD, although circular references still work in many cases. - -### Bundles - -Bundles configuration allows a single bundle file to be loaded in place of separate module files. - -```javascript - System.bundles['build/core'] = ['jquery', 'app/app', 'app/dep', 'lib/third-party']; - - // loads "app/app" from the module "build/core". - System.import('app/app'); - - // a request to any one of 'jquery', 'app/app', 'app/dep', 'lib/third-party' - // would delegate to the "build/core" module -``` - -A built file must contain the exact named defines or named `System.register` statements for the modules -it contains. Mismatched names will result in separate requests still being made. - -We can create a custom bundle with Traceur by combining together a module with all its dependencies into a single file: - -``` - traceur --out build.js app/main.js app/core.js app/another.js -``` - -Each file will be traced and all its dependencies included in the final build file. - -We can also just include this bundle with a ` - -``` - -To make all module formats work with CSP, we need to ensure everything is built with a suitable wrapper. - -See [SystemJS Builder](https://github.com/systemjs/builder) for a single-file build workflow that can wrap up all module formats. - -### RequireJS Support - -To use SystemJS side-by-side in a RequireJS project, make sure to include RequireJS after ES6 Module Loader but before SystemJS. - -Conversely, to have SystemJS provide a RequireJS-like API in an application set: - -```javascript -window.define = System.amdDefine; -window.require = window.requirejs = System.amdRequire; -``` +[Read the guide here on creating plugins](https://github.com/systemjs/systemjs/wiki/Creating-a-Plugin). ### NodeJS Usage @@ -452,19 +157,11 @@ System.import('./app').then(function(m) { }); ``` -## Contributing - -Contributions are welcome. The goal of SystemJS is to encourage loaders made out of small self-contained features. - -Since different builds can be created for different use cases, new builds or new features are welcome to be submitted for -consideration with pull requests. - #### Running the tests To install the dependencies correctly, run `bower install` from the root of the repo, then open `test/test.html` in a browser with a local server or file access flags enabled. - License ---