ESLint and This-Bind operator - javascript

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.

Related

How to stop babel from transpiling 'this' (used as an IIFE argument) to 'void 0'? [duplicate]

EDIT: This is not about fat arrows. It's also not about passing this to an IIFE. It's a transpiler-related question.
So I've created a simple pub-sub for a little app I'm working on. I wrote it in ES6 to use spread/rest and save some headaches. I set it up with npm and gulp to transpile it but it's driving me crazy.
I made it a browser library but realized it could be used anywhere so I decided to make it Commonjs and AMD compatible.
Here's a trimmed down version of my code:
(function(root, factory) {
if(typeof define === 'function' && define.amd) {
define([], function() {
return (root.simplePubSub = factory())
});
} else if(typeof module === 'object' && module.exports) {
module.exports = (root.simplePubSub = factory())
} else {
root.simplePubSub = root.SPS = factory()
}
}(this, function() {
// return SimplePubSub
});
But no matter what I try (such as making this a variable and passing it) it sets it to undefined.
}(undefined, function() {
It probably has something to do with Babel not knowing what this will be and transpiling it away but is there any other approach I can take?
UPDATE: Passing }((window || module || {}), function() { instead of this seems to work. I'm not sure this is the best approach though.
For Babel >= 7.x
ES6 code has two processing modes:
"script" - When you load a file via a <script>, or any other standard ES5 way of loading a file
"module" - When a file is processed as an ES6 module
In Babel 7.x, files are parsed as "module" by default. The thing that is causing you trouble is that in an ES6 module, this is undefined, whereas in the "script" case, this varies depending on the environment, like window in a browser script or exports in CommonJS code. Similarly, "module" files are automatically strict, so Babel will insert "use strict";.
In Babel 7, you'll need to tell Babel what type your file is if you want to avoid this behavior. The simplest option would be to use the "sourceType" option to set sourceType: "unambiguous" in your Babel options, which essentially tells Babel to guess the type (scripts vs module), based on the presence of import and export statements. The primary downside there being that it's technically fine to have an ES6 module that doesn't use import or export, and those would be incorrectly treated as scripts. On the other hand, that's really not that common.
Alternatively, you can use Babel 7's "overrides" option to set specific files as scripts, e.g.
overrides: [{
test: "./vendor/something.umd.js",
sourceType: "script",
}],
Either approach allows Babel to know that some files are script types, and thus shouldn't have this converted to undefined.
For Babel < 7.x
ES6 code has two processing modes:
"script" - When you load a file via a <script>, or any other standard ES5 way of loading a file
"module" - When a file is processed as an ES6 module
When using Babel 6 and babel-preset-es2015 (or Babel 5), Babel by default assumes that files it processes are ES6 modules. The thing that is causing you trouble is that in an ES6 module, this is undefined and files are all strict, whereas in the "script" case, this varies depending on the environment, like window in a browser script or exports in CommonJS code.
If you are using Babel, the easiest option is to write your code without the UMD wrapper, and then bundle your file using something like Browserify to automatically add the UMD wrapper for you. Babel also provides a babel-plugin-transform-es2015-modules-umd. Both are geared toward simplicity, so if you want a customized UMD approach, they may not be for you.
Alternatively, you would need to explicitly list all of the Babel plugins in babel-preset-es2015, making sure to exclude the module-processing babel-plugin-transform-es2015-modules-commonjs plugin. Note, this will also stop the automatic addition of use strict since that is part of the ES6 spec too, you may want to add back babel-plugin-transform-strict-mode to keep your code strict automatically.
As of babel-core#6.13 presets are able to take options, so you can also do
{
"presets": [
[ "es2015", { "modules": false } ]
]
}
in your Babel config (.babelrc) to use babel-preset-es2015 with module processing disabled.
The "es2015" preset wraps the Babel output in a commonJs wrapper by default. Use the "babel-preset-es2015-script" (you must npm install --save babel-preset-es2015-script first) to output for "script" (no modules). This was wreaking havoc on other libraries I was wrapping up using Babel.
The preset: https://www.npmjs.com/package/babel-preset-es2015-script

Babel fails to compile ES6 object cloning with spread operator

I use grunt-babel to compile my ES6 code. But it returns Warning: dist/app.js: Unexpected token (321:9) Use --force to continue. when I try to use {...obj} to copy and extend object. Following code is working perfect in console of Chrome v61 but Babel doesn't like it. What is the problem?
let a = { a: 12 };
let b = { ...a, b: 15 };
I am using env preset. (babel-core v.6.26.0 and babel-preset-env v.1.6.1)
The spread property for objects is not part of ES6. Currently, as of Dec 2017, it is part of the stage 3 proposal for ECMAScript. You can have a look at the proposal here.
You need a babel preset that includes features not yet officially in the language. The babel-preset-env does not include those features.
To solve your problem, you could use something like babel-preset-stage-3 and add "stage-3" to the list of presets in your .babelrc.
Side note:
An alternative to the spread syntax for objects in ES6 is to use Object.assign
let b = Object.assign({}, a, { b: 15 });
You probably would want to add these plugins to your .babelrc. This Github issue has a lot of solutions unexpected token (rest spread operator). I am trying these out now.
{
"presets": ["react", "es2015"],
"plugins": ["transform-es2015-destructuring", "transform-object-rest-spread"]
}
npm install --save-dev babel-plugin-transform-es2015-destructuring
npm install --save-dev babel-plugin-transform-object-rest-spread

Using async/await in Node 6 with Babel

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

How to stop babel from transpiling 'this' to 'undefined' (and inserting "use strict")

EDIT: This is not about fat arrows. It's also not about passing this to an IIFE. It's a transpiler-related question.
So I've created a simple pub-sub for a little app I'm working on. I wrote it in ES6 to use spread/rest and save some headaches. I set it up with npm and gulp to transpile it but it's driving me crazy.
I made it a browser library but realized it could be used anywhere so I decided to make it Commonjs and AMD compatible.
Here's a trimmed down version of my code:
(function(root, factory) {
if(typeof define === 'function' && define.amd) {
define([], function() {
return (root.simplePubSub = factory())
});
} else if(typeof module === 'object' && module.exports) {
module.exports = (root.simplePubSub = factory())
} else {
root.simplePubSub = root.SPS = factory()
}
}(this, function() {
// return SimplePubSub
});
But no matter what I try (such as making this a variable and passing it) it sets it to undefined.
}(undefined, function() {
It probably has something to do with Babel not knowing what this will be and transpiling it away but is there any other approach I can take?
UPDATE: Passing }((window || module || {}), function() { instead of this seems to work. I'm not sure this is the best approach though.
For Babel >= 7.x
ES6 code has two processing modes:
"script" - When you load a file via a <script>, or any other standard ES5 way of loading a file
"module" - When a file is processed as an ES6 module
In Babel 7.x, files are parsed as "module" by default. The thing that is causing you trouble is that in an ES6 module, this is undefined, whereas in the "script" case, this varies depending on the environment, like window in a browser script or exports in CommonJS code. Similarly, "module" files are automatically strict, so Babel will insert "use strict";.
In Babel 7, you'll need to tell Babel what type your file is if you want to avoid this behavior. The simplest option would be to use the "sourceType" option to set sourceType: "unambiguous" in your Babel options, which essentially tells Babel to guess the type (scripts vs module), based on the presence of import and export statements. The primary downside there being that it's technically fine to have an ES6 module that doesn't use import or export, and those would be incorrectly treated as scripts. On the other hand, that's really not that common.
Alternatively, you can use Babel 7's "overrides" option to set specific files as scripts, e.g.
overrides: [{
test: "./vendor/something.umd.js",
sourceType: "script",
}],
Either approach allows Babel to know that some files are script types, and thus shouldn't have this converted to undefined.
For Babel < 7.x
ES6 code has two processing modes:
"script" - When you load a file via a <script>, or any other standard ES5 way of loading a file
"module" - When a file is processed as an ES6 module
When using Babel 6 and babel-preset-es2015 (or Babel 5), Babel by default assumes that files it processes are ES6 modules. The thing that is causing you trouble is that in an ES6 module, this is undefined and files are all strict, whereas in the "script" case, this varies depending on the environment, like window in a browser script or exports in CommonJS code.
If you are using Babel, the easiest option is to write your code without the UMD wrapper, and then bundle your file using something like Browserify to automatically add the UMD wrapper for you. Babel also provides a babel-plugin-transform-es2015-modules-umd. Both are geared toward simplicity, so if you want a customized UMD approach, they may not be for you.
Alternatively, you would need to explicitly list all of the Babel plugins in babel-preset-es2015, making sure to exclude the module-processing babel-plugin-transform-es2015-modules-commonjs plugin. Note, this will also stop the automatic addition of use strict since that is part of the ES6 spec too, you may want to add back babel-plugin-transform-strict-mode to keep your code strict automatically.
As of babel-core#6.13 presets are able to take options, so you can also do
{
"presets": [
[ "es2015", { "modules": false } ]
]
}
in your Babel config (.babelrc) to use babel-preset-es2015 with module processing disabled.
The "es2015" preset wraps the Babel output in a commonJs wrapper by default. Use the "babel-preset-es2015-script" (you must npm install --save babel-preset-es2015-script first) to output for "script" (no modules). This was wreaking havoc on other libraries I was wrapping up using Babel.
The preset: https://www.npmjs.com/package/babel-preset-es2015-script

How do I install the babel-polyfill library?

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';

Categories

Resources