I'm using Webpack with my Vuejs app.
I can't get my app to load on IE 11. This is what the console looks like:
The console states SCRIPT1010: Expected identifier
webpack.config.js
{
test: /\.(es6|js|mjs)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
.babelrc
{
"presets": [
[
"#babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": 3,
"modules": false,
"debug": true
}
]
]
}
.browerslistrc
> 0.25%
not ie <= 10
main.js
import "core-js/stable";
According to the stacktrace, the error is thrown by the "async" library you’re using. Having a look at the docs (https://caolan.github.io/async/v3/), it says:
Async should work in any ES2015 environment (Node 6+ and all modern browsers).
If you want to use Async in an older environment, (e.g. Node 4, IE11) you will have to transpile.
Because async cromes from node_modules and your Webpack loader config explicitely exclude it, async is not transpiled. To make it so, you can change your exclude rule like this:
exclude: /node_modules\/(?!async)/,
But this might not fix the overall IE11 compatibility if you have other incompatible libraries. You can adapt the rule to add as many packages as you need to be transpiled like this:
exclude: /node_modules\/(?!async|library2|library3)/,
Related
I'm using svelte with Rollup. And I need to support IE11
My current babel config in rollup.config.js is:
babel({
extensions: [ '.js', '.mjs', '.html', '.svelte' ],
exclude: 'node_modules/**',
presets: [
[
'#babel/env',
{
modules: 'false',
targets: {
browsers: '> 1%, IE 11, not op_mini all, not dead',
node: 8
},
useBuiltIns: 'usage'
}
]
]
}),
Please help me with configuring, now my app breaks both at IE and others(Chrome,Mozilla).
You can use the configuration for the Babel plugin that is used in Sapper as a reference:
babel({
extensions: ['.js', '.mjs', '.html', '.svelte'],
runtimeHelpers: true,
exclude: ['node_modules/#babel/**'], // <= /!\ NOT 'node_mobules/**'
presets: [
['#babel/preset-env', {
// adapter to ensure IE 11 support
targets: '> 0.25%, not dead, IE 11'
}]
],
plugins: [
'#babel/plugin-syntax-dynamic-import',
['#babel/plugin-transform-runtime', {
useESModules: true
}]
]
}),
The important thing to note is that you can't exclude your whole node_modules from processing by Babel. The reason is that Svelte's code itself (i.e. under node_modules/svelte) needs to be transpiled for IE 11 support. Similarly, if you use third-party Svelte components, they will probably live under node_modules, yet require transpilation.
Another tricky bit to know is that transpiled code cannot be compatible with non transpiled code. In particular, ES6+ classes (that are used for Svelte components) are not compatible with their ES5 transpiled counterparts ("can't extend from non class, yada yada..."). So you will have to make sure that all your Svelte code is either transpiled with the same rules, or not transpiled at all...
Here's another example that uses (almost) the same config in a raw Svelte (i.e. non-Sapper) project.
Both links point to template projects, so you can easily clone & run them to try it for yourself. (If you want to use the second example, please notice that my link does not point to the master branch, so you'll have to checkout the right branch to try the babel config.)
I need Babel not just for the web-app (build by Webpack) but also for nodejs automation utilities like gulp. In the general case, babel settings for web application and nodejs must not be same. The question is how to separate it.
I have not tested yet, but I suppose we could define settings for the nodejs in .babelrc and settings for the web application directly in webpack configuration like:
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader?blacklist[]=regenerator',
options: {
presets: [
['env', {'modules': false}]
],
plugins: [
'syntax-dynamic-import',
'transform-runtime'
]
}
},
'eslint-loader'
]
}
]
}
};
The question is which config webpack will give higher priority: .babelrc or webpack loader options (second one desired).
Answer for babel 7 (latest)
First make sure you have #babel/core, #babel/preset-env installed (follow install babel 7 tutorials).
Instead of .babelrc use .babel.config.js in your project root directory.
Because babel.config.js (contrary to package.json) is just javascript file, you can now use conditionals.
You can now for example set the environment variable BABEL_ENV which will be available in node as a property of the global process variable under process.env.BABEL_ENV (webpack is also run in node environment).
For example call BABEL_ENV=browser npx webpack and also call BABEL_ENV=node some_other_command. Now you can access process.env.BABEL_ENV and use logic like:
babel.config.js
module.exports = function () {
const isBrowser = process.env.BABEL_ENV === 'browser';
const presets = ['shared_preset_1', 'shared_preset_2'];
const plugins = ['shared_plugin_1', 'shared_plugin_2'];
if (isBrowser) {
plugins.push('YOUR PLUGIN');
}
if (!isBrowser) {
// other logic
}
}
As for babel 6: I'd say just try it out. If you google for that issue though, you will find a lot of confusion because babel-loader, that decides which babel config is used, has never documented it. Apparently there's an undocumented feature: { babelrc: false } that prioritizes webpack set configs, but if you look it up: it's very vague!
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
I got a problem with transpiling imported modules from node_modules. Babel for some reason doesn't transpile imported module from node_modules, but transpile modules imported from src.
Here is an example repo: https://github.com/NikitaKA/babeltest
main.js
// result code contains const and let, but it shouldn't. :(
index.js
import qs from 'query-string; // not transpiled
import lib from './lib' // transpiled
const query = qs.parse(window.location.search);
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js'
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: "babel-loader"
}
}
]
}
};
.babelrc
{
"presets": [
["#babel/preset-env", {
"modules": false,
"targets": {
"chrome": 39
}
}],
["#babel/preset-stage-1", {
"modules": false,
"decoratorsLegacy": true,
"pipelineProposal": "minimal"
}]
],
"plugins": [
"transform-es2015-constants",
"#babel/plugin-transform-block-scoping",
"#babel/plugin-transform-runtime"
]
}
The solution in this case is to transpile the module again, this can be done by modifying the exclude property in your webpack config:
{
test: /\.js$/,
exclude: /node_modules\/(?!(es6-module|another-es6-module)\/).*/,
},
Modules es6-module and another-es6-module will no longer be ignored by webpack and will be transpiled with the rest of your source code.
See the GitHub issue on the webpack project.
Tested with webpack#3.12.0, babel-core#6.26.3 and babel-core#6.26.3
To expand upon my comments:
You really don't want to transpile all of node_modules – it'll take a long time, and most of the code there should already be ES5 (unless they're actually ES6 modules, in which case the ES6 entry point is announced as "module" in the package.json manifest).
query-string#6.x isn't, and it says so in its README:
This module targets Node.js 6 or later and the latest version of Chrome, Firefox, and Safari. If you want support for older browsers, use version 5: npm install query-string#5.
If you're using Vue, there is a simple solution. Just list your module in transpileDependencies:
vue.config.js
module.exports = {
publicPath: '',
outputDir: 'www',
transpileDependencies: [
'query-string'
],
}
I have the following set up:
And I am trying to do the following:
case 'UPDATE_PASSWORD':
return {
...state, //preserve current state, apply changes to it below
password: action.password,
};
but I am getting:
Unexpected token (5:8) at where '...' starts
What may be the issue? How do I check if I am using ES6?
This is a proposed ECMAScript feature (object spread) and can be enabled by adding stage-0 to your babel presets:
npm install --save-dev babel-preset-stage-0
Then, in your .babelrc or within your webpack.config.js query add the preset to your babel settings. Example .babelrc:
{
"presets": [
"es2015",
"react",
"stage-0"
]
}
Or, if you make use of the webpack babel-loader query string:
{
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react', 'stage-0']
}
}
EDIT
Babel presets are an assortment of many transformations. As per zerkms' suggestion, you could use stage-2, which does not include/transpile many other features you may not be using at this time. If you really just want the object spread to work, you can also just install transform object rest spread.