I'm trying to configure Babel for Node v6.9.2. I want to use async/await constructs.
Because I'm new to Babel and all Node infrastructure, I confused how to configure it properly:
What preset should I use? Node is already implemented most of the ES6 features. So I don't want Babel to transpile features already supported by Node 6.9.x (arrow functions, new import mechanism etc) for performance reasons.
What plugins should I include so I can use async/await? There I also confused, because after some researching I found several plugins: syntax-async-functions, transform-async-to-generator and some more.
Example of .babelrc will help.
Thanks
What preset should I use?
You don't need to use any preset. Presets are just a collection of plugins which makes it easier to use if you want to transpile a set of features (for instance all ES2015 with preset-es2015). But when you want to transpile only a selection of these features, you only include the corresponding plugins.
What plugins should I include so I can use async/await?
Because Node 6 supports generators, you can use transform-async-to-generator with the following .babelrc:
{
"plugins": ["transform-async-to-generator"]
}
And of course you would need to add plugins if you need to transpile more unsupported features.
Alternative babel-preset-env
babel-preset-env automatically determines what plugins you need for the specified environment. This will not include any plugins that are not necessary. To specify your current Node version you would use this .babelrc:
{
"presets": [
["env", {
"targets": {
"node": "current"
}
}]
]
}
Short answer
Use Babel preset for Node 6.x:
https://www.npmjs.com/package/babel-preset-node6
Long answer
To see what ES feature is supported in a given Node version, see:
http://node.green/
For async/await support in particular, see:
http://node.green/#ES2017-features-async-functions
If you use Node v7.x (the current version) then you can use the --harmony flag and use async/await natively without transpilation.
Node v8.x (available as nightly builds) doesn't even need the --harmony flag for that.
But note that Node doesn't support import/export - to know why see:
javascript - Why is there a spec for sync and async modules?
Exporting Node module from promise result
Related
I noticed that Babel wasn't transforming this:
function({ param, ...rest }) {}
This syntax is already supported in the latest popular browsers. However, according to Mozilla (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment), it's not supported in browsers as new as Edge 79 (released this year).
I tried manually enabling some Babel plugins, but it didn't work:
#babel/plugin-transform-destructuring
#babel/plugin-proposal-object-rest-spread
#babel/plugin-syntax-object-rest-spread
#babel/plugin-transform-parameters
Is it possible to transform this syntax with Babel? I need to do testing in older browsers, but I'm getting SyntaxError: invalid property id because of this.
Sometimes babel needs to combine more than one plugins to transform something. In this case I think you would need to combine at least 2 plugins:
#babel/plugin-transform-destructuring
#babel/plugin-transform-parameters
npx babel /path/to/yourFile plugins=#babel/plugin-transform-destructuring,#babel/plugin-transform-parameters
To make life easier, I would suggest to use preset-env instead which supports official ES changes (since it includes all official plugins for you):
npx babel /path/to/yourFile presets=#babel/preset-env
In order to setup webpack + babel + react, I was told to include following in .babelrc:
"presets": ["latest", "stage-0", "react"]
I want to understand: why should I use babel presets, what do they allow me to do (apart from babel itself)? That's one question. Hope that's not opinion-based (in terms of stackoverflow), it's about how babel works.
As far as I read in the docs, preset-latest combines preset-es2015 + preset-es2016 + preset-es2017. As far as I understand, these are officially accepted features of upcoming ES versions and latest is a shorthand for choosing not only ES2015, but all future versions at one shot. The specs won't change, so it's stable enough to use in production.
But how about stage-0, stage-1, stage-2, stage-3 - do they represent features that are still unofficial proposals of upcoming ECMAScript versions or does that stand for something else? Babel docs is not clear about that. That's second question.
And finally, what is the difference between a plugin and a preset?
...why should I use babel presets, what do they allow me to do...
A Babel preset conveniently defines a group of Babel plugins so that you don't have to explicitly declare you want to use each of them under "plugins" in your .babelrc (or wherever you declare your config).
Take a look at the source code of the es2016 preset and you'll see what I mean... it simply exports an array of plugins: https://github.com/babel/babel/blob/master/packages/babel-preset-es2016/src/index.js
...(apart from babel itself)?
Babel itself is an interface for its plugins. It utilises a sibling program, babylon, a fork of acorn, that provides plugins a particular way of parsing, inspecting, and then manipulating the source code of your program, in order to add the features you want according to the plugins you use.
And finally, what is the difference between a plugin and a preset?
As discussed, a preset itself does not contain features, rather a list of plugins. Together these typically represent some related group of functionality. For example, the stage-0 preset will contain all plugins that implement features of proposals which are at stage zero of the process of submission defined by TC39, ECMAScript's "governing body".
You might have noticed that a preset is a JavaScript file instead of JSON. This is because the list of plugins that a preset defines can be derived from a configuration. Take a look at the env preset, for example: https://github.com/babel/babel-preset-env/blob/master/src/index.js
But how about stage-0, stage-1, stage-2, stage-3 - do they represent features that are still unofficial proposals of upcoming ECMAScript versions or does that stand for something else?
There are no "official" proposals. A proposal can be submitted by anyone. But if what you mean by official is whether the proposal is being seriously considered, that is determined by 1) what stage it is at in the process and 2) general consideration by the community of its worth as a new feature. However you should always take proposals with a pinch of salt in terms of whether they will be accepted, even at the last stage, as we have experienced with Object#observe, which was dropped at the very last minute.
I also didn't understand why "modules": false and why there is an "env" setting and that env has its own preset configuration.
Finally, I found this article What's in our .babelrc? explains it well, e.g
Secondly, we set modules to false to ensure that import statements are
left as is (opposed to transpiling them to require). We're doing this
to give Webpack the ability to statically analyze our code to produce
more efficient bundles.
Lastly, we have an environment specific override for Jest, our testing
framework of choice. Since Jest is run in node, we need to transpile
our imports to requires, and target whatever node runtime we're
currently working in.
The This-Bind operator is a proposal for convenient this method-binding syntax for ES7:
// this-bind via '::'
$(".some-link").on("click", ::view.reset);
// oldschool .bind(this, ...)
$(".some-link").on("click", view.reset.bind(view))
// or even longer...
$(".some-link").on("click", function () {
return view.reset.apply(view, Array.prototype.slice.call(arguments));
})
// and even ES6 while is more handy, but still leaves some redundancy
$(".some-link").on("click", (...args) => view.reset(...args));
The problem is, well, it still in proposal stage for future (7) version of ES, so it wasn't yet included in standart and thus not supported by ESLint, while can be still used via tanspiling (with Babel, f.e.).
The question is, is there any modules/plugins/options for ESLint to support function-bind operator (or whole set of ES7 experimental features) syntax?
Well, while I surfed net in preparation of this question, I found, that Babel has implementation of it's own custom parser for ESLint, which allows to lint any valid Babel code.
In order to use it you should:
Instal babel-eslint parser first via npm:
$ npm install eslint babel-eslint --save-dev
Configure ESLint to use custom parser, by specifying it in .eslintrc file:
f.e. .eslintrc.json:
{
"parser": "babel-eslint",
...
}
If you using SublimeLinter, togle linter off/on in order to reload config.
I'm using TypeScript (1.6) with node under the --harmony flag, so I'd like to transpile the es6 module syntax to commonjs.
From what I can tell, I can't do this with TypeScript 1.6. If I set my target to es6, and module to commonjs, I get a TypeScript error -
Cannot compile modules into 'commonjs', 'amd', 'system' or 'umd' when
targeting 'ES6' or higher.
Why won't TypeScript compile to commonjs with an ES6 target? I imagine a lot people want to do this since node doesn't support ES6 modules yet.
I'd thought the new moduleResolution compiler option might solve this issue, but it doesn't appear to do anything.
Currently, I'm having to use babel just to transpile the module syntax to commonjs, but I'd like to remove babel from my builds so I can take advantage of source maps.
Is there a way I can achieve this? NOTE: I do not want to transpile to ES5. I want my JS running as ES6 under the harmony flag. Thanks!
The TypeScript team will add support for what you are looking for in the next release. You can wait for a few weeks/months. Alternatively, you can use a Polyfill for the ES6 module loader:
es6-module-loader
SystemJS
There are more libraries like the ones above available online just check which one does the job for you until official support for --module with --target es6 arrives.
UPDATE
tsconfig.json
{
"compilerOptions": {
"target":"ES6",
"moduleResolution": "classic",
}
}
ES6 support with generators
No import stuff transpiling due to
"moduleResolution": "classic"
I just started to use Babel to compile my ES6 javascript code into ES5. When I start to use Promises it looks like it's not working. The Babel website states support for promises via polyfills.
Without any luck, I tried to add:
require("babel/polyfill");
or
import * as p from "babel/polyfill";
With that I'll get the following error on my app bootstrapping:
Cannot find module 'babel/polyfill'
I searched for the module but it seems I'm missing some fundamental thing here. I also tried to add the old and good bluebird NPM but it looks like it's not working.
How to use the polyfills from Babel?
This changed a bit in babel v6.
From the docs:
The polyfill will emulate a full ES6 environment. This polyfill is automatically loaded when using babel-node.
Installation:
$ npm install babel-polyfill
Usage in Node / Browserify / Webpack:
To include the polyfill you need to require it at the top of the entry point to your application.
require("babel-polyfill");
Usage in Browser:
Available from the dist/polyfill.js file within a babel-polyfill npm release. This needs to be included before all your compiled Babel code. You can either prepend it to your compiled code or include it in a <script> before it.
NOTE: Do not require this via browserify etc, use babel-polyfill.
The Babel docs describe this pretty concisely:
Babel includes a polyfill that includes a custom regenerator runtime
and core.js.
This will emulate a full ES6 environment. This polyfill is
automatically loaded when using babel-node and babel/register.
Make sure you require it at the entry-point to your application, before anything else is called. If you're using a tool like webpack, that becomes pretty simple (you can tell webpack to include it in the bundle).
If you're using a tool like gulp-babel or babel-loader, you need to also install the babel package itself to use the polyfill.
Also note that for modules that affect the global scope (polyfills and the like), you can use a terse import to avoid having unused variables in your module:
import 'babel/polyfill';
For Babel version 7, if your are using #babel/preset-env, to include polyfill all you have to do is add a flag 'useBuiltIns' with the value of 'usage' in your babel configuration. There is no need to require or import polyfill at the entry point of your App.
With this flag specified, babel#7 will optimize and only include the polyfills you needs.
To use this flag, after installation:
npm install --save-dev #babel/core #babel/cli #babel/preset-env
npm install --save #babel/polyfill
Simply add the flag:
useBuiltIns: "usage"
to your babel configuration file called "babel.config.js" (also new to Babel#7), under the "#babel/env" section:
// file: babel.config.js
module.exports = () => {
const presets = [
[
"#babel/env",
{
targets: { /* your targeted browser */ },
useBuiltIns: "usage" // <-----------------*** add this
}
]
];
return { presets };
};
Reference:
usage#polyfill
babel-polyfill#usage-in-node-browserify-webpack
babel-preset-env#usebuiltins
Update Aug 2019:
With the release of Babel 7.4.0 (March 19, 2019) #babel/polyfill is deprecated. Instead of installing #babe/polyfill, you will install core-js:
npm install --save core-js#3
A new entry corejs is added to your babel.config.js
// file: babel.config.js
module.exports = () => {
const presets = [
[
"#babel/env",
{
targets: { /* your targeted browser */ },
useBuiltIns: "usage",
corejs: 3 // <----- specify version of corejs used
}
]
];
return { presets };
};
see example: https://github.com/ApolloTang/stackoverflow-eg--babel-v7.4.0-polyfill-w-core-v3
Reference:
7.4.0 Released: core-js 3, static private methods and partial
application
core-js#3, babel and a look into the future
If your package.json looks something like the following:
...
"devDependencies": {
"babel": "^6.5.2",
"babel-eslint": "^6.0.4",
"babel-polyfill": "^6.8.0",
"babel-preset-es2015": "^6.6.0",
"babelify": "^7.3.0",
...
And you get the Cannot find module 'babel/polyfill' error message, then you probably just need to change your import statement FROM:
import "babel/polyfill";
TO:
import "babel-polyfill";
And make sure it comes before any other import statement (not necessarily at the entry point of your application).
Reference: https://babeljs.io/docs/usage/polyfill/
First off, the obvious answer that no one has provided, you need to install Babel into your application:
npm install babel --save
(or babel-core if you instead want to require('babel-core/polyfill')).
Aside from that, I have a grunt task to transpile my es6 and jsx as a build step (i.e. I don't want to use babel/register, which is why I am trying to use babel/polyfill directly in the first place), so I'd like to put more emphasis on this part of #ssube's answer:
Make sure you require it at the entry-point to your application,
before anything else is called
I ran into some weird issue where I was trying to require babel/polyfill from some shared environment startup file and I got the error the user referenced - I think it might have had something to do with how babel orders imports versus requires but I'm unable to reproduce now. Anyway, moving import 'babel/polyfill' as the first line in both my client and server startup scripts fixed the problem.
Note that if you instead want to use require('babel/polyfill') I would make sure all your other module loader statements are also requires and not use imports - avoid mixing the two. In other words, if you have any import statements in your startup script, make import babel/polyfill the first line in your script rather than require('babel/polyfill').
babel-polyfill allows you to use the full set of ES6 features beyond
syntax changes. This includes features such as new built-in objects
like Promises and WeakMap, as well as new static methods like
Array.from or Object.assign.
Without babel-polyfill, babel only allows you to use features like
arrow functions, destructuring, default arguments, and other
syntax-specific features introduced in ES6.
https://www.quora.com/What-does-babel-polyfill-do
https://hackernoon.com/polyfills-everything-you-ever-wanted-to-know-or-maybe-a-bit-less-7c8de164e423
Like Babel says in the docs, for Babel > 7.4.0 the module #babel/polyfill is deprecated, so it's recommended to use directly core-js and regenerator-runtime libraries that before were included in #babel/polyfill.
So this worked for me:
npm install --save core-js#3.6.5
npm install regenerator-runtime
then add to the very top of your initial js file:
import 'core-js/stable';
import 'regenerator-runtime/runtime';