After installing babel-polyfill
, in next.config.js
module.exports = {
webpack: (config, { dev }) => {
var oldEntry = config.entry;
config.entry = function () {
return oldEntry().then(function (entries) {
entries['main.js'].unshift('babel-polyfill');
return entries;
});
}
return config;
}
};
We use this automatically as you use features which needs a polyfill. You don't need to use it manually.
Well, the version I was on v2.4.0 doesn't work (on IE 11, etc) if I didn't include the script I wrote above. I got errors for null calling on "includes" methods etc.
I assume that means polyfill either isn't included automatically or what it was there didn't work at all.
@pencilcheck I assume this is related to a module in your app. It doesn't come with a polyfill. In that case you need to use it.
But including the whole babel-polyfill
is not a good option. It's huge.
May be you can add the exact polyfill you need. Use core-js
That's what's inside babel-polyfill
Things have come a long way. babel-polyfill
now plays well with babel-preset-env
so you can include only the polyfills for your target environments/browsers. To do that:
// next.config.js
module.exports = {
webpack: (config) => {
// Unshift polyfills in main entrypoint.
const originalEntry = config.entry;
config.entry = async () => {
const entries = await originalEntry();
if (entries['main.js']) {
entries['main.js'].unshift('./polyfills.js');
}
return entries;
};
return config;
}
}
// polyfills.js
import 'babel-polyfill';
// .babelrc
{
"presets": [
[
"next/babel",
{
"preset-env": {
"targets": {
"browsers": "defaults"
},
"useBuiltIns": true
}
}
]
]
}
// .babelrc (Babel 7)
{
"presets": [
[
"next/babel",
{
"preset-env": {
"useBuiltIns": "usage"
}
}
]
]
}
// .browserslistrc
defaults
You still need a separate polyfills.js
file with the import statement, as simply unshifting babel-polyfill
as the original post will include all the polyfills.
Would be good to consider this as default in Next though.
I just want to leave a note here that after upgrading to Next 6, after every navigation that required a server build, HMR informed me that "The following modules couldn't be hot updated: (Full reload needed)" because - undefined
module could not be hot replaced.
I noticed that multiple babel-polyfill
's were being added to the bundle (by console.log
the moduleMap
in webpack-hot-middleware/client.js
) each time a page needed to be built.
I removed the babel-polyfill
code and the issue went away. So maybe something to be cautious of.
@joaovieira a couple of comments on that:
useBuiltins
does not appear to accept a value of true
now, see the error below:
Module build failed: Invariant Violation: [BABEL] ~/pages/_error.js: Invalid Option: The 'useBuiltIns' option must be either
'false' (default) to indicate no polyfill,
'"entry"' to indicate replacing the entry polyfill, or
'"usage"' to import only used polyfills per file (While processing: "~/node_modules/next/babel.js$0")
at invariant (~/node_modules/invariant/invariant.js:40:15)
at validateUseBuiltInsOption (~/node_modules/next/node_modules/@babel/preset-env/lib/normalize-options.js:130:26)
also there seems to be no need to hack the webpack entries, you can use the clientBootstrap
in next.config.js:
exports = module.exports = {
// ...
clientBootstrap: [path.join(__dirname, './app/polyfills.js')]
// ...
};
with the same content in polyfills.js as in your example.
clientBootstrap
is not part of the Next.js codebase at this point.
To add IE11 Array.includes
support I added includes as polyfill from core-js. But now I have the same issue as @vjpr.
If I just removed the polyfill part from the config it works as expected and doesn't reloads at every page navigation.
I don't get it yet how to fix it. Following some code example:
module.exports = {
webpack: function(cfg) {
const originalEntry = cfg.entry;
cfg.entry = async() => {
const entries = await originalEntry();
if(entries['main.js']) {
entries['main.js'].unshift('./src/polyfills.js');
}
return entries;
};
return cfg;
},
};
/* eslint no-extend-native: 0 */
import includes from 'core-js/library/fn/array/virtual/includes';
Array.prototype.includes = includes;
Facing the same issue, for now I conditionally only add my polyfills for production
webpack: function(cfg, { dev }) {
if (!dev) {
const originalEntry = cfg.entry;
cfg.entry = async() => {
// ...
Thanks to @joaovieira for your example. It solved my issue for supporting IE11. If you are on Babel 7 (Next 6.x and beyond), a small change in the preset is required. Here is the updated code (including an example of transpiling a node module that used an arrow function:
This assumes you have a file called polyfills.js
that just has a import @babel/polyfill
.
const path = require('path')
module.exports = {
webpack: config => {
// Unshift polyfills in main entrypoint.
const originalEntry = config.entry
config.entry = async () => {
const entries = await originalEntry()
if (entries['main.js']) {
entries['main.js'].unshift('./polyfills.js')
}
return entries
}
// This lib has an arrow fn causing IE11 to explode
config.module.rules.push({
test: path.resolve('./node_modules/superagent-charset/index.js'),
loader: 'babel-loader',
options: {
babelrc: false,
cacheDirectory: true,
presets: ['@babel/preset-env'],
},
})
return config
},
}
Are the imports in polyfills.js
being transpiled by babel?
I'm including a polyfill for Object proxy https://github.com/GoogleChrome/proxy-polyfill
and IE is throwing on the template string in one of the errors. I confirmed that preset-env
is applying the babel plugin for converting template strings.
Does this solution works only for the client side code ? I keep on getting regeneratorRuntime is not defined if I use async/await on server side code.
With babel 7 and nextjs 7, just add useBuiltIns: "usage"
in .babelrc
and it works:
module.exports = {
presets: [
[
"next/babel",
{
"preset-env": {
targets: {
browsers: [">0.03%"]
},
useBuiltIns: "usage"
}
}
]
]
};
Source : https://babeljs.io/docs/en/babel-polyfill#usage-in-node-browserify-webpack
Note that this will NOT polyfill anything that node_module dependencies depend on, since it only inserts polyfills for stuff that is babel transformed, and by default node_modules are not babel transpiled when building the client project (which is a good thing).
@joaogranado Using your solution with babel 7 gives this error (warning?) on build:
When setting `useBuiltIns: 'usage'`, polyfills are automatically imported when needed.
Please remove the `import '@babel/polyfill'` call or use `useBuiltIns: 'entry'` instead.
I changed "useBuiltIns": "usage"
to "useBuiltIns": "entry"
and it _seems_ to work, not sure it's the right way though...
@rap2hpoutre for whatever reason, this solution isn't working for us - still getting Object does not support property or method 'assign'
errors in IE 11. Is there anything further we need beyond the configuration change in .babelrc
? (the entries business, perhaps?)
Most helpful comment
Things have come a long way.
babel-polyfill
now plays well withbabel-preset-env
so you can include only the polyfills for your target environments/browsers. To do that:Babel 6
Babel 7
You still need a separate
polyfills.js
file with the import statement, as simply unshiftingbabel-polyfill
as the original post will include all the polyfills.Would be good to consider this as default in Next though.