Next.js: polyfills and redirect on dev environment

Created on 20 Jun 2018  路  6Comments  路  Source: vercel/next.js

Bug report [tested on IE11, Chrome/Firefox supports without polyfills]

  • Polyfills added by next.js (i.e. object.assign) can't be recognized by the browser.
  • the way with-polyfill example suggested can't be recognized by the browser as well.
  • polyfills added as following way performs redirect on dev mode when changing page.

Describe the bug

  1. Polyfills added by default have no effect: Here is the webpack-bundle-analyzer report: https://d.pr/f/EMnBSM. It shows bundler already added polyfills like object.assign from core-js (https://d.pr/i/drxC87). But we experience that browsers (IE11) can't recognize those. didn't test on Chrome/Firefox as those support without polyfills.

  2. Browser can't recognize the following way as suggested by with-polyfills example

import includes from 'core-js/library/fn/string/virtual/includes'
String.prototype.includes = includes

Need to do like this: (polyfills.js)

// sort of global
import "core-js/fn/string/virtual/includes"
  1. Redirects on changing pages when configure next.config.js as suggested way

Our next.config.js code without css stuff:

const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer")
const DotEnv = require("dotenv-webpack")
const withCSS = require("@zeit/next-css")
const internalNodeModulesRegExp = /@friflyt(?!.*node_modules)/
const externalNodeModulesRegExp = /node_modules(?!\/@friflyt(?!.*node_modules))/

module.exports = withCSS({
  webpack: (config, { dev, isServer, defaultLoaders }) => {
    // environment specific
    config.plugins.push(new DotEnv())

    // bundle analyzer plugin for prod
    !dev &&
      config.plugins.push(
        new BundleAnalyzerPlugin({
          analyzerMode: "static",
          openAnalyzer: false,
          reportFilename: isServer
            ? "server-bundle-analysis.html"
            : "client-bundle-analysis.html"
        })
      )

    // polyfills
    const origEntry = config.entry
    config.entry = async () => {
      const entries = await origEntry()

      if (entries["main.js"]) {
        entries["main.js"].unshift("./polyfills.js")
      }

      return entries
    }

    // compile local modules through babel
    config.resolve.symlinks = false
    config.externals = config.externals.map(external => {
      if (typeof external !== "function") return external
      return (ctx, req, cb) =>
        internalNodeModulesRegExp.test(req) ? cb() : external(ctx, req, cb)
    })
    config.module.rules.push({
      test: /\.+(js|jsx)$/,
      loader: defaultLoaders.babel,
      include: [internalNodeModulesRegExp]
    })
    return config
  },
  webpackDevMiddleware: config => {
    config.watchOptions.ignored = [
      ...config.watchOptions.ignored,
      externalNodeModulesRegExp
    ]
    return config
  }
})


Expected behavior

Describe above.

Screenshots

System information

  • OS: macOS
  • Browser: redirect issue tested on chrome on dev mode, not tested on other browsers
  • Version of Next.js: 6.0.3

Most helpful comment

@yves-s assign isn't a method on Object instances (made available via its prototype), but rather a static method called like Object.assign. So ditch the prototype there!

All 6 comments

Having same issue

Similar issue to #4643.

I wonder if, since _app.js exists now, the recommended advice will be to import your polyfill module(s) there? Before, the custom webpack config approach was necessary because there wasn't a single customizable entrypoint, but now _app.js basically serves that purpose.

Currently I add necessary polyfills as suggested in the example:

// polyfill.js

/* eslint no-extend-native: 0 */
// core-js comes with Next.js. So, you can import it like below
import includes from 'core-js/library/fn/array/virtual/includes';
import find from 'core-js/library/fn/array/virtual/find';
import assign from 'core-js/library/fn/object/assign';

// Add your polyfills
// This files runs at the very beginning (even before React and Next.js core)
Array.prototype.includes = includes;
Array.prototype.find = find;
Object.prototype.assign = assign;
// next.config.js

const withTypescript  = require('@zeit/next-typescript');

module.exports = withTypescript({
    webpack: function(config, {dev}) {
        if(!dev) {
            const originalEntry = config.entry;

            config.entry = async() => {
                const entries = await originalEntry();

                if(entries['main.js'] && !entries['main.js'].includes('./src/polyfills.js')) {
                    entries['main.js'].unshift('./src/polyfills.js');
                }

                return entries;
            };
        }

        return config;
    },
});

It's actually pretty straight forward and works with includes and find but unfortunately it doesn't with assign.

Any suggestions or ideas why?

@yves-s assign isn't a method on Object instances (made available via its prototype), but rather a static method called like Object.assign. So ditch the prototype there!

Thanks @exogen for your quick answer.

Going to close this in favor of something like #4754

Was this page helpful?
0 / 5 - 0 ratings