I am using an ES6 rest parameter in the simplest possible way:
function func(a, ...b) {
for (var i = 0; i < b.length; i += 2) {
console.log(b[i], b[i + 1]);
}
}
I've installed babel-preset-es2015, and my .babelrc file simply has:
{
"presets": ["es2015"]
}
Strangely, the resulting output is:
"use strict";
function func(a) {
for (var i = 0; i < arguments.length; i += 2) {
console.log(arguments[i], arguments[i + 1]);
}
}
I filed a bug at https://phabricator.babeljs.io/T7000, but I'm extremely concerned since this is the second time I've had really basic ES6 transpile incorrectly using Babel 6. Is my setup broken? Is Babel 6 documented somewhere as unstable/alpha? Or is this highly popular module really just that bad? Are there any alternate ES6 transpilers out there written with compiler-grade rigor and comprehensive test suites that would be safe to use?
The transform you're looking for is http://babeljs.io/docs/plugins/transform-object-rest-spread/, which is not part of babel-preset-es2015, but is part of babel-preset-stage-2, or you can install it by itself.
Here's what I discovered.
A preset is a collection of transform plugins, all versioned with ^. It seems that as these transform versions are bumped, new version of the preset are not published. It's not a good source for a curated set of plugins that are known to work together. So in my case, despite the fact that I had the latest babel-preset-es2015, and a new version of that didn't exist, it didn't mean I had all the latest plugins as well.
Forcing newer versions of the constituent plugins fixed the issue for me. The preset version tells you nothing useful apparently. If you don't have a direct dependency on the plugins themselves, the only way to force them to update is to force a reinstall of the preset.
I had the same ES6 rest parameter problem as Jacob had. I followed yaycmyk's advice and did npm install babel-preset-stage-2 and then changed my gulp file from
pipe(babel({ presets: ['es2015'] })) to
pipe(babel({ presets: ['es2015', 'stage-2'] })) and on my merry way I went.
Related
I added bundleconfig.json to ASP.NET Core application. It has the following structure:
[
{
"outputFileName": "wwwroot/js/main.min.js",
"inputFiles": [
"wwwroot/js/scripts/first.js",
"wwwroot/js/scripts/second.js"
],
"minify": {
"enabled": true,
"renameLocals": true
},
"sourceMap": false
}
]
Both scripts has been minified and merged into main.min.js. But after minification all async modifiers has been removed from result script.
Function such as
async function foo() {
await /* some promise */;
}
have been turned into:
function foo() {await /*some promise*/;}
How do I avoid removing async modifier?
I'v reproduced the issue and tried to minify a simple js file that using ES6 specifications and later.
Test.js
async function foo() {
await bar();
}
async function bar() {
for (var i = 0; i < 10; i++) { // do some work
}
}
Then i tried to minify the file with Bundler and Minifier tool then this error thrown:
This means Bundler and Minifier doesn't support ES6 specifications and later.
For confirmation i started searching about this issue in the Github and i found these same behaviors
Crash on ES6 arrow functions in source files
minify es6 js file without turning them to es5
Where BundleMinifier currently is usefull (and where not)
I can surely claim that this is The Transpilers Issue
Transpilers, or source-to-source compilers, are tools that read source
code written in one programming language, and produce the equivalent
code in another language.
The most common and widely use one is TypeScript
TypeScript in some cases Transpiles ES6 and later to ES5
For example: if you set Target to ES6 and ES2015 it Transpiles to ES5. However, if You Target to ES2020 does NOT Transpile your code.
At The End
BundlerMinifier uses NUglify that perform javascript code
minification So There is NO way minifying ES6 and later codes by
using Bundler and Minifier. Unless, The Author decides to support it.
You are encountering The Transpile Issue (ex:ES6 to ES5).
Bundler & Minifier doesn't remove unknown keywords like async but thrown error
I'm new to Gulp and the concept of task runners. I am wanting to write some javascript using es6 and have gulp run it through jscs, jshint and finally use babel to convert it to es5.
The part I'm confused about is the order I should have these tasks in my gulp pipeline. If I run jshint first I get warnings about how I can't use let and arrow functions. However, if I convert my code using babel first the babel output then fails validation as well.
What I'm looking for is a correct way of ordering my gulp task so it validates and converts my code to es5.
This is my current gulp task.
gulp.task('js-validation', function() {
$.util.log('**Starting js validation**');
return gulp
.src(config.alljs)
.pipe($.print())
.pipe($.jshint())
.pipe($.jscs())
.pipe($.babel())
.pipe($.jshint.reporter('jshint-stylish', {verbose: true}))
.pipe($.jshint.reporter('fail'))
.pipe(gulp.dest(config.temp));
});
This work for me:
.pipe(jshint({
esnext: true
}))
First, if possible, consider moving to ESLint; I'm not saying that because it's a subjective opinion, I'm saying that because it's modular and supports ES6, and even React+JSX if that's where you want to go with it.
You aren't going to have a lot of luck with JSHint, yet, if ES6 is where you're going.
If/when I'm wrong, please let me know, but I believe they have yet to replace their parser, to support all of ES6, and unless you're going to include the entirety of the browser polyfill+library in the pipeline (just for sake of having no missing methods, for validate to work), you may well be at a loss, here.
With ESLint in place, you could use the following config options (in .eslintrc, in the package.json, et cetera), to get ES6 support:
{
"env": {
"browser": true,
"node": true,
"es6": true
},
"ecmaFeatures": {
"modules": true,
"jsx": true
}
}
Of course, if you don't need node globals, JSX or ES6 modules, feel free to rip those out.
The one other caveat there is that ESLint has no support for ES7 (ES2016), yet (but will, when it's standardized).
So array/generator comprehensions, async/await, trailing commas in function argument lists, et cetera, are not supported and will cause explosions.
There is a babel-eslint version of eslint which will validate these, if that's your requirement.
You can put that in place by installing "babel-eslint" and then in your eslint config, setting { "parser": "babel-eslint" } to the root object, along with all of your other config preferences.
But typically, you would lint the code that you are putting into the system, pre-compile, using ESLint and Babel:
// ...
.pipe( eslint() )
.pipe( babel() )
// ...
To lint the source code (rather then the compiled code) you have to call the linter before babel, so the order is correct.
However, you have to use a linter that really understands ES6. With JSHint, you have to set the esnext option, but I'm not sure whether it supports all ES6 features. I recommend to have a look at eslint with babel-eslint instead.
Instead of JSHint, you can use ESLint, which will have support for numerous ES6 functions:
http://eslint.org/docs/user-guide/configuring
You are correct that you want your linting to occur prior to transpilation, also.
gulp.task('jshint', function () {
gulp.src('js/**/*.js')
.pipe(cache('jshint'))
.pipe(jshint({esnext:true}))
.pipe(jshint.reporter('default'));
});
.pipe(jshint({esnext:true}))
You have the correct order, but as suggested from other answers to use ESLint. You should also have a function to handle errors when linting. Here is my gulpfile.js (not a perfect example, but it's working for me):
const gulp = require("gulp"),
babel = require("gulp-babel"),
eslint = require("gulp-eslint");
gulp.task("babel", () => {
gulp.src("src/*.js")
.pipe(eslint())
.pipe(eslint.format())
.pipe(eslint.failAfterError())
.on("error", onError) // handle error for eslint
.pipe(babel())
.on("error", onError) // handle error for babel
.pipe(gulp.dest("dist"));
});
gulp.task("watch", () => {
process.chdir(process.env.INIT_CWD);
gulp.watch("src/*.js", ["babel"]);
});
// ignore if error is from babel, eslint error message is enough
if (err.plugin != "gulp-babel" && err.message) {
console.log("Message: ", err.message);
}
I have tests for an addon which pass in chrome, but fail in phantomjs.
It seems to be a problem similar to this question. However, I tried the solution there and it didn't work for me.
The code is all available in the public repo linked above. The failures are exhibited in the failing travis build on github. Any ideas on how to diagnose better and fix?
EDIT -- actual error message
Died on test #1 at http://localhost:7357/assets/test-support.js:3062
at test (http://localhost:7357/assets/test-support.js:1945)
at test (http://localhost:7357/assets/dummy.js:2090)
at http://localhost:7357/assets/dummy.js:2885
at http://localhost:7357/assets/vendor.js:150
at tryFinally (http://localhost:7357/assets/vendor.js:30)
at http://localhost:7357/assets/vendor.js:156
at http://localhost:7357/assets/test-loader.js:29
at http://localhost:7357/assets/test-loader.js:21
at http://localhost:7357/assets/test-loader.js:40
at http://localhost:7357/assets/test-support.js:6775: Can't find variable: Symbol
UPDATE
Following up on a hint from #knownasilya, I tried forcing optional babel transform es6.spec.symbols on: in ember-cli-build.js:
module.exports = function(defaults) {
var app = new EmberAddon(defaults, {
// Add options here
+ babel: {
+ optional: ['es6.spec.symbols']
+ }
});
However -- no luck. It does look like an es6 transpilation problem, though. Did I not pass the option successfully? Any other hints? I'll be happy to post code snippets if you don't want to look in the repo. :)
UPDATE 2
Including as well:
+ includePolyfill: true
works!
Now I'm on to:
ReferenceError: Can't find variable: requestAnimationFrame
I'm looking for a polyfill for this as well... but looking at the testem configuration for ember-collection, which seems to have a similar configuration, I notice that phantomjs testing is turned off! Now the question is: best way to test requestAnimationFrame in phantomjs?
The offending culprit is Can't find variable: Symbol, which is an ES2015 (ES6) feature, which is why the es5 shim didn't work for you.
Since babel doesn't include polyfills by default, you need to force ember-cli-babel to include the polyfills.
// ember-cli-build.js
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function(defaults) {
const app = new EmberApp(defaults, {
'ember-cli-babel': {
includePolyfill: true
}
});
return app.toTree();
};
For details of the available options, see https://github.com/babel/ember-cli-babel#options
For a more comprehensive solution, give babel6 (https://github.com/ember-cli/ember-cli/pull/6828) and targets (https://github.com/ember-cli/ember-cli/pull/6776) a try.
Note: The polyfill includes core.js which includes Symbols.
I am trying to run Karma-babel-preprocessor and a straight forward ES6 generator:
//require('babel/polyfill');
describe("how Generators work", function() {
it("will allow generator functions", function() {
/*function * numbers() {
yield 1;
yield 2;
yield 3;
};*/
let numbers = {
[Symbol.iterator]:function*(){
yield 1;
yield 2;
yield 3;
}
}
let sum = 0;
for(n of numbers){
sum += n;
}
expect(sum).toBe(6);
});
});
From this I generated my test files (ES6 => ES5) with babel:
babel src --watch --out-dir tests
Then I run karma start I get error:
ReferenceError: regeneratorRuntime is not defined".
Relevant bits in karma.conf.js:
// list of files / patterns to load in the browser
files: [
'test-main.js',
{pattern: 'tests/*.js', included: true}
],
// list of files to exclude
exclude: [
],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'src/*.js': ['babel']
},
'babelPreprocessor': {
options: {
sourceMap: 'inline'
},
filename: function(file) {
return file.originalPath.replace(/\.js$/, '.es5.js');
},
sourceFileName: function(file) {
return file.originalPath;
}
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress'],
Full project on github
I am able to use many ES6 features including arrows. Just no go on Generators.
Node js Env - updated December 2015
This question has already been answered, please see accepted answer UNLESS running within NodeJS environment.
If like myself, you had the same error message: 'ReferenceError: regeneratorRuntime is not defined' but were running Babel within a NodeJS environment, then simply doing the following will likely solve your problem:
npm install babel-polyfill --save
Then insert the following require statement towards the top of the affected module to obtain required (generator) behaviour:
require("babel-polyfill");
This should be all you need, just importing the module adds required polyfill behaviour at runtime.
Similar to the post by arcseldon, I was running Babel within a NodeJS environment and getting the same error message 'ReferenceError: regeneratorRuntime is not defined'. While installing babel-polyfill does work, I went with #babel/plugin-transform-runtime instead.
#babel/plugin-transform-runtime
It needs to be installed in two ways ... first as a dev dependency:
npm install --save-dev #babel/plugin-transform-runtime
and second as a production dependency:
npm install --save #babel/runtime
And then there needs to be one simple addition to your .babelrc file:
{
"plugins": ["#babel/plugin-transform-runtime"]
}
These additions give ES6 authoring functionality without the ReferenceError.
While I'm taking a different approach** to using Karma with Babel in my project, I suspect you're having the same problem I was: the Babel polyfill is not being loaded, and so you're not getting the functionality it supports (including the custom regenerator runtime that Babel uses to make generators work).
One approach would be to find a way to include the polyfill, perhaps by feeding it to Karma via the files array:
files: [
'path/to/browser-polyfill.js', // edited: polyfill => browser-polyfill per P.Brian.Mackey's answer
...
An alternate approach may be to use Babel's runtime transformer [edit: on rereading the docs, this will not work unless you then browserify/webpack/etc. to process the require() calls created by the transformer]; per its docs,
The runtime optional transformer does three things:
Automatically requires babel-runtime/regenerator when you use generators/async functions.
Automatically requires babel-runtime/core-js and maps ES6 static methods and built-ins.
Removes the inline babel helpers and uses the module babel-runtime/helpers instead.
I have no experience with this, but I suspect you would do so by including the optional: ['runtime'] option from the Babel docs in your babelPreprocessor config, viz.:
'babelPreprocessor': {
options: {
optional: ['runtime'], // per http://babeljs.io/docs/usage/options/
sourceMap: 'inline'
},
...
(** I'm currently using jspm + jspm-karma + some config to get the Babel polyfill to load in SystemJS; ask if relevant and I'll expound.)
I modified karma.conf.js to add browser-polyfill as mentioned in the Docs Link:
files: [
'node_modules/babel/browser-polyfill.js',
'test-main.js',
{pattern: 'tests/*.js', included: true}
],
After this modification, the following unit test works in Karma:
describe("how Generators work", function() {
it("will allow generator functions", function() {
/*function* numbers(){
yield 1;
yield 2;
yield 3;
};*///Simplified syntax does not work
let numbers = {
[Symbol.iterator]:function*(){
yield 1;
yield 2;
yield 3;
}
}
let sum = 0;
for(let num of numbers){
sum += num;
}
expect(sum).toBe(6);
});
});
If you use React, adding polyfills from create-react-app worked for me.
yarn add --dev react-app-polyfill
Then add the following lines to webpack.config.js
entry: {
app: [
'react-app-polyfill/ie9', // Only if you want to support IE 9
'react-app-polyfill/stable',
'./src/index.jsx',
],
},
See more examples on the react-app-polyfill GitHub page.
There is a proposal for introducing C# style async-await. I know Babel.js transpiles ES6 to ES5, but is there any way to make it transpile async-await to ES5?
Babel v6
As of Babel v6, Babel doesn't contain any transformers itself anymore. You have to explicitly specify any feature you want to transform.
Presets - non ES2015 environment
The quickest way to get this working is to use presets which already contain the set of plugins needed to transform ES2015 and newer proposals. For async, you will need the es2015 and es2017 presets and the runtime plugin (don't forget to install babel-runtime as described in the documentation):
{
"presets": [
"es2015",
"es2017"
],
"plugins": [
"transform-runtime"
]
}
Presets - ES2015 environment
If you run the code in an environment that supports ES2015 (more specifically, generators and Promises), then all you need is the es2017 preset:
{
"presets": [
"es2017"
]
}
Custom
To only transform the async functions, you will need the following plugins.
syntax-async-functions is needed in any every case to be able to parse async functions
In order to run the async function, you either need to use
transform-async-to-generator: Converts the async function into a generator. This will use Babel's own "co-routine" implementation.
transform-async-to-module-method: Also converts the async function to a generator, but passes it to the module and method specified in the configuration instead of Babel's own method. This allows you to use external libraries such as bluebird.
If your code runs in an environment that supports generators, then there is nothing left to do. However, if the target environment does not support generators, you will also have to transform the generator. This is done via the transform-regenerator transform. This transform depends on runtime functions, so you will also need Babel's transform-runtime transform (+ the babel-runtime package).
Examples:
Async to generator
{
"plugins": [
"syntax-async-functions",
"transform-async-to-generator"
]
}
Async to module method
{
"plugins": [
"syntax-async-functions",
["transform-async-to-module-method", {
"module": "bluebird",
"method": "coroutine"
}]
]
}
Async to generator + regenerator
{
"plugins": [
"syntax-async-functions",
"transform-async-to-generator",
"transform-regenerator",
"transform-runtime"
]
}
Babel v4 and older
Yes, you have to enable the experimental transformers. Babel uses regenerator.
Usage
$ babel --experimental
babel.transform("code", { experimental: true });
This solution may have changed since (Feb 25 Felix Kling) or perhaps there is still more than one way to use async await.
What worked for us was to run Babel like so
$ npm install babel-runtime
$ babel inputES7.js -o outputES5.js --optional runtime
I got this working as-of today by doing an additional npm install babel-preset-stage-0 and using it like
var babel = require("babel-core");
var transpiled = babel.transform(code, { "presets": ["stage-0"] });
See
http://babeljs.io/docs/usage/options/#options
http://babeljs.io/docs/plugins/preset-stage-0/
Perhaps even more up-to-date now; just put the babel stuff in a separate file:
'use strict';
require('babel/register'); // Imports babel - auto transpiles the other stuff
require('./app'); // this is es6 - gets transpiled
See my code at how-can-i-use-es2016-es7-async-await-in-my-acceptance-tests-for-a-koa-js-app for some more details.
The approved answer seems to be outdated now. The experimental flag has been deprecated in favor of stage.
http://babeljs.io/blog/2015/03/31/5.0.0/#experimental-option
Usage
$ babel --stage 0
babel.transform("code", { stage: 0 });
Stage 0
es7.classProperties
es7.comprehensions
Stage 1
es7.asyncFunctions
es7.decorators
es7.exportExtensions
es7.objectRestSpread
Stage 2 (Stage 2 and above are enabled by default)
es7.exponentiationOperator