Next.js: Build bundle for modern browsers and legacy browser separately

Created on 9 Oct 2017  路  16Comments  路  Source: vercel/next.js

  • [x] I have searched the issues of this repository and believe that this is not a duplicate.

There is about 47% desktop browsers and about 45% mobile browsers run ES2015 without any problem. By https://www.netmarketshare.com

There is new simplest solution yet how to deploy separate javascript to modern browsers and transpiled to older browsers. And it is use to

All 16 comments

Step 2 might not be necessary, the newer version of uglify is fully es6 compatible.

Any news on the progress of this issue? We're targeting only recent browsers and would love to lose the 10kb core-js, 2.5kb regenerator and 1kb babel-runtime deps + the size improvements by having es6 over es5 in all files.

Updates on this? Some time has passed and there's more browser support across the board. The latest versions of Chrome, Safari, Firefox, Edge, iOS Safari, and Chrome for Android support type="module" and the nomodule attribute according to caniuse.

Looks like @babel/preset-env has an option for module output:

"presets": [
  ["@babel/preset-env", {
    "targets": {
      "esmodules": true
    }
  }]
]

And uglify has a compress option to specify version output:

new UglifyJsPlugin({
  uglifyOptions: {
    compress: {
      ecma: 6,
    }
  }
});

Quick demo of module/nomodule (view source)

Very much looking forward to the day when Next can let the browser decide which Ecma version to download!

Updates on this?

In general, when there's no comment there's no update.

Vue CLI, Preact CLI and Meteor.js now support this so it could be worth reviewing their approaches.

I鈥檝e seen people report savings of up to 50% in bundle sizes.

This plugin may be of interest: https://github.com/prateekbh/babel-esm-plugin

@timneutkens I imagine that making support for this implies big changes on the Next.JS codebase. Am I wrong?

@radeno wouldn't be better if instead of using <script type="module"> to load the generated bundle for modern browsers, and <script nomodule> for legacy, just add paths for the next.js server and differ which bundles need to be loaded based on the user-agent? (That's how meteor 1.7 works currently)

@JonatanSalas The user-agent solution would not be viable if your Next.JS server was behind a caching layer like a CDN. Or at least the cache key would need to contain the user-agent which could cause problems for some use cases.

@alexparish yeah, but using the approach explained here will lead to issues too except in the case that you can make a custom babel config to support transpiling those unsupported features.

Would you mind to explain me this?

Or at least the cache key would need to contain the user-agent which could cause problems for some use cases.

Why you consider it should cause some problems using the user-agent as the cache-key and in which cases?

@JonatanSalas Sure! I assumed your proposal would involve the Node server rendering the appropriate script tag for the user agent. If you have a caching solution in front of the Node server then the first version of the document will get cached and all user agents will be sent the same document and therefore script tag. To work round this any cache providers used would need to be configured appropriately. This is a burden that I don't think a framework should put on its users.

@alexparish I see your point! Thanks for the explanation.

Nuxt.js recently merged this feature in: https://github.com/nuxt/nuxt.js/pull/4231

@timneutkens are you open to PRs introducing this enhancement?

Not yet, I have a few ideas on tackling this.

There are a few pitfalls:

  • module scripts will always be loaded deferred, this might e.g. make polyfills available only after the first executed code that depends on them
  • Safari 10.1 supports modules, but will still execute scripts with the nomodule attribute, there is a fix for this though
  • using esmodules: true in babelrc will disable the browserslist integration - so even when my browserslistrc would exclude some browsers that support modules, that would be overridden, and babel would apply some unnecessary transformations, and if useBuiltIns: usage is used, unnecessary polyfills will be pulled in additionally

Hi all,
Can we start by providing a feature to remove polyfills from next.js commons bundle.
Right now what happens is that next is published to npm transpiled. So:
https://github.com/zeit/next.js/blob/d9c462bf379709db8070ff19217b12149f97b63f/packages/next/client/index.js#L18-L20
gets transpiled as

var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
if (!window.Promise) {
  window.Promise = _promise.default;
}

And this gets uploaded to npm registry. And now there is no way of removing the dependency on @babel/runtime-corejs2/core-js/promise. (I tried to pass variouspreset-env options to next/babel but then this is hardcoded into the npm registry so can't do anything. 馃槶 )

Related RFC: #7563

Was this page helpful?
0 / 5 - 0 ratings

Related issues

flybayer picture flybayer  路  3Comments

timneutkens picture timneutkens  路  3Comments

ghost picture ghost  路  3Comments

knipferrc picture knipferrc  路  3Comments

kenji4569 picture kenji4569  路  3Comments