This post is part of a series of three:
Figuring out the best strategy for transpiling with Babel is tricky. This blog post proposes a new strategy, made possible by Babel’s preset-env
.
For a while, the best approach for building web apps via webpack was:
preset-latest
:
Then Babel introduced preset-env
, which lets you adapt the code you generate to the platforms it will run on. Now, the best approach would be:
preset-env
.
The benefits of this new approach are:
preset-env
).How can we deliver both transpiled and untranspiled code in npm packages?
Three properties in package.json
currently let you deliver multiple versions of the same code (for more information, consult “Setting up multi-platform npm packages”):
main
: points to a CommonJS module (or UMD module) with JavaScript as modern as Node.js can currently handle.browser
: swaps out some of the main
code so that it works in browsers.module
: the same code as main
, but in ES modules.es2015
: untranspiled ES6 code. Introduced by Angular.Alas, none of these properties help with delivering untranspiled code beyond ES6 (es2015
) or beyond what’s currently supported in Node.js (module
).
pkg.esnext
pkg.foo
is an abbreviation for “property foo
in package.json
”.
I propose to use package.json
as follows:
esnext
: source code using stage 4 features (or older), not transpiled, in ES modules.main
continues to be used the same way. Its code can be generated from the untranspiled code.module
use cases should be handleable via esnext
.browser
can be handled via an extended version of esnext
(see next section).The next blog post in this series describes how to implement this approach.
This is an excerpt of a package.json
using the new property:
{
···
"main": "main.js",
"esnext": "main-esnext.js",
···
}
pkg.esnext
An extended version of pkg.esnext
could be a JSON object with two properties:
main
: points to the untranspiled code.browser
: points to browser-specific untranspiled code.This would look as follows:
{
···
"main": "main.js",
"esnext": {
"main": "main-esnext.js",
"browser": "browser-specific-main-esnext.js"
},
···
}
webpack can be configured to recognize alternatives to pkg.main
(via resolve.mainFields
). That enables you to refer to untranspiled code via pkg.module
. Note that that is not exactly how module
is supposed to be used, but it lets you use packages with that property. And the following solutions become possible:
pkg.module
, via clever use of module.loaders
and include
. He documented his approach in a Gist.babel-engine-plugin
, which only transpiles packages that depend on Node.js versions newer than 0.10 (with features beyond ES5). To do so, it checks pkg.engines
. This plugin could be adapted to support the new approach outlined in this blog post.Yet another quick-and-dirty approach is to use file extensions:
.js
is never transpiled..esm
is always transpiled, even in npm-installed dependencies. It’s best not to use the upcoming file extension .mjs
, so that future code doesn’t break packages using this approach.This approach is especially handy if your own app is spread out across multiple npm packages.