UNPKG

5.96 kBMarkdownView Raw
1# rollup
2
3*I roll up, I roll up, I roll up, Shawty I roll up*
4
5*I roll up, I roll up, I roll up* –[Wiz Khalifa](https://www.youtube.com/watch?v=UhQz-0QVmQ0)
6
7This is an early stage project under active development. If you find a bug, [please raise an issue!](https://github.com/rollup/rollup/issues).
8
9
10## A next-generation ES6 module bundler
11
12Right now, you have a few different options if you want to create a bundle out of your ES6 modules:
13
14* The best option, in terms of performance, size of the resulting bundle, and accurate representation of ES6 module semantics, is to use [esperanto](http://esperantojs.org). It's used by [ractive.js](http://ractivejs.org), [moment.js](http://momentjs.com/), Facebook's [immutable.js](https://github.com/facebook/immutable-js), the jQuery Foundation's [pointer events polyfill](https://github.com/jquery/PEP), [Ember CLI](http://www.ember-cli.com/) and a bunch of other libraries and apps
15* You could use [jspm](http://jspm.io/), which combines a module bundler with a loader and a package manager
16* Or you could use [browserify](http://browserify.org/) or [webpack](http://webpack.github.io/), transpiling your modules into CommonJS along the way
17
18But there's a flaw in how these systems work. Pretend it's the future, and lodash is available as an ES6 module, and you want to use a single helper function from it:
19
20```js
21// app.js
22import { pluck } from 'lodash';
23```
24
25With that single import statement, you've just caused the whole of [lodash](https://lodash.com/) to be included in your bundle, even though you only need to use a tiny fraction of the code therein.
26
27If you're using esperanto, that's not totally disastrous, because a sufficiently good minifier will be able to determine through [static analysis](http://en.wikipedia.org/wiki/Static_program_analysis) that most of the code will never run, and so remove it. But there are lots of situations where static analysis fails, and unused code will continue to clutter up your bundle.
28
29If you're using any of the other tools, static analysis won't be able to even begin to determine which of lodash's exports aren't used by your app (AFAIK! please correct me if I'm wrong).
30
31
32### The current solution is not future-proof
33
34I picked lodash because it does offer one solution to this problem: modular builds. Today, in your CommonJS modules, you can do this:
35
36```js
37var pluck = require( 'lodash/collection/pluck' );
38```
39
40**This is not the answer.** Using a folder structure to define an interface is a bad idea - it makes it harder to guarantee backwards compatibility, it imposes awkward constraints on library authors, and it allows developers to do this sort of thing:
41
42```js
43var cheekyHack = require( 'undocumented/private/module' );
44```
45
46Sure enough, you [won't be able to do this with ES6 modules](https://github.com/esperantojs/esperanto/issues/68#issuecomment-73302346).
47
48
49### A better approach?
50
51This project is an attempt to prove a different idea: ES6 modules should define their interface through a single file (which, by convention, is currently exposed as the `jsnext:main` field in your package.json file), like so...
52
53```js
54// snippet from future-lodash.js
55export { partition } from './src/collection/partition';
56export { pluck } from './src/collection/pluck';
57export { reduce } from './src/collection/reduce';
58/* ...and so on... */
59```
60
61...and ES6 *bundlers* should handle importing in a much more granular fashion. Rather than importing an entire module, an intelligent bundler should be able to reason like so:
62
63* I need to import `pluck` from `future-lodash.js`
64* According to `future-lodash.js`, the definition of `pluck` can be found in `lodash/src/collection/pluck.js`
65* It seems that `pluck` depends on `map` and `property`, which are in... *these* files
66* ...
67* Right, I've found all the function definitions I need. I can just include those in my bundle and disregard the rest
68
69In other words, the 'tree-shaking' approach of throwing everything in then removing the bits you don't need is all wrong - instead, we should be selective about what we include in the first place.
70
71This is not a trivial task. There are almost certainly a great many complex edge cases. Perhaps it's not possible. But I intend to find out.
72
73
74## Goals
75
76* Maximally efficient bundling
77* Ease of use
78* Flexible output - CommonJS, AMD, UMD, globals, ES6, System etc
79* Speed
80* Character-accurate sourcemaps
81* Eventually, port the functionality to esperanto
82
83### Secondary goals
84
85* Support for legacy module formats
86* Respect for original formatting and code comments
87
88
89### API
90
91The example below is aspirational. It isn't yet implemented - it exists in the name of [README driven development](http://tom.preston-werner.com/2010/08/23/readme-driven-development.html).
92
93```js
94rollup.rollup({
95 // The bundle's starting point
96 entry: 'app.js',
97
98 // Any external modules you don't want to include
99 // in the bundle (includes node built-ins)
100 external: [ 'path', 'fs', 'some-other-lib' ]
101}).then( function ( bundle ) {
102 // generate code and a sourcemap
103 const { code, map } = bundle.generate({
104 // output format - 'amd', 'cjs', 'es6', 'iife', 'umd'
105 format: 'amd',
106
107 // exports - 'auto', 'none', 'default', 'named'
108 exports: 'auto',
109
110 // amd/umd options
111 moduleId: 'my-library',
112
113 // umd options
114 moduleName: 'MyLibrary', // necessary if the bundle has exports
115 globals: {
116 backbone: 'Backbone'
117 }
118 });
119
120 fs.writeFileSync( 'bundle.js', code + '\n//# sourceMappingURL=bundle.js.map' );
121 fs.writeFileSync( 'bundle.js.map', map.toString() );
122
123 // possible convenience method
124 bundle.write({
125 dest: 'bundle.js', // also writes sourcemap
126 format: 'amd'
127 });
128});
129```
130
131The duplication (`rollup.rollup`) is intentional. You have to say it like you're in the circus, otherwise it won't work.
132
133
134## License
135
136Not that there's any code here at the time of writing, but this project is released under the MIT license.