Babel does not transpile imported modules from 'node_modules' - javascript

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'
],
}

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

Webpack generated library has problem being imported by project where useBuiltIns is set to 'usage'

I want to write a reusable UI component library and pack it with Webpack. However, when I import it in another project, where the babelrc has useBuiltIns: 'usage' set, the import will fail with an error:
"export 'default' (imported as 'Component') was not found in 'component'
This is part of my webpack configuration in library project:
output: {
path: path.resolve(process.cwd(), './dist'),
filename: 'component.js',
chunkFilename: '[id].js',
library: 'Component',
libraryTarget: 'commonjs2',
libraryExport: 'default'
},
...
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
Babel configuration in library project:
module.exports = {
presets: [
[
"env",
{
modules: false,
targets: {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}
],
"stage-2"
]
}
Babel configuration in the consuming project:
module.exports = {
presets: [
'#vue/app'
]
}
Where the useBuiltIns: 'usage' is implicitly set.
While the problem could be solve by either set useBuiltIns: false or scriptType: 'unambiguous' in the consuming project. But this is not what I want. Since my goal is to provide a reusable library and it is expected to be used in different projects. I cannot force all the consuming projects to do this.
Am I missing something here?
I've found the answer in the Vue.js forum: https://forum.vuejs.org/t/export-default-imported-as-components-was-not-found-in-mylib/63905
The problem was that I was adding the dependency with a local path, namely:
$ npm install ../component
And in this case, npm is creating a symlink in node_modules. It seems that some babel plugin doesn't really like symlinks.
After I've changed to use git:
$ npm install git+file://localhost/path/to/component
Everything works fine.

Can't import npm modules in commonjs with rollup : "require is not defined"

I work on an ES6 project that I transpile using rollup and babel. It works well except when I try to import npm modules that use commonjs (and particularly require('something')) getting an error "require is not defined" in my browser (which means it hasn't properly compiled node modules from commonjs to ES5). However, I use rollup-plugin-node-resolve and rollup-plugin-commonjs, that should do that job if I've understood properly...
Here are my rollup config file:
import babel from 'rollup-plugin-babel';
import eslint from 'rollup-plugin-eslint';
import resolve from 'rollup-plugin-node-resolve'; // to import node_modules packages easily
import commonjs from 'rollup-plugin-commonjs'; // convert commonjs to es6 (in case you use require)
export default {
input: 'src/main.js',
output: {
file:'build/index.js',
format: 'iife'
},
sourcemap: 'inline',
plugins: [
resolve({
jsnext: true,
main: true,
browser: true
}),
commonjs({
include: 'src/**'
}),
eslint({
exclude: [
'src/styles/**',
]
}),
babel({
exclude: 'node_modules/**',
})
],
};
and my babel config file:
{
"presets": [
[
"es2015",
{
"modules": false
}
]
],
"plugins": ["external-helpers"]
}
Examples of modules that I can't load are math.js, nsolvejs, chroma.js, data.gui, etc.
The issue is probably with commonjs plugin, it is used to transform cjs into es modules at build time, therefore you should include the cjs modules from node_modules instead of src.
commonjs({
include: 'node_modules/**'
})

Making a library importable using webpack and babel

I am trying to publish a package on npm (this one) that I am developing using webpack and babel. My code is written in ES6. I have a file in my sources, index.js, that (for the moment) exports one of my library's core components, it simply goes like this:
import TheGamesDb from './scrapers/thegamesdb';
export { TheGamesDb };
I am using webpack and babel to create a dist index.js that is my package's main file. My webpack.config.js goes like this:
const webpack = require('webpack');
const nodeExternals = require('webpack-node-externals');
module.exports = {
entry: {
index: ['babel-polyfill', './src/index.js'],
development: ['babel-polyfill', './src/development.js']
},
output: {
path: '.',
filename: '[name].js',
library: 'rom-scraper',
libraryTarget: 'umd',
umdNamedDefine: true
},
devtool: 'source-map',
module: {
loaders: [
{ test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }
]
},
target: 'node',
externals: [nodeExternals()]
};
Now when I load my package in another project and try to import my export TheGamesDb simply like this
import { TheGamesDb } from 'rom-scraper';
I get the error
Uncaught TypeError: Path must be a string. Received undefined
It is to be noted that I am importing my library in electron.
Update: Electron seems to be the main problem here and it is not even my library but a dependency that throws this error (only in Electron)
The problem wasn't any of the things in my question but node-expat not working in electron. I switched to an alternative library and it's all right now.

Webpack throws syntax error for JSX

When I attempted to use webpack to compile my react jsx code, I received the following error:
ERROR in ./client/index.js
Module parse failed: C:\Users\Gum-Joe\Documents\Projects\bedel/client\index.js Unexpected token (6:11)
You may need an appropriate loader to handle this file type.
SyntaxError: Unexpected token (6:11)
at Parser.pp.raise (C:\Users\Gum-Joe\Documents\Projects\bedel\node_modules\acorn\dist\acorn.js:920:13)
at Parser.pp.unexpected (C:\Users\Gum-Joe\Documents\Projects\bedel\node_modules\acorn\dist\acorn.js:1483:8)
at Parser.pp.parseExprAtom (C:\Users\Gum-Joe\Documents\Projects\bedel\node_modules\acorn\dist\acorn.js:330:12)
at Parser.pp.parseExprSubscripts (C:\Users\Gum-Joe\Documents\Projects\bedel\node_modules\acorn\dist\acorn.js:225:19)
at Parser.pp.parseMaybeUnary (C:\Users\Gum-Joe\Documents\Projects\bedel\node_modules\acorn\dist\acorn.js:204:17)
at Parser.pp.parseExprOps (C:\Users\Gum-Joe\Documents\Projects\bedel\node_modules\acorn\dist\acorn.js:151:19)
at Parser.pp.parseMaybeConditional (C:\Users\Gum-Joe\Documents\Projects\bedel\node_modules\acorn\dist\acorn.js:133:19)
at Parser.pp.parseMaybeAssign (C:\Users\Gum-Joe\Documents\Projects\bedel\node_modules\acorn\dist\acorn.js:110:19)
at Parser.pp.parseExpression (C:\Users\Gum-Joe\Documents\Projects\bedel\node_modules\acorn\dist\acorn.js:86:19)
at Parser.pp.parseReturnStatement (C:\Users\Gum-Joe\Documents\Projects\bedel\node_modules\acorn\dist\acorn.js:1854:26)
at Parser.pp.parseStatement (C:\Users\Gum-Joe\Documents\Projects\bedel\node_modules\acorn\dist\acorn.js:1719:19)
at Parser.pp.parseBlock (C:\Users\Gum-Joe\Documents\Projects\bedel\node_modules\acorn\dist\acorn.js:1991:21)
at Parser.pp.parseFunctionBody (C:\Users\Gum-Joe\Documents\Projects\bedel\node_modules\acorn\dist\acorn.js:607:22)
at Parser.pp.parseMethod (C:\Users\Gum-Joe\Documents\Projects\bedel\node_modules\acorn\dist\acorn.js:576:8)
at Parser.pp.parseClassMethod (C:\Users\Gum-Joe\Documents\Projects\bedel\node_modules\acorn\dist\acorn.js:2137:23)
at Parser.pp.parseClass (C:\Users\Gum-Joe\Documents\Projects\bedel\node_modules\acorn\dist\acorn.js:2122:10)
# ./client/index.js 1:0-20
.babelrc:
{
"presets": ["es2015", "react"]
}
webpack.config.js:
// Webpack config
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// Use client as our root
context: __dirname + "/client",
// Entry file
entry: "./index.js",
// Resolve
resolve: {
extensions: ['', '.js', '.jsx']
},
// Output to /build
output: {
path: path.join(__dirname, "build", "js"),
filename: "bundle.js"
},
loaders: [
{ test: /\.jsx$/, exclude: /node_modules/, loader: "babel-loader" }
],
// Plugins
plugins: [
// HTML
new HtmlWebpackPlugin({
title: 'Bedel',
filename: path.join(__dirname, 'views', 'index.ejs'),
template: path.join(__dirname, 'client', 'templates', 'index.ejs')
})
]
};
index.js:
import React from 'react';
import ReactDOM from 'react-dom';
class App extends React.Component {
render () {
return <p> Hello React</p>;
}
}
ReactDOM.render(<App/>, document.getElementById('app'));
I have installed all the babel presets required, as well as babel-core.
I have looked at the following answers already:
babel-loader jsx SyntaxError: Unexpected token
React, babel, webpack not parsing jsx code
Edit: After commenting out my jsx syntax, the outputting bundle.js does not appear to have been transformed by babel (i.e. I can see ES6 code in it)
Edit: Sorry for the inconvenience, but app.jsx was a solution that I tried that involved putting the logic that should be in index.js into a separate file.
Edit: Here is a list of the solutions I tried that did not work:
Copy .babelrc to client/.babelrc
Change test to test for .js instead of .js
Separate app logic into separate file (app.js)
Put presets to use in webpack config
Also, I have pushed my code to my GitHub repo (https://github.com/Gum-Joe/bedel). Feel free to have a look at it.
You configured the loader to only pass .jsx files through Babel:
test: /\.jsx$/
However, your file has the extension .js. Either rename the file or update the test expression to /\.jsx?$/.
In addition to updating the test, you need to rename .babel.rc to .babelrc (no . before rc). Otherwise Babel thinks that there is no configuration file and won't load any presets.
The loaders property must exist within the module property. Webpack Loaders
module.exports = {
// ...
// Output to /build
output: {
path: path.join(__dirname, "build", "js"),
filename: "bundle.js"
},
module: {
loaders: [
{ test: /\.jsx$/, exclude: /node_modules/, loader: "babel-loader" }
]
},
//...
};
You need to use react-preset with babel, like here:
loaders: [{
test: /\.(js|jsx)$/,
loader: 'babel',
query: {
presets: [
'es2015',
'react'
]
}
}]
I'm having this issue as well, and if you're using Windows and Node 6.x, the only workaround I've found for now seems to be to use Node 4 LTS or 5 instead. Without knowing the root cause, the problem seems to stem from some combination of using JSX, Webpack, Babel, Acorn JS, Node 6, and Windows.
https://github.com/coryhouse/pluralsight-redux-starter/issues/2
https://github.com/danmartinez101/babel-preset-react-hmre/issues/32
Can you try wrapping the entire element in brackets "()"?
return (<p>...</p>)

Categories