This guide is part of The Complete Guide to ES6 with Babel 6 series. If you’re having trouble upgrading to Babel 6, start with Six Things You Need To Know About Babel 6.
Even if you write your NPM package with ES2015, it is important that the code you publish is compatible with everyone else’s JavaScript environments. That means compiling your code to ES5 before publishing it. And of course, the best way to do so is with the Babel CLI.
Before we set up compilation with Babel 6, make sure to delete any previous Babel-related packages from your project’s node_modules
directory — babel
, babel-core
, etc.. Once you’ve done so, install the babel-cli
package and ES2015 preset:
npm install babel-cli babel-preset-es2015 --save-dev
If you’d like to use proposed ES7 features, you’ll also need to install the babel-preset-stage-0
package:
npm install babel-preset-stage-0 --save-dev
To instruct Babel to use the installed presets, pass them to to the --presets
option as a comma-separated list. So assuming your source is in a src
directory and you want to place your output in lib
, you’d do this:
./node_modules/.bin/babel --presets es2015,stage-0 -d lib/ src/
We call Babel from ./node_modules/.bin/babel
instead of installing babel globally with npm install babel-cli -g
to ensure that we’re not messing up the environment of any other projects using Babel 5. But typing out this command sure doesn’t sound like much fun, so let’s record this in package.json
as a compile
script:
"scripts": {
"compile": "babel --presets es2015,stage-0 -d lib/ src/"
}
You can now compile your project by just typing npm run compile
from your project root.
Finally, let’s add a prepublish
script to ensure compilation happens automatically before uploading to NPM:
"scripts": {
"compile": "babel --presets es2015,stage-0 -d lib/ src/",
"prepublish": "npm run compile"
}
Don’t forget to add lib
to your .gitignore
file, and src/
to your .npmignore
file!
# .gitignore - the files to not push via git
lib
# .npmignore - the files to not push to NPM
src/
.babelrc
Note that you could omit the --presets es2015,stage-0
, and instead add a .babelrc
file:
{
"presets": ["es2015","stage-0"]
}
However, my recommendation is to keep the options to your command-line tools on the command line.
Babel Runtime
Babel can’t support all of ES6 with compilation alone – it also needs to add some code to your application.
This is generally solved by requiring the babel-polyfill package at the entry point of your application. This package polyfills new ES6 Built-ins like Map, Set and Promise, while also requiring babel-runtime to add runtime support for Babel’s generators.
However. If you’re publishing a library to NPM, it is bad practice to mess with the entire global environment. In this case, you have three options:
- Avoid features which require runtime support (including new Built-ins and generators)
- Require
babel-runtime
directly, allowing usage of generators, but not polyfills which would modify the global environment - Require
babel-polyfill
as a peer dependency and document that the consuming app must require it
Examples
For an example of an NPM package configured with Babel 6, see react-pacomo.
More ways to Babel
Now that you’ve got your library building with ES6, why not test it with ES6 too? And write your tasks with it. And write your app with it…
- Testing with Mocha and Babel’s
register
script - Running tasks with
gulpfile.babel.js
- Using ES6 in the Browser with Webpack’s babel-loader
Keeping up to date
So you’ve made Babel 6 work. But the JavaScript world moves fast — how long will it stay working?
If trying to keep up feel overwhelming, I’d love to help! Just subscribe to my free Newsletter to receive news and guides on the most important tools for people making small apps with React. And in return for your e-mail, you’ll immediately receive three bonus print-optimised PDF cheatsheets – on React (see preview), ES6 and JavaScript promises. All for free!
I will send you useful articles, cheatsheets and code.
One more thing – I love hearing your questions, offers and opinions. If you have something to say, leave a comment or send me an e-mail at james@jamesknelson.com. I’m looking forward to hearing from you!
`”prepublish”: “npm run compile”,` has a extra comma
Thanks for picking that up! I’ve made an update.
Can you help me with compile decorators? I wrote the following commands:
$ npm install -g babel-cli
$ npm install babel-preset-es2015 babel-preset-stage-0 –save-dev
$ npm install core-decorators –save
Сreate file with name src/main.js:
https://github.com/jayphelps/core-decorators.js#readonly
The last command:
$ babel –presets es2015,stage-0 -d lib/ src/
Result in console:
src\main.js -> lib\main.js
result in file:
‘use strict’;
var _coreDecorators = require(‘core-decorators’);
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(“Cannot call a class as a function”); } }
var Meal = function Meal() {
_classCallCheck(this, Meal);
};
var dinner = new Meal();
dinner.entree = ‘salmon’;
Thanks for the blogpost. But beware of prepublish!!! https://github.com/npm/npm/issues/10074
Thanks for the heads-up, Kent. I’ll keep a watch on that issue.
I made yeoman `babel` generator to simplify process of getting babel up and running in your project https://github.com/iamstarkov/generator-babel
Please, take a look if you are interested or file an issue if you will find any bug
Thanks for the awesome guide! I really liked how you cleared up the usage of polyfill/runtime.
However, I’m a bit troubled how to run our applications in production. The official documentation states that you should not use babel-node in production: “You should not be using babel-node in production. It is unnecessarily heavy, with high memory usage due to the cache being stored in memory. You will also always experience a startup performance penalty as the entire app needs to be compiled on the fly.”
But the docs doesn’t say anything about the require-hook / babel-register. My understanding is that they are quite similar in function, they both compile on the fly and cache files and they both include the polyfill. So, if you want to run your application in production properly, is the only way to transpile ahead of time? I wouldn’t mind seeing a guide on this topic 😉
> However, my recommendation is to keep the options to your command-line tools on the command line.
I would argue instead that you should keep your config options for your project in a config file.
Just because you *can* pass something as a command line argument doesn’t mean that’s the right way to do it.
Thanks for the tip! Found your blog after serving npm with ES2015 source in a first attempt to publish a package 🙂
Regards,
George
“prepublish”: “npm run compile”
this automatic script is good. but in some case, npm will not publish the lib/ dir randomly.
if somebody ran into this issue, just remove this script and compile manual before publish.
ref: https://github.com/npm/npm/issues/5082