JS IPFS is a large collection of modules that aim to implement IPFS in Node.js and the browser. As such the distributions of these modules has a specific set of constraints.
Our current setup is not bad, and does generate bundles usable in Node.js and the browser, but there are some pain points that need work.
- Bundles are quite large
- Lots of dependencies are duplicated, for example
readable-stream
is included 12 times in the currentjs-ipfs
browser bundle. - Developers have to know very domain specific configurations to be able to use browserify or webpack.
- We break browserify and webpack compat without knowing about it until we get a bug report.
- Bundle Size
- Ease of use for developers embedding the library (i.e. Orbit)
- Ease of use for contributors
There are two different module formats for JavaScript modules in main use today.
- CommonJS
var dep = require('dependency')
- Only native format in Node.js at the moment.
- ES2015 Modules
import dep from 'dependency'
- You can read about it in detail in this article: http://www.2ality.com/2014/09/es6-modules-final.html
The current code base uses CommonJS.
The tooling landscape is quite large today, with things developing and changing quite rapidly. The for us currently relevant tooling is listed below.
A module bundler can take in many JavaScript files and generate a bundle, which is usable in the browser.
- [Webpack] (CommonJS, ES2015)
- jspm (CommonJS, ES2015)
- Closure Compiler (CommonJS, ES2015)
- Rollup (CommonJS, ES2015)
- Browserify (CommonJS)
- Babel (CommonJS, ES2015)
Transpilers can transform code written with ES2015 features and output code that is usable in ES5 (and lower) environments.
A good comparision of the differences in size and runtime can be found in The cost of transpiling ES2015 in 2016.
Given the set of constraints mentioned above, the following is a list of steps I suggest to improve and solve our current pain points.
Similar to what PouchDB does, the end result for Node.js and the browser should be a single file.
If there are differences between Node.js and browser, modules use two different entry points
src/index.js
- Original source for node.jssrc/index-browser.js
- Original source the browser
For the builds we target the same places as currently
dist/index.js
ES5 code for the browserlib/index.js
- ES5 code for node.js
but lib/index.js
will be a single file, fully transformed rather than still many files such that treeshaking and processing of things like webpack loaders already happend and this is runnable through in node.js directly.
To make tooling aware of what is avaliable, the following should fields should be in package.json
"main": "./lib/index.js",
"jsnext:main": "./src/index.js",
"browser": {
"./lib/index.js": "./dist/index.js"
},
"jspm": {
"main": "dist/index.js"
}
- Fully compatabile out of the box, with default configuaration with
- browserify
- webpack
- jspm
- rollup
- Transpiled code in
lib/index.js
is a bit harder to read as it is now a single large file.
- Build with the default configurations for browserify and webpack.
- Run the full test suite against these versions.
- We can be sure that our builds are usable by other developers.
- CI run time increases.
- Using tools like cjs-to-es6 this is pretty straight forward for our own modules.
- For dependencies that do not yet publish a build which uses ES2015
- Enable tree shaking in our webpack build.
- Smaller module size, due to the availability of statically analyzable dependencies and so allowing us to use tree shaking
- Not runnable in Node.js directly anymore until they integrate ES2015 modules or you use something like
babel-register
.
- Look at all of them
- Migrate where needed and large enough benefits are clear to ES2105 modules
- Major culprits that we know about
- all shims for Node.js functionality in the browser
- forge
- web-crypto -> browserify-crypto
- readable-stream and all users of it
- Only include what we absolutly need
- Improves tree shaking if we can use dependencies that use ES2015 modules.
- Takes time
- https://nolanlawson.com/2016/08/15/the-cost-of-small-modules/
- https://pouchdb.com/2016/01/13/pouchdb-5.2.0-a-better-build-system-with-rollup.html
- https://pouchdb.com/2016/06/06/introducing-pouchdb-custom-builds.html
- https://github.com/samccone/The-cost-of-transpiling-es2015-in-2016
- http://www.2ality.com/2015/12/webpack-tree-shaking.html