vercel / next.js

The React Framework
https://nextjs.org
MIT License
127.51k stars 27.04k forks source link

Use Terser for minifying production build #5021

Closed robinvdvleuten closed 6 years ago

robinvdvleuten commented 6 years ago

Feature request

Is your feature request related to a problem? Please describe.

Currently Next.js minifies the production build with Uglify. Unfortunately, uglify-es is no longer maintained and uglify-js does not support es6+ syntax very well. It would be nice to make the same move as Parcel to use the terser library.

Describe the solution you'd like

Webpack v4 has already a compatible terser plugin, which could be enabled quite easily;

// next.config.js
const TerserPlugin = require('terser-webpack-plugin')
const withSourceMaps = require('@zeit/next-source-maps')

module.exports = withSourceMaps({
  webpack: (config, { dev, isServer }) => {
    if (!dev && !isServer) {
      config.optimization.minimizer = [new TerserPlugin({
        parallel: true,
        sourceMap: true
      })]
    }

    return config
  }
})

I already did this on one of my projects which currently runs in production and haven't run into any issues yet. I even noticed some improvements on the build time. Also the sourcemaps work as expected.

Describe alternatives you've considered

An alternative would be to create a next-terser plugin to let people have the option to opt-in if they want.

timneutkens commented 6 years ago

In your tweet you pointed out improved build times, could you provide data backing this up? Just curious about it, I definitely think we need to make this move 👍

robinvdvleuten commented 6 years ago

The first run is the default Next.js webpack configuration (so it's using Uglify);

$ next build
[09:45:08] Compiling client
[09:45:08] Compiling server
> Using external babel configuration
> Location: "~/.babelrc"
[09:45:18] Compiled server in 10s
[09:47:16] Compiled client in 2m
✨  Done in 129.50s.

The second is with the terser webpack plugin enabled;

$ next build
[09:42:46] Compiling server
[09:42:46] Compiling client
> Using external babel configuration
> Location: "~/.babelrc"
[09:42:54] Compiled server in 8s
[09:43:36] Compiled client in 50s
✨  Done in 52.12s.

I am not that of an export of Babel / Webpack performance, but it can also be that there is some caching involved?

robinvdvleuten commented 6 years ago

Hmm it seems if I run the build multiple times, the build times do not differ that much (+/- 5s).

timneutkens commented 6 years ago

The best thing you can do when benchmarking is rm -rf .next && rm -rf node_modules/.cache && yarn build

timneutkens commented 6 years ago

https://github.com/babel/minify#benchmarks you're right that it's faster

robinvdvleuten commented 6 years ago

I've ran both builds again with my caches cleared, but the difference is in 2 or 3 seconds most of the time. So it's not that much faster. But if you look at projects like Parcel, it seems the way to go to minify es6 code with terser. Is there anything I can do to get terser into Next? As I mentioned, the config changes are not that hard and I have the time to create a PR for it to continue the discussion.

timneutkens commented 6 years ago

Yeah the only thing you'll have to do is add the config you mentioned in the issue description.

timneutkens commented 6 years ago

This is the result for zeit.co production build:

Default webpack / Uglify:

rm -rf .next node_modules/.cache && yarn build
yarn run v1.7.0
$ yarn run buildonly && yarn run build:rss
$ cross-env NODE_ENV=production next build
[2:36:51 PM] Compiling client
[2:36:51 PM] Compiling server
> Using external babel configuration
> Location: "/Users/timneutkens/projects/front/.babelrc.js"
[2:37:46 PM] Compiled server in 55s
[2:39:12 PM] Compiled client in 2m
$ node ./.next/server/scripts/build-rss.js
Atom feed file generated at `./server/atom`
✨  Done in 145.19s.

Terser:

rm -rf .next node_modules/.cache && yarn build
yarn run v1.7.0
$ yarn run buildonly && yarn run build:rss
$ cross-env NODE_ENV=production next build
[2:42:22 PM] Compiling client
[2:42:22 PM] Compiling server
> Using external babel configuration
> Location: "/Users/timneutkens/projects/front/.babelrc.js"
[2:43:20 PM] Compiled server in 57s
[2:44:42 PM] Compiled client in 2m
$ node ./.next/server/scripts/build-rss.js
Atom feed file generated at `./server/atom`
✨  Done in 143.70s.