babel/babel-loader

How to handle npm modules which include es6

eoinmurray opened this issue Β· 22 comments

This is my babel-loader import in my webpack.config.js file

loaders: [
  {
    test: /\.jsx?$/,
    exclude: /node_modules/,
    loader: 'babel',
    query: {
      presets: ['react', 'es2015']
    }
  }
],

I try to run this to make minified code with webpack -p --config webpack.config.js

It works fine unless I have the module qs.js included, which uses the keyword let throughout.

The authors of qs.js recommend transpiling qs using babel ljharb/qs#141.
I achieved this in the compilation step by removing exclude: /node_modules/but I think thats messy as it babelify's every module included in my application.

Is there a more elegant way to do this, without needed to manage my own version of qs.js

Any word on this?

@eoinmurray you can exclude all node modules except qs using the following:

exclude: /node_modules\/(?!qs)/

This will let babel transpile qs without touching every other node module.

If you need to exclude more than one module you can extend the exception list like so:

exclude: /node_modules\/(?![module1|module2])/

Hope that helps :)

This is great thanks, totally solves the issue!

kyhy commented

Above second regex didn't work me. Regex for including multiple modules, that worked for me, is:

exclude: /node_modules\/(?!(module1|module2)\/).*/

thanks @jonnymbgood for the right pointers though!

@kyhy

/node_modules\/(?!(async\-es|lodash\-es)\/).*/ doesn't work for me.

/node_modules\/(?![async\-es|lodash\-es])/ works well.

It looks like perhaps this has since been fixed in qs (see ljharb/qs#141 (comment)).

But for future reference, I've created a webpack helper to automatically detect dependencies such as this one that may require Babel transpilation. See https://github.com/andersdjohnson/webpack-babel-env-deps. It should work if a module specifies engines correctly in its package.json, or module which is a transpile-eligible entry a package can specify.

I've struggled with this also and this solutions, adding the exclude negative lookahead didn't solved my problem, but 50% of it. I had to add to the include as well.. For ex.

exclude: /node_modules\/(?!(event-class-es6))/,
include: path.join(__dirname, 'node_modules', 'event-class-es6'),

we should use exclude and include to make this work

not sure if this is a feature or a bug

It's odd that the two posters above only got it working when they added both the exclude and include entries. For me it works with just the include line. (though, in my case I had to add a fs.realpathSync call, since I had my node-module symlinked)

{
	test: /\.(jsx?|tsx?)$/,
	// we have babel ignore most node_modules, but we tell it to transpile the scripts within MY_MODULE
	include: [
		path.resolve(rootPath, "src"),
		fs.realpathSync(path.resolve(rootPath, "node_modules", "MY_MODULE"))
	],
	loader: "babel-loader",
	options: [...]
},

same problem but different use case. i am using lerna to create packages for different modules. so my packages have this kind of pattern node_modules/@packages/ui-components
i tried to both include and exclude but it doesn't work.

I built a package called are-you-es5 that checks which of your dependencies aren't ES5 and builds the exclude regex you need for your specific set of packages, based on @jonnymbgood's solution. I could really use some testers/contributors for the package to run it in different projects and make sure it behaves well in all cases.

carbon

For your information, there's a plugin that may help simplifying things: next-plugin-transpile-modules

You could use an array for the dependencies, it's a little nicer to edit this way. And you don't have to escape module names.

const transpileDependencies = [
    'module1',
    'module2'
]

loaders: [
    {
        exclude: new RegExp(`node_modules/(?!(${transpileDependencies.join('|')})/).*`)
    }
]

I know I've compiled node_modules in the past using something like the above methods that use exclude. They weren't working for me this time, as of babel 7 which seems to ignore node_modules automatically

This worked:

import { resolve } from 'path';

// ...

  {
    test: /\.(js|jsx|ts|tsx)$/,
    include: [
      resolve('src'),
      // These dependencies have es6 syntax which ie11 doesn't like.
      resolve('node_modules/@rehooks/component-size'),
      resolve('node_modules/react-spring'),
    ],
    use: ['babel-loader'],
  },

If anyone's still confused by changes in Babel 7 (I was), you have to switch to using babel.config.js in order to affect modules in node_modules:
https://babeljs.io/docs/en/configuration#babelconfigjs

@eoinmurray you can exclude all node modules except qs using the following:

exclude: /node_modules\/(?!qs)/

This will let babel transpile qs without touching every other node module.

If you need to exclude more than one module you can extend the exception list like so:

exclude: /node_modules\/(?![module1|module2])/

Hope that helps :)

works!!!!!!!!!!

If you're experiencing this issue with Next.js, use next-transpile-modules! My setup was a Dockerized Next.js app and a local npm module that wasn't being transpilled.

What if the package that should be transpiled contains its own node_modules package that should be transpiled as well? How it can be handled?
Thanks

Project (Babel/Webpack/Typescript)

  • node_modules
    • dependencyA (ES6)
      • node_modules
        • nested_dependency (ES6)

worth mentioning is that (for me at least) the build time was much quicker, especially in watch mode with webpack when using only include and not even bothering with exclude. node_modules seems to be ignored by default, and simply explicitly including what you need to be transpiled instead appears to be faster:

const path = require('path');

include: [
  path.resolve(__dirname + '/assets/src/js'), // your default js source
    ...['module-to-be-transpiled', 'another-module-to-be-transpiled'].map((moduleName) => (
      path.resolve(__dirname + '/node_modules/' + moduleName)
    ))
]

node_modules\/(?!(module1|module2)) works
[] matches a single character in the row, but wrapping modules in () matches a sequence.

So my code is like this:

const modulesToTranspile = ['module1', 'module2', '@corp/long-module-name'];

// webpack config
include: modulesToTranspile.map(moduleName =>
    path.resolve(__dirname, `../../../../node_modules/${moduleName}`)
),
exclude: [new RegExp(`node_modules\/(?!(${modulesToTranspile.join('|')}))`)]