Babel Transform Runtime issue with Webpack 2 - javascript

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

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".

No loaders configured for node_modules | webpack + babel

I am trying to load a JSX Component from a module declared as a devDependency in my project. However, upon running webpack, I get the below error:
Module parse failed: Unexpected token (70:20)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.
|
| render(
> <Provider store={store}>
| <MyApp />
| </Provider>,
# ./src/App.js 48:43-96
# ./src/index.js
I am using webpack 4 and babel 7.
webpack dependencies:
"devDependencies": {
"#babel/core": "^7.9.6",
"#babel/preset-env": "^7.9.6",
"#babel/preset-react": "^7.9.4",
"dummy-pkg": "file:../dummy-pkg",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^8.2.3",
"babel-loader": "^7.1.2",
"sass-loader": "^8.0.0",
"style-loader": "^0.16.1",
"uglifyjs-webpack-plugin": "^2.2.0",
"webpack": "^4.40.2",
"webpack-cli": "^3.3.10"
}
webpack config:
module: {
rules: [
{
test: /\.jsx?$/,
include: [path.resolve(__dirname, './src'), /node_modules\/dummy-pkg/],
use: 'babel-loader'
},
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
}
]
}
babelrc
{
"presets": ["#babel/preset-react", "#babel/preset-env"]
}
When I try to import the Component from dummy-pkg, it fails with the error message that I have mentioned above.
If I remove the import, all the other JSX components that have been declared within my current project are transpiled correctly. Introducing this causes all the problems.
I have been looking at a lot of other questions on Stack Overflow as well as some GitHub issues. The solutions suggested there do not seem to work out for me.
Any help would be really appreciated.
TIA!
UPDATE
After some more debugging, I found that you need to define the babel config in babel.config.json
More info available here. Other File types are listed here
Surprisingly what I have noticed is that when you are providing the presets in .babelrc it's not working if there's anything that you want exclude from node_modules but when I placed the presets in my webpack.config it worked like gem. So I would suggest to try keeping the rule for js or jsx like below and test
{
test: /\.(js|jsx)$/,
exclude: [/node_modules\/dummy-pkg/],
use: {
loader: "babel-loader",
options: {
presets: ["#babel/preset-env", "#babel/preset-react"],
plugins: [
"#babel/plugin-proposal-class-properties"
]
}
}
}
Hope this helps.

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

babel-preset-env not transpiling arrow functions using webpack

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.

Error: Uncaught ReferenceError: React is not defined

Overview
I am trying to use Babel and Webpack to build a React app. I know I could use create-react-app but I'd like to learn how these technologies can work together for myself.
When I run yarn run start or yarn run build (see package.json below), Webpack reports to have built the bundle fine. When I run the application in the browser, I get the Uncaught ReferenceError: React is not defined error.
There are a number of questions on SO regarding this same error, but none of the solutions have solved my problem yet.
Question
What piece am I missing to get React, Babel, and Webpack to play together nicely?
Code
package.json
{
"private": true,
"scripts": {
"build": "webpack",
"start": "webpack-dev-server"
},
"dependencies": {
"react": "^15.4.1",
"react-dom": "^15.4.1",
"react-redux": "^5.0.1",
"redux": "^3.6.0"
},
"devDependencies": {
"babel-core": "^6.21.0",
"babel-loader": "^6.2.10",
"babel-preset-es2015": "^6.18.0",
"babel-preset-react": "^6.16.0",
"redux-devtools": "^3.3.1",
"webpack": "^1.14.0",
"webpack-dev-server": "^1.16.2"
}
}
.babelrc
{
"presets": ["react", "es2015"]
}
webpack.config.js
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: './dist'
},
devtool: 'source-map',
debug: true,
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}
]
}
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
<div id="root"></div>
<script src="dist/bundle.js"></script>
</body>
</html>
src/index.js
import ReactDom from 'react-dom';
import React from 'react';
import App from './App';
ReactDom.render(
<App />,
document.getElementById('root'),
);
src/App.js
import React from 'react';
import { Component } from 'react';
export default class App extends Component {
render() {
return (
<h1>hello</h1>
);
}
}
Observations
It seems that Webpack/Babel is expecting React to be available on the global scope, or is ignoring my import React from 'react'; statements.
Also, I have yet to find the proper incantation of devtools and debug properties in my Webpack config to actually get source maps working. I don't yet see them in the compiled output.
EDIT
The broken bundle.js is too large for SO (21,000+ lines), so here is a link: http://chopapp.com/#1a8udqpj — it takes several seconds to load and display.
Since you're trying to learn the in's and out's of webpack et al... Your original problem was that you needed to specify the output.publicPath in your webpack.config.js:
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: './dist',
publicPath: '/dist' // <- was missing
},
devtool: 'source-map',
debug: true,
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}
]
}
}
"path" is the physical path to the folder that contains your bundle.js. "publicPath" is the virtual path (URL) to that folder. So, you don't even have to use "dist". For example, if you used...
output: {
filename: 'bundle.js',
path: './dist',
publicPath: '/assets'
},
Your HTML would then point to:
<script src="assets/bundle.js"></script>
I wish to make the following observations. First to your question regarding devTools and debug. The debug flag for webpack (according to their official documentation) switches the loaders to debug mode. Then, from what I understand, webpack, when running in a dev environment, does not actually compile the code to hard files, but keeps it in memory. Thus the source maps are also kept in memory and linked to the browser. You see their effect when you open the browser dev tools and view source.
Now assuming you have the dev server configured correctly, I also assume your index.html is located in your source directory. If this is the case, then your script reference should simply point to '/bundle.js' and not 'dist/bundle.js' since there may not be a physical "dist" folder.
I would also suggest dropping the ".js" from your entry point in the webpack.config.js
You will need to add a query to your module within the webpack.config.js file:
module: {
loaders: [{
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['react', 'es2015']
}
}]
},
resolve: {
extensions: ['', '.js', '.jsx']
};

Categories