Next.js 5.1: Faster Page Resolution, Environment Config & More

Arunoda SusiripalaArunoda Susiripala

We are happy to introduce Next.js 5.1, which features support for environment configuration, phases, source maps, and new Next.js plugins.

Major performance improvements are introduced: resolving pages is 102x faster, and error pages are loaded more efficiently.

To upgrade or install, run:

npm i next@latest react@latest react-dom@latest

In addition to bumping Next.js, we upgrade the peer dependencies react and react-dom

Be sure to upgrade next-plugins like @zeit/next-css, @zeit/next-sass, @zeit/next-less or @zeit/next-typescript as well.

Faster page resolution

Thanks to the architectural changes in Next.js 5.0, we were able to simplify the logic that resolves pages based on url path. These changes were based on research from @oliviertassinari. Previously resolving a page took an average of 2.347ms. With the new logic resolving the same page takes on average 0.023ms. That's a 102x speedup for one of the most commonly invoked methods in Next.js applications.

Page resolution shown per request. Left is Next.js 5.0, right is Next.js 5.1

Environment configuration

Typical Node.js environments often depend on passing environment variables to the application, for example: API_URL=https://api.zeit.co node index.js and then you can use API_URL anywhere in your application using process.env.API_URL.

With universal rendering process.env is not available on the client side. So with Next 5.1 we're introducing a new feature: publicRuntimeConfig and serverRuntimeConfig. These can be set in next.config.js and will then be available using the next/config module.

// next.config.js
module.exports = {
  serverRuntimeConfig: {
    // Will only be available on the server side
    mySecret: 'secret'
  },
  publicRuntimeConfig: {
    // Will be available on both server and client
    staticFolder: '/static'
  }
}

Both serverRuntimeConfig and publicRuntimeConfig are defined in next.config.js

// pages/index.js
import getConfig from 'next/config'
const { serverRuntimeConfig, publicRuntimeConfig } = getConfig()

console.log(serverRuntimeConfig.mySecret) // Will only be available on the server side
console.log(publicRuntimeConfig.staticFolder) // Will be available on both server and client

export default function Index() {
  return (
    <div>
      <img src={`${publicRuntimeConfig.staticFolder}/logo.png`} />
    </div>
  )
}

The getConfig method from the next/config module is used to get configuration values

Improved Error Handling

Previously Next.js had a special error handling mechanism for detecting server errors when loading page bundles. A page bundle is the javascript file that is loaded on the client side to load the page, for example /_next/-/page/index.js.

If there were an error, like a build ID mismatch, the page bundle would still be served with a 200 HTTP status, but the contents would be a JSON representation of an error generated by the Next.js server. The reason for this is that there was client side error handling that depended on more than just the page being a 404. This solution worked really well, until you try to upload assets to a static file host or CDN that doesn't support a fallback.

With Next.js 5.1 we've completely refactored the error handling logic, when a page bundle returns a 404 HTTP status the router will automatically detect it and reload the page, to make sure navigation between multi-zones is possible.

In rewriting this logic, we removed the Router.onAppUpdated hook; which was mainly used to trigger a page reload. Now the page will be automatically reloaded

In addition to this, we've added a new set of integration tests on error recovery in the development mode, to avoid regressions on error recovery in future releases.

Phases / config function

Some next-plugins like @zeit/next-css are only required when Next.js is in development mode or when running next build.

You can now export a function that returns the configuration object instead of immediately exporting the object.

module.exports = (phase, { defaultConfig }) => config

next.config.js exporting a function that returns the user configuration

Exporting a function will give you access to the phase in which Next.js is running, for example development, production, building, export. This allows plugins to be loaded only when needed, but also gives access to the default configuration.

We've introduced a new module called next/constants holding commonly used constants, including phases.

const {PHASE_DEVELOPMENT_SERVER} = require('next/constants')
module.exports = (phase, {defaultConfig}){
  if(phase === PHASE_DEVELOPMENT_SERVER) {
    return { /* development only config options here */ }
  }

  return { /* config options for all phases except development here */ }
}

A next.config.js that checks for the development phase

Improved production source map generation

With the introduction of universal webpack in Next.js 5 adding source maps to your production environment became as simple as adding a few lines to next.config.js:

module.exports = {
  webpack(config, { dev }) {
    if (!dev) {
      config.devtool = 'source-map'
      for (const plugin of config.plugins) {
        if (plugin['constructor']['name'] === 'UglifyJsPlugin') {
          plugin.options.sourceMap = true
          break
        }
      }
    }
    return config
  }
}

Manually enable source maps in next.config.js

@zeit/next-source-maps can be added to a project to automatically enable production source maps for you, add the following to next.config.js:

const withSourceMaps = require('@zeit/next-source-maps')
module.exports = withSourceMaps()

Using @zeit/next-source-maps to enable source maps in next.config.js

This enabled outputting of source maps for all but one file, app.js, the reason for this was that app.js consisted of multiple files (manifest.js and commons.js) combined with a webpack plugin. A side effect of this was that webpack couldn't generate source maps for the combined file.

Thanks to a pull request from @ptomasroos the app.js file was replaced by main.js. This file will hold the code that was previously compiled to manifest.js and commons.js and webpack will generate a source map for main.js. Source maps will be automatically served, allowing external error tracking tools to show the actual file an line number when errors are detected.

The source code is shown in the sources panel

New plugins / improvements to existing ones

We've introduced two new official plugins. @zeit/next-bundle-analyzer allows for easily setting up webpack-bundle-analyzer to analyze the server side and client side bundles separately.

Additionally there were a lot of improvements to the official css, less, and sass plugins regarding hot reloading and bundling. For example there is no longer a flash of unstyled content in development mode. And styles in subcomponents get picked up as well.

Community

You can now find the Next.js community on GitHub. Recently a list of notable companies using Next.js was posted there. Feel free to post projects in the thread.

Thank you

We would like to thank everyone who has contributed to Next.js for this release. Whether it's contributing to the core or expanding and improving our ever growing examples directory.

If you are looking to start contributing to Next.js you can find issues with the good first issue or help wanted label.

A special thank you to Trulia for their valuable feedback related to environment configuration and the new error page handling.