aboutsummaryrefslogtreecommitdiff
path: root/docs/creating-plugins.md
blob: 531ece16303a1018362ec4ad80a4edc46bca14a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
### Creating a Plugin

A plugin is just a set of overrides for the loader hooks of the ES6 module specification.

The hooks plugins can override are `locate`, `fetch`, `translate` and `instantiate`.

Read more about loader extensions and hooks at the [ES6 Module Loader polyfill wiki](https://github.com/ModuleLoader/es6-module-loader/blob/v0.17.0/docs/loader-extensions.md).

The behaviors of the hooks are:

* Locate: Overrides the location of the plugin resource
* Fetch: Called with third argument representing default fetch function, has full control of fetch output.
* Translate: Returns the translated source from `load.source`, can also set `load.metadata.sourceMap` for full source maps support.
* Instantiate: Providing this hook as a promise or function allows the plugin to hook instantiate. Any return value becomes the defined custom module object for the plugin call.

### Building Plugins

When building via [SystemJS Builder](https://github.com/systemjs/builder), plugins that use the translate hook will be inlined into the bundle automatically.

In this way, the bundle file becomes independent of the plugin loader and resource.

If it is desired for the plugin itself not to be inlined into the bundle in this way, setting `exports.build = false` on the plugin will disable this,
causing the plugin loader itself to be bundled in production instead to continue to dynamically load the resource.

#### Sample CoffeeScript Plugin

For example, we can write a CoffeeScript plugin with the following (CommonJS as an example, any module format works fine):

js/coffee.js:
```javascript
  var CoffeeScript = require('coffeescript');

  exports.translate = function(load) {
    // optionally also set the sourceMap to support both builds and in-browser transpilation
    // load.metadata.sourceMap = generatedSourceMap;
    return CoffeeScript.compile(load.source);
  }
```

By overriding the `translate` hook, we now support CoffeeScript loading with:

```
 - js/
   - coffee.js             our plugin above
   - coffeescript.js       the CoffeeScript compiler
 - app/
   - main.coffee
```

```javascript
  System.import('app/main.coffee!').then(function(main) {
    // main is now loaded from CoffeeScript
  });
```

Source maps can also be passed by setting `load.metadata.sourceMap`.

#### Sample CSS Plugin

A CSS plugin, on the other hand, could override the fetch hook:

js/css.js:
```javascript
  exports.fetch = function(load, fetch) {
    return new Promise(function(resolve, reject) {
      var cssFile = load.address;

      var link = document.createElement('link');
      link.rel = 'stylesheet';
      link.href = cssFile;
      link.onload = resolve;

      document.head.appendChild(link);
    })
    .then(function() {
      // return an empty module in the module pipeline itself
      return '';
    });
  }
```

Each loader hook can either return directly or return a promise for the value.

The other loader hooks are also treated otherwise identically to the specification.