Next.js: Unable to transpile ES6 to ES5 for IE11

Created on 6 Feb 2020  路  7Comments  路  Source: vercel/next.js

Bug report

Describe the bug

As per my knowledge next/babel in presets should transpile the code for non ES6 supporting browsers. But I can still find arrow functions, class, etc, in my /out folder. Also when I try to deploy this build it only works for chrome but not for IE or older versions of firefox.

To Reproduce

Repo Link:
Steps to reproduce the behavior, please provide code snippets or a repository:
1) git clone https://github.com/mdvkmd/nextTranspileIssue.git nextTranspileIssue 2) cd nextTranspileIssue 3) npm install 4) npm run start

Expected behavior

It should produce ES5 transpiled code in out folder and should work on IE 11, Firefox 30, etc

System information

  • OS: macOS
  • Browser : [IE11, mozilla 30]
  • Version of Next.js: [^9.1.6]

Additional context

I've also tried the below babel.config (Will also attach more babel.configs that I have tried)

module.exports = function (api) {
  api.cache(true);

  const presets = [
    [
      'next/babel',
      {
        'preset-env': {
          targets: {
            browsers: ['last 2 versions', 'ie > 9']
          },
          corejs: '2',
          useBuiltIns: 'usage',
          loose: true
        },
        'transform-runtime': {
          useESModules: false
        }
      }
    ]
  ];

  const plugins = [
    'inline-dotenv',
    ['module-resolver', { root: ['./src'] }],
    ['import', { libraryName: 'antd', style: 'css' }],
    ['emotion']
  ];

  const env = {
    test: { presets: [['next/babel']] },
    production: { presets: [['next/babel', { 'preset-env': { modules: false } }]] }
  };

  return {
    presets,
    plugins,
    env
  };
};

But the above results in
Error occurred prerendering page "/recharge" https://err.sh/zeit/next.js/prerender-error: TypeError: Class constructor App cannot be invoked without 'new'

Related Links:
#7914
#9000

Most helpful comment

@abhinavnigam2207

In my experience it's not related to nextjs... as @jamesmosier mentioned this too often comes with npm thirdparty. So here's something that might help :

Locate problems with es-check

yarn add es-check --dev

Add scripts in your package.json

{
    "clean": "rimraf --no-glob ./.next ./out",
    "check:es:build": "es-check es5 './.next/static/**/*.js' -v",
    "check:es:export": "es-check es5 './out/**/*.js' -v",
}

Then run yarn clean && yarn check:es:build for example

You'll probably end up with an error message. The tricky part is now to locate the incriminated package in the file (I generally open it, then format in webstorm, and guess the culprit).

Transpile the package with next-transpile-modules

yarn add next-transpile-modules --dev

Activate it in your next.config.js

const withTM = require('next-transpile-modules')([
  // Those packages needs to be transpiled to be sure they pass `es-check es5`
  'ky',
  '@sindresorhus/is',
]);

module.export = withXX?(
  withZZ?(
    withTM({
      // your next config
    })
 )
)

Then retry a build and a check.

Notes

  • Good to put the es5 checks in your CI
  • I'm often too lazy, but would be awesome to open P/R for corresponding package

Hope it helps

All 7 comments

module.exports = function (api) {
  api.cache(true);

  const presets = [['next/babel',
    {
      'preset-env': {
        targets: {
          chrome: '58',
          ie: '11'
        },
        modules: false
      }
    }],
  '@emotion/babel-preset-css-prop'
  ];

  const plugins = [
    'inline-dotenv',
    ['module-resolver', { root: ['./src'] }],
    ['import', { libraryName: 'antd', style: 'css' }],
    ['emotion']
  ];

  const env = {
    test: { presets: [['next/babel']] },
    production: { presets: [['next/babel', { 'preset-env': { modules: false } }]] }
  };

  return {
    presets,
    plugins,
    env
  };
};

Also tried the above babel.config still
Error occurred prerendering page "/abc" https://err.sh/zeit/next.js/prerender-error: TypeError: Class constructor App cannot be invoked without 'new'

Instead of using a custom Babel config for this, have you looked at using polyfills? There is a good example for this.

Next itself is compatible with the browsers you mentioned, but any third-party packages might not be. That is where the polyfills come in handy.

@jamesmosier I too read that next-babel covers the preset-env out of the box, but it doesn't converts the ES6 modules to ES5 like arrow function, async functions, etc
Just to confirm I also tried with the below config just for adding a few extra options for browsers.
const presets = [ [ 'next/babel', { 'preset-env': { targets: { browsers: ['last 2 versions', 'ie > 9'] } }, 'transform-runtime': { useESModules: false } } ], '@emotion/babel-preset-css-prop' ];
Still no luck.

If you were to start an empty Next project, run next build, and then view the output it would properly transpile all of the assets for the browsers in question.

Once you start adding third-party NPM packages, that's when the polyfills would be useful.

As far as your specific Babel config, I'm not sure.

@abhinavnigam2207

In my experience it's not related to nextjs... as @jamesmosier mentioned this too often comes with npm thirdparty. So here's something that might help :

Locate problems with es-check

yarn add es-check --dev

Add scripts in your package.json

{
    "clean": "rimraf --no-glob ./.next ./out",
    "check:es:build": "es-check es5 './.next/static/**/*.js' -v",
    "check:es:export": "es-check es5 './out/**/*.js' -v",
}

Then run yarn clean && yarn check:es:build for example

You'll probably end up with an error message. The tricky part is now to locate the incriminated package in the file (I generally open it, then format in webstorm, and guess the culprit).

Transpile the package with next-transpile-modules

yarn add next-transpile-modules --dev

Activate it in your next.config.js

const withTM = require('next-transpile-modules')([
  // Those packages needs to be transpiled to be sure they pass `es-check es5`
  'ky',
  '@sindresorhus/is',
]);

module.export = withXX?(
  withZZ?(
    withTM({
      // your next config
    })
 )
)

Then retry a build and a check.

Notes

  • Good to put the es5 checks in your CI
  • I'm often too lazy, but would be awesome to open P/R for corresponding package

Hope it helps

I also realized that you're using ant-design... So here's my current tricks to enable tree-shaking

  1. the babel.config.js
const aliasPlugin = [
  'module-resolver',
  {
    root: ['.'],
    alias: {
      _core: './src/core',
      _assets: './src/assets',
      _features: './src/features',
      _components: './src/components',
      _data: './src/data',
      _backend: './src/backend',
      _pages: './src/pages'
     //....
    },
  },
];


const antdImportPlugin = [
  'import',
  {
    libraryName: 'antd',
// 'es' will allow tree shking and thus you need to transpile afterwards
    libraryDirectory: 'es',
// set this to true if you want the less customization and want to prevent modifying global styles
// @link https://next.ant.design/docs/react/customize-theme#How-to-avoid-modifying-global-styles?
    style: 'css', 
    },
];

module.exports = {
  env: {
    development: {
      presets: [['next/babel'], ['@emotion/babel-preset-css-prop']],
      plugins: [antdImportPlugin, aliasPlugin],
    },
    production: {
      presets: [['next/babel'], ['@emotion/babel-preset-css-prop']],
      plugins: [antdImportPlugin, aliasPlugin],
    },
    test: {
      presets: [['next/babel'], ['@emotion/babel-preset-css-prop']],
      plugins: [antdImportPlugin, aliasPlugin],
    },
  },
};

  1. I specify the browserlist in my package.json
  "browserslist": {
    "production": [
      ">1%",
      "ie >= 11",
      "edge >= 14",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  1. in my nextjs.config.js, i have to transpile the following ant components:
// We need to transpile this because we use the 'es' version
const withTM = require('next-transpile-modules')([
  'antd',
  'rc-util',
  'rc-animate',
  'rc-pagination',
  'css-animation',
  'rc-tabs',
]);

Far from perfect... but I could not find a better way till now.

I guess I was setting config.rules = [] rather than pushing into it. As I already had a .babel..config file my next.config was overriding it as instead of pushing I was setting the rules in it.

Below is the babel.config and next.config which solved my problem:

`module.exports = function (api) {
api.cache(true);

const presets = [['next/babel', {
'preset-env': {
// eslint-disable-next-line max-len
targets: '> 0.25%, not dead',
corejs: 2,
modules: 'commonjs',
forceAllTransforms: true,
useBuiltIns: 'usage'
}
}], '@emotion/babel-preset-css-prop'
];

const plugins = [
'inline-dotenv',
['module-resolver', { root: ['./src'] }],
['import', { libraryName: 'antd', style: 'css' }],
['emotion']
];

const env = {
test: {
presets: [
['next/babel', {
'preset-env': {
modules: 'commonjs'
}
}]
]
}
};
return {
presets,
plugins,
env
};
};
`

below is the next.config:
`webpack: (config, { isServer }) => {
config.output.publicPath = '';
if (isServer) {
const antStyles = /antd\/.?\/style\/css.?/;
const origExternals = [...config.externals];
config.externals = [ // eslint-disable-line
(context, request, callback) => { // eslint-disable-line
if (request.match(antStyles)) return callback();
if (typeof origExternals[0] === 'function') {
origExternals0;
} else {
callback();
}
},
...(typeof origExternals[0] === 'function' ? [] : origExternals)
];

  config.module.rules.unshift({
    test: antStyles,
    use: 'null-loader'
  });
}

if (ANALYZE) {
  config.plugins.push(new BundleAnalyzerPlugin({
    analyzerMode: 'server',
    analyzerPort: 8888,
    openAnalyzer: true
  }));
}

config.node = {
  fs: 'empty'
};

config.module.rules.push({
  loader: 'babel-loader',
  exclude: /node_modules/,
  test: /\.js$/,
  options: {
    cacheDirectory: true,
    plugins: [
      ['import', { libraryName: 'antd', style: 'css' }]
    ]
  }
});

config.module.rules.push({
  test: /\.less$/,
  use: [
    { loader: 'style-loader' },
    { loader: 'css-loader' },
    {
      loader: 'less-loader',
      options: {
        modifyVars: themeVariables,
        root: path.resolve(__dirname, './'),
        javascriptEnabled: true
      }
    }
  ]
});

config.module.rules.push({
  test: /\.css$/,
  use: [
    {
      loader: 'css-loader'
    }
  ]
});

return config;

}
`

Was this page helpful?
0 / 5 - 0 ratings

Related issues

renatorib picture renatorib  路  3Comments

pie6k picture pie6k  路  3Comments

sospedra picture sospedra  路  3Comments

irrigator picture irrigator  路  3Comments

knipferrc picture knipferrc  路  3Comments