babel-preset-env not transpiling arrow functions using webpack - javascript

I'm using babel with webpack, I'm trying to make arrow functions work with Internet Explorer, but I can't get it working.
This is my package.json dev dependencies:
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^7.1.5",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-preset-env": "^1.7.0",
"webpack": "^3.12.0",
"webpack-cli": "^3.1.0"
}
and this is my webpack.config.js:
module.exports = {
entry: ['./chat.js'],
devtool: 'source-map',
output: {
path: path.resolve(__dirname, "dist"),
filename: "chat.js"
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
}
]
}
};
I'm using the plugins with .babelrc:
{
"presets": ["env"],
"plugins": ["transform-class-properties"]
}
I don't know what I'm doing wrong or if I'm missing something but I get the following syntax error on Internet Explorer:
DF.fn = () => {
// Content
};

If you are using Babel 7, the behaviour of .babelrc has changed.
My advice is to drop .babelrc and put the config inside your webpack config.
Additionally you will need to either remove exclude: /node_modules/ from your config config, or add in some conditions for not excluding any libraries that use browser incompatible code (eg, arrow functions if you want to use IE).
Personally I removed the exclude altogether and noticed no degredation in speed or size.

For those using Webpack 5, you need to specify the features that you want to transpile in the ouput.environment configuration, as explained here: https://webpack.js.org/configuration/output/#outputenvironment.
I am using differential serving so I have set all the flags according to a modern variable (which is set to true only if building for recent browsers, which is the last 5 versions of Chrome and Firefox and the last 2 versions of Safari, Edge and iOS).
output: {
// ... other configs
environment: {
arrowFunction: modern,
bigIntLiteral: modern,
const: modern,
destructuring: modern,
dynamicImport: modern,
forOf: modern,
module: modern,
},
}

You have to specify the target browsers for your build. Based on that babel-preset-env decides which transforms need to be applied. Here's docs and example of config
{
"presets": [
["env", {
"targets": {
"browsers": ["last 2 versions", "safari >= 7"]
}
}]
]
}
And here are all possible ways to specify the browsers set.

Related

Why isn't my Mutex class being transpiled by Webpack?

I'm having an issue with upgrading from Webpack 4 to Webpack 5, where Babel no longer seems to transpile code from one of my dependencies (async-mutex). I managed to strip it down to a minimal setup that demonstrates the problem:
package.json
{
"scripts": {
"build": "webpack --mode=production"
},
"devDependencies": {
"#babel/core": "~7.12.0",
"#babel/preset-env": "~7.12.0",
"async-mutex": "~0.2.0",
"babel-loader": "~8.2.0",
"webpack": "~5.10.0",
"webpack-cli": "~4.2.0"
},
"babel": {
"presets": [
"#babel/preset-env"
]
},
"browserslist": [
"Explorer >= 11"
]
}
webpack.config.js
module.exports = {
entry: {
bundle: './index.js',
},
module: {
rules: [
{
test: /\.m?js$/,
use: 'babel-loader',
},
],
},
};
index.js
import {Mutex} from 'async-mutex';
console.log(Mutex);
class MyClass {}
console.log(MyClass);
As per my browserslist, I need to support IE 11. After building this and inspecting the resulting dist/bundle.js I can see that the class MyClass was transpiled into a function, but the class Mutex was not transpiled, which obviously causes IE 11 to fail with a syntax error. It's as if Babel is using different settings to process the async-mutex package than it uses to process my index.js.
I found another question with an answer that suggests adding target: ['web', 'es5'], but that doesn't help and it also seems unnecessary, since Webpack is supposed to honor browserslist.
With Webpack 4 I did not have this issue, but I'm not sure if the problem is with my setup, with Webpack, with Babel or even with async-mutex.
Note aside: I'm aware that this minimal setup is lacking a Promise polyfill, but I omit it here because it seems irrelevant to the issue.
Babel configuration within package.json only applies within your specific package, not node_modules, so even though Babel is set up to process all files in your bundle, it's only been configured to perform transformations on your own package's files. See the Babel config file docs.
You need to create a babel.config.json instead, or you need to put the config directly into the Webpack config, so either
babel.config.json:
{
"presets": [
"#babel/preset-env"
]
}
OR
webpack.config.js:
module.exports = {
entry: {
bundle: './index.js',
},
module: {
rules: [
{
test: /\.m?js$/,
use: 'babel-loader',
options: {
"presets": [
"#babel/preset-env"
]
}
},
],
},
};
You'll need to include async-mutex in your webpack.config.js's module rule for babel. Once in awhile you'll come across a package that doesn't transform its ES6. Funny enough, the best way to include it in your transpilation is using exclude, like this:
module.exports = {
entry: {
bundle: './index.js',
},
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules\/(?!(async-mutex)\/).*/,
use: 'babel-loader',
},
],
},
};
This exclude rule says, "exclude all node_modules but async-mutex".

How to configure webpack + babel for ie11?

Babel configs:
"babel": {
"presets": [
[
"#babel/env",
{
"targets": {
"ie": "9"
},
"useBuiltIns": "usage",
"corejs": 3
}
]
]},
Node Modules:
"devDependencies": {
"#babel/core": "^7.9",
"#babel/preset-env": "^7.9",
"babel-loader": "^8",
"core-js": "^3",
"regenerator": "^0.14"
"webpack": "^4.40",
"webpack-cli": "^3.3"},
Webpack configs
{
test: /\.js$/,
exclude: /node_modules\/(?!(dom7|ssr-window|swiper)\/).*/,
loader: 'babel-loader'
},
In Internet Explorer 11, I get an error "Object doesn't support property or method 'closest'"
You've configured webpack and #babel/preset-env correctly here, but unfortunately, core-js, which #babel/preset-env relies on for all of it's polyfills doesn't polyfill any Browser APIs, which Element.closest() is. It only polyfills JavaScript.
The difference between Browser/Web APIs and JavaScript is very nuanced - it includes anything which you access from a Node/Element and any Web APIs listed here
If you would like to polyfill Element.closest, you'll have to include the polyfill separately - element-closest seems popular!

JavaScript - babel-preset-env not transpiling arrow functions for IE11

I'm having a hard time trying to configure Babel to transpile code that IE11 can understand, specifically arrow functions. Running npx webpack --mode=development with my configuration doesn't convert the arrow functions in my code: in the eval() statement in the generated code, I can see that all the instances have gone unconverted.
Unlike in the console output quoted in this question, there's no mention in mine of "Using targets" or "Using presets". Whether that's something to do with using npx webpack rather than npm run build I don't know.
Here's the Babel part of my package.json:
{
// name, version etc. snipped
"devDependencies": {
"#babel/core": "^7.1.2",
"#babel/plugin-transform-async-to-generator": "^7.1.0",
"#babel/plugin-transform-es2015-arrow-functions": "^6.22.0",
"#babel/plugin-transform-es2015-modules-commonjs": "^6.26.2",
"#babel/preset-env": "^7.1.0",
"ajv": "^6.5.4",
"copy-webpack-plugin": "^4.5.2",
"eslint-plugin-jest": "^21.24.1",
"jest": "^23.6.0",
"jest-dom": "^2.0.4",
"webpack": "^4.20.2",
"webpack-cli": "^3.1.2"
},
"babel": {
"presets": [
[
"#babel/preset-env",
{
"targets": {
"ie": "11"
}
}
]
],
"env": {
"development": {
"plugins": [
"transform-es2015-arrow-functions",
"transform-es2015-modules-commonjs"
]
},
"test": {
"plugins": [
"transform-es2015-arrow-functions",
"transform-es2015-modules-commonjs"
]
}
}
}
}
My webpack.config.js looks like:
const CopyWebpackPlugin = require("copy-webpack-plugin");
const path = require("path");
module.exports = {
entry: "./src/thing.js",
optimization: {
minimize: false
},
output: {
filename: "thing.js",
path: path.resolve(__dirname, "dist")
},
plugins: [
new CopyWebpackPlugin([
// snipped
])
]
};
I arrived at this point from reading other questions here about Babel configurations, and the babel-preset-env docs and also the very skimpy babel-plugin-transform-es2015-arrow-functions docs. The answers to this very similar question (no accepted answer) don't mention that plugin at all, and one suggests using a polyfill, which seems to involve loading a library in your actual code rather than at this stage?
I'm very new to working with Webpack in general and don't understand what the difference is between "env" (which gets mentioned in a lot of questions) and "#babel/preset-env". Or really what the former implies in general; if you click on "env" in the docs navigation, it takes you to the page for #babel/preset-env.
What am I doing wrong?
If you are using Webpack 5, you need to specify the features that you want to transpile in the ouput.environment configuration, as explained here: https://webpack.js.org/configuration/output/#outputenvironment.
output: {
// ... other configs
environment: {
arrowFunction: false,
bigIntLiteral: false,
const: false,
destructuring: false,
dynamicImport: false,
forOf: false,
module: false,
},
}
EDIT 08/10/22
While doing some refactoring of my webpack configuration, I figured out that the arrows had stopped transpiling (or maybe I didn't test extensively when giving the original answer).
Two things weren't setup correctly: the target key was missing, and the babel configuration had a wrong value.
For supporting legacy browsers, the target key needs to be set like this:
target: ['web', 'es5']
While in the Babel configuration, I had added 'not dead' in the browserslist configuration under targets in the Babel loader, so since IE11 is now technically dead, this configuration removed the trasnpilation of the arrow function.
So if you still need to transpile the arrow function, this would be the relevant part in the Babel configuration.
module: {
rules: [
{
test: /\.m?js$/,
use: {
loader: 'babel-loader',
options: {
presets: [
[
'#babel/preset-env',
{
useBuiltIns: 'entry',
targets: {
// be sure not to add 'not dead' here
browsers: ['> 1%', 'last 2 versions', 'Firefox ESR']
},
corejs: {
version: 3,
proposals: false,
},
},
],
],
plugins: [['#babel/plugin-transform-runtime', { corejs: 3 }]],
},
},
},
],
},
In addition to loganfsmyth's answer that solved the problem, I want to note for any other beginners reading this that I made life easier for myself afterward by moving the Babel configuration out of package.json into a .babelrc.
I also discovered that the plugins I needed, such as the one I mentioned above, babel-plugin-transform-es2015-arrow-functions, have newer versions with a different naming scheme - for that example, #babel/plugin-transform-arrow-functions. The documentation pages for the old versions don't mention that.
The module part of my webpack.config.js now looks like:
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
}
My .babelrc looks like:
{
"presets": [
[
"#babel/preset-env",
{
"targets": {
"ie": "11"
},
"useBuiltIns": "entry"
}
]
],
"plugins": [
"#babel/transform-async-to-generator",
"#babel/transform-arrow-functions",
"#babel/transform-modules-commonjs"
],
"env": {
"development": {},
"test": {},
"production": {}
}
}
Update 2021: As of Webpack version 5, it outputs ES6 code by default. If you need that not to happen, you need to add a configuration setting. See Giorgio Tempesta's answer.
Babel itself is a transformation library, but on its own it will not integrate into any specific tooling. To use Babel with Webpack, you'll want to install the babel-loader package and configure it in your Webpack config using something along the lines of
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
}
}
]
}
I had the same problem. Turned out it wasn't all of my code that had arrow functions, but only one single library. I went inside my built bundle, and searched for code with arrow functions (=>). Then I searched and copied some unique-looking names around it and managed to find the source of it searching for it in all files within node_modules. In my case it turned out that the code with arrow functions came from fetch polyfill called unfetch. I'm not sure why it didn't get transpiled by the plugin, but I switched it to "whatwg-fetch" and it worked just fine - no arrow functions in bundle anymore. You could try the same technique to discover what causes it in your case.
2022 Update
If you have this problem now, it could be because browerslist treats IE 11 as dead since version 4.21.0. The solution to access IE 11 anyway is to add ie 11 either as the last entry in browserslist or at least after not dead.
Normally you don't see browserslist in the package.json, but if you use npm ls browserslist you can see which dependency uses browserslist and which version of it.
See also: https://github.com/browserslist/browserslist/issues/699

fetch and Headers are undefined in IE11.0.9600 with babel-polyfill when process.env.NODE_ENV=='production'

When process.env.NODE_ENV=='development' - it is OK!
But our production build failed in IE 11 (11.0.9600).
All work fine in chrome 55.
devDependencies:
...
babel-core: "6.22.0",
babel-eslint: "^7.0.0",
babel-loader: "^6.2.5",
babel-preset-env: "^1.5.2",
babel-preset-es2015: "^6.16.0",
babel-preset-es2016: "^6.22.0",
babel-preset-es2017: "^6.16.0",
babel-preset-react: "^6.16.0",
babel-preset-stage-0: "^6.22.0"
...
dependencies:
...
babel-polyfill: "^6.16.0"
...
.babelrc:
{
"presets": [
"react",
["env", {
"useBuiltIns": true
}],
"stage-0"
]
}
Try "useBuiltIns": false, es2016, es2015, es2017 presets. Nothing changes.
index.js:
"use strict";
import 'babel-polyfill'
...
webpack.config module.exports.entry:
vendor: ['babel-polyfill', 'immutable', 'react', 'react-dom', ...],
...
bundle: [path.resolve(__dirname, srcPath + ""index.js)]
vendor is the first script in index.html.
Typing _babelPolyfill in ie console return true.
But Headers, fetch are undefined...
Why process.env.NODE_ENV=='production' broke my app in IE11?
How to fix my config?
core.js do not have polyfill for Headers() and fetch, so babel-polyfill don't.
Use one of fetch polyfills:
whatwg-fetch polyfill for browsers only support https://github.com/github/fetch
isomorphic-fetch - polyfill, based on whatwg-fetch, for node and browsers support
For more info:
https://github.com/zloirock/core-js
What is the difference between isomorphic-fetch and fetch?

Babel Transform Runtime issue with Webpack 2

Good afternoon,
This is the same issue I reported at webpack's github, but I suspect I might be the one doing something wrong, thus opening a question here.
I'm trying to configure webpack 2 with Babel, and one of the requirements is to transpile built-ins such as Symbol.
Despite that now working fine, when I try to use webpack and babel's transform-runtime, I'm unable to use exports *.
Input file (src/index.js):
export * from './secondFile'
secondFile.js:
export let TESTSYMBOL = Symbol('test');
export let TESTSYMBOL2 = Symbol('test2');
webpack.config.js (only copied the relevant part):
module: {
rules: [
{
test: /\.jsx?$/,
// Skip any files outside of `src` directory
include:path.resolve(__dirname, 'src'),
use: {
loader: 'babel-loader',
options: {
presets: ["es2015", "stage-3"],
plugins: ['transform-runtime']
}
}
}
]
}
script:
"webpack -d --config config/webpack.config.js"
Output file: gist
Exception:
Uncaught ReferenceError: exports is not defined - at Object.defineProperty(exports, "__esModule", {
Dev Dependencies:
"webpack": "2.6.1",
"webpack-dev-server": "2.4.5",
"webpack-notifier": "1.5.0"
"babel-cli": "6.24.1",
"babel-loader": "7.0.0",
"babel-plugin-transform-runtime": "6.23.0",
"babel-preset-es2015": "6.24.1",
"babel-preset-stage-3": "6.24.1"
Dependencies:
- "babel-runtime": "6.23.0"
Thanks for any help!
It seems that the problem is with the include. For some reason, I was unable to use path.resolve or path.join. The webpack documentation has such example.
If the webconfig is as follows, it works just fine:
module: {
rules: [
{
test: /\.js$/,
include: [
/src/
],
// or exclude: [/node_modules/],
use:
{
loader: 'babel-loader',
options: {
plugins: ['transform-runtime'],
presets: ['es2015', 'stage-3']
}
}
}
]
}
Either way, now there's a problem with exports not defined, which can be solved by setting modules to false in es2015 preset (thanks to Vanuan at Github for that suggestion):
presets: [['es2015', { modules: false }], 'stage-3'],
For IE or older browsers, I need to use es-shims - libraries which ports the ECMAScript specs to legacy JS engines.
These libs below may resolve your problem if added as the first imports on your index.html (or equivalent). Here's one for example:
<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.7/es5-shim.min.js"></script>
See this link for every lib you may need:
ES-Shims

Categories