How can I configure babel/preset-env to include core-js URLSearchParams polyfill? - babeljs

I'm using URLSearchParams in my app. The code is transpiled with babel, using babel/preset-env and core-js#3 to include polyfills needed for the browsers I target.
This is my babelrc:
{
"presets": [
[
"#babel/preset-env",
{
"modules": false,
"corejs": "3",
"useBuiltIns": "entry",
"forceAllTransforms": true
}
]
]
}
Here is my .browserslistrc:
IE 11
Edge >= 14
last 2 Chrome versions
last 2 Firefox versions
The problem is that even though I've specified IE11 in .browserslistrc, the polyfill for URLSearchParams is still not included in the final bundle. So far I've solved this by manually importing core-js/web/url-search-params.js but I would rather that was done automatically by babel/preset-env.
Can I configure babel/preset-env somehow to include the URLSearchParams polyfill from core-js?

Since I'm getting upvotes on the question I should probably add my answer here as well.
The problem for me was that I was adding #babel/polyfill next to my entrypoint in my webpack config:
{
entry: {
"my.js": ["#babel/polyfill", "my.js"]
}
}
To fix my problem I removed #babel/polyfill from the entrypoint, and instead added the following to the top of my.js:
import "core-js/stable";
import "regenerator-runtime/runtime";

Related

Not able to use babel "preset-env" plugin with NextJS

I have a requirement where I am trying to use the Babel plugin "preset-env". This plugin compiles my NextJS project from ES6 to ES5. I have created the .babelrlc file as suggested by NextJS documentation and added my plugin like this:
{
"presets": ["next/babel"],
"plugins": ["#babel/preset-env"]
}
When I try to run my project locally I get this error:
error - ./node_modules/next/dist/client/router.js
Error: Cannot find module '#babel/plugin-preset-env' from '/Users/agastya/Local/testcap/Sample-proj'
- If you want to resolve "#babel/preset-env", use "module:#babel/preset-env"
- Did you accidentally pass a preset as a plugin?
NextJS documentation says "Next.js includes the next/babel preset to your app, which includes everything needed to compile React applications and server-side code. ".
It would be great if someone can explain where/what is the right approach to fix this.
You have to do the following:
// .babelrc file, also could be babel.config.js
{
"presets": [
[
"next/babel",
{
"preset-env": {},
"transform-runtime": {},
"styled-jsx": {},
"class-properties": {}
}
]
],
"plugins": []
}
Taken from: https://nextjs.org/docs/advanced-features/customizing-babel-config

Babel 7 not including polyfills

I am trying to transpile a webapplication using Babel v7.8.7 and Webpack v4.42.0.
The solution works in the latest version of Chrome. In Internet Explorer I am getting an error:
SCRIPT5022: Exception thrown and not caught.
If I include polyfills from a CDN the app works correctly in IE11:
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.6.15/browser-polyfill.min.js"></script>
I am now wondering why Babel is not polyfilling correctly.
My index.js includes core-js polyfills:
import "core-js/es";
import "regenerator-runtime/runtime";
I have set .browserslistrc to include Internet Explorer 11.
My babel.config.js:
module.exports = {
presets: [
[
"#babel/preset-env",
{
useBuiltIns: "usage",
corejs: '3.6.4'
}
],
"#babel/preset-react"
],
plugins: [
"#babel/plugin-transform-async-to-generator",
"#babel/plugin-proposal-object-rest-spread",
"#babel/plugin-syntax-dynamic-import",
"#babel/plugin-proposal-class-properties",
"#babel/plugin-proposal-optional-chaining",
"#babel/plugin-proposal-nullish-coalescing-operator"
]
};
Do you know what I am missing to have Babel polyfill correctly?

VS code debugger not working with babel on async code

Versions used:
VS code: 1.35.1
Babel cli: 7.2.3
node: 10
While using breakpoints on async code, with babel transpiling the original source code, the VS code debugger or any other debugger doesn't work because there is something wrong with the --source-maps that the babel provides.
I faced this problem, and now answering my own question,
This is kind of a workaround solution, since I don't know what actually is wrong with the source-maps of babel.
Use targets in babel to define which node version should the output of babel should be. I'm using node 10, and using babel to transpile into node 10 solved my issue. This is my .babelrc file:
{
"presets": [
[
"#babel/preset-env",
{
"targets": {
"node": "10"
}
}
]
],
}
Hope this helps. :)

babel-preset-env not changing build size

I have an ES6 React app that is being bundled with webpack and using babel. I am configuring babel-preset-env, for node everything is working perfect, but for browser the size of my build is not changing regardless the target percentage. The size is the same when the interval is >1 or when its 90%.
The webpack version is 1.13.1, my babel version 6.26.0 and babel-preset-env version is 1.6.1
I have this in my .babelrc
{
"presets": [
"es2015",
"stage-0",
"react",
[
"env",
{
"targets": {
"node": "9.4.0",
"browsers": [
">1%"
]
}
}
]
],
"plugins": [
[
"transform-class-properties",
"transform-runtime",
"transform-decorators-legacy",
"react-intl",
{
"messagesDir": "./build/messages",
"enforceDescriptions": false
}
]
]
}
When you use babel-preset-env it will decide, based on the list of browsers your target, to include only the necessary babel transforms.
It is an alternative to es2015 and stage-0, and including those presets along with env is counterproductive, as the transforms included in those presets will be applied whether they're needed or not.
It also depends on how you use babel-polyfill. Set it as import 'babel-polyfill' at the beginning of your JavaScript entry file, and babel-preset-env will replace the import with individual imports with only the polyfills needed for the browsers you target.
I am not sure if it works that way if you include babel-polyfill as part of the Webpack entry option, e.g.:
js
entry: {
myentry: ['babel-polyfill', 'js/index.js']
}
Hope this will help you get that bundle size down!
P.S. I'm aware the babel-preset-env documentation is not the clearest when it comes to describing what you need to do.
Make sure you have import "#babel/polyfill"; in your index.js.
Also, make sure you only import it once.
If you have something like this
entry: ["#babel/polyfill", path.join(__dirname, "./src/index.js")],
in your webpack config, move the polyfill, so it should look like
entry: path.join(__dirname, "./src/index.js")

babel-jest doesn't handle ES6 within modules

I am trying to set up Jest on a React based project which uses ES6 modules. However I seem to be having issues with ES6 modules, I am using babel-jest and believe I have this set up properly (Jest detects it automatically).
Jest doesn't seem to have a problem using ES6 imports however as soon as it hits on an import statement within one of the imported modules it chokes. It's as if it is only transpiling the initial test script and not any of the imported modules. I have tried various configurations and tried searching Google with no luck. Running tests without any imports works fine.
Here is the error:
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import Predications from './predications';
^^^^^^
SyntaxError: Unexpected token import
Here are the relevant bits of config:
jest.conf.json
{
"testRegex": "\/test\/spec\/.*\\.js$",
}
.babelrc
{
"presets": ["es2015", "stage-0", "react"]
}
Test script
import React from 'react';
import { mount, shallow } from 'enzyme';
import Slider from 'react-slick';
import Carousel from '../../client/components/carousel/carousel.js'; // test chokes on when I include this module
describe('carousel component', () => {
it('is a test test case', () => {
expect(1 + 2).toEqual(3);
});
});
Update:
As suggested, I have tried running the test without jest.conf.js, however the testRegex is needed in order for Jest to find my tests, I tried moving tests to the default test directory and they still fail.
I would like to clarify that tests themselves are running fine, the issue seems to be where one of my imported modules uses ES6, in my example above, if I don't import my carousel component the test runs fine, as soon as I import that the test chokes on the import statement within that file. It seems as though the imported modules are not getting transpiled.
Update #2
After some investigation it appears the issue is that babel is not transpiling ES6 within node_modules. I have created an example repo to demonstrate this here: https://github.com/jamiedust/babel-jest-example
I understand that third party modules should be handling their own transpiling, however we have a number of modules which are hosted on our own npm registry and are re-used between projects, in these cases Webpack handles transpiling, for the Jest tests we need these node_modules to be transpiled by Babel, or a way of leveraging our webpack set up to do this for us.
Solution
Add the following config in package.json (or Jest config file).
"jest": {
"transformIgnorePatterns": [
"/node_modules/(?!test-component).+\\.js$"
]
}
By default any code in node_modules is ignored by babel-jest, see the Jest config option transformIgnorePatterns. I've also created a PR on your example repo, so you can see it working.
While this works, I've found it to be extremely slow in real applications that have a lot of dependencies containing ES modules. The Jest codebase has a slightly different approach to this as you can find in babel-jest transforming dependencies. This can also take much longer on Windows, see Taking 10 seconds on an empty repo.
If doing "unit" testing, mocking is probably the better way to go.
You could try adding the transform-es2015-modules-commonjs plugin to your babel config file for testing only. Here is an example config file which tells babel to transpile modules only when in a testing environment. You can put it underneath your presets:
{
"presets": [
"react",
["es2015", {"modules": false, "loose": true}]
],
"env": {
"test": {
"plugins": ["transform-es2015-modules-commonjs"]
}
}
}
You can read about the plugin here:
https://www.npmjs.com/package/babel-plugin-transform-es2015-modules-commonjs
Then, when running your Jest tests on the command line specify NODE_ENV=test (you may need to add the --no-cache flag to the command the first time after making the change to the babel config because Jest caches babel output, but after that you can leave it off:
NODE_ENV=test jest --no-cache
I learned about this issue in a React seminar by Brian Holt at Frontend Masters. https://frontendmasters.com/courses/
faced the same issue, followed the steps to resolve,
install babel-jest
in jest config add this configuration
transform: {
'^.+\\.js?$': require.resolve('babel-jest')
}
make sure you have babel.config.js present (your config might be different than provided below)
module.exports = {
"env": {
"test": {
presets: [
[
'#babel/preset-env',
{
targets: {
node: 'current',
},
},
],
]
}
}
};
I faced the same problem (node_module not transpiled by babel-jest), without being able to solve it.
Instead, I finally succeed by mocking the node_module, like described here https://facebook.github.io/jest/docs/manual-mocks.html
NB: setting mocks in __mocks__ subfolders did not work for me. So I passed the mock as the second parameter of the jest.mock() function. Something like :
jest.mock('your_node_module', () => {})
Another possible cause. Babel now ignores your .babelrc inside node_modules and uses the one provided by the dependency. If you have control of the dependency you would have to add a .babelrc to it and babel would use those settings for it.
this can cause problems though if your dependency and your project use different babel versions or modules.