Remove the hassle in writing npm libraries in a transpiled language (babeljs, CoffeeScript, etc) by using browserify.

With this technique, there’s no need to maintain a full new directory of compiled files… just one pre-built dist/ file.


├─ lib
│  └─ index.js        - actual entry point
├─ dist
│  └─ js2coffee.js    - built package
└─ index.js           - entry point (used in development)

Install the requisite packages

npm install --save-dev browserify babelify babel-preset-es2015

Make the entry point

Put your actual main entry point as, say, ./lib/index.js. Then create an entry point ./index.js like this for development:

module.exports = require('./lib/index');

Set up compilation

Set up a compliation script in the prepublish hook:

  "scripts": {
    "prepublish": "browserify -s js2coffee --bare -t [ babelify --presets [ es2015 ] ] ./lib/index.js > dist/js2coffee.js"

For CoffeeScript support, use coffeeify for CoffeeScript (-t [ coffeeify -x .coffee ]).

Options used:

  • -s - standalone (uses a UMD wrapper)
  • --bare - don’t stub node builtins
  • -t - define transformations to use

For packages targeting Node.js, use --node --no-bundle-external. This will disable browser-field resolution in package.json and not bundle node_modules.

Point the package

Set main in package.json to the precompiled version:

  "main": "dist/js2coffee.js"

All done

  • Every time npm publish is called, the pre-built version (dist/js2coffee.js) gets built
  • Doing require('js2coffee') will point to the dist/ version
  • Doing require('../index') in your tests will point to the source version
  • You can also do require('js2coffee/index') from other packages


For babeljs, I recommend using --loose for libraries that will target legacy IE.

-t [ babelify --loose all ]