跳至内容
返回博客

2018年9月19日,星期三

Next.js 7

发布者

经过26个候选版本发布和340万次下载,我们很自豪地推出可用于生产环境的 Next.js 7,其特色包括

最后,我们很高兴能够在全新的Nextjs.org上分享这一消息

开发体验改进

Next.js 的主要目标之一是提供最佳的生产性能和**尽可能好的开发体验**。此版本对构建和调试流程进行了许多重大改进

编译速度

由于 webpack 4、Babel 7 以及我们代码库中的许多改进和优化,Next.js 在开发期间的启动速度现在提高了57%。

由于我们新的增量编译缓存,您对代码所做的更改现在将以**40% 更快的速度构建**。

以下是一些我们收集到的示例数据

6.07.0变化
启动时间(基本应用)1947毫秒835毫秒57% 更快
代码更改(基本应用)304毫秒178毫秒42% 更快

作为额外福利,在开发和构建时,您现在将看到更好的实时反馈,这要归功于 webpackbar

使用 React 错误覆盖改进错误报告

渲染准确并提供帮助错误对于良好的开发和调试体验至关重要。到目前为止,我们会渲染错误消息及其堆栈跟踪。展望未来,我们使用react-error-overlay来丰富堆栈跟踪,其中包括

  • 服务器和客户端错误的准确错误位置
  • 源代码的突出显示以提供上下文
  • 完整的丰富堆栈跟踪

这是我们错误的之前和之后的对比

The previous overlay left, react-error-overlay right
之前的覆盖层在左侧,react-error-overlay在右侧

作为额外福利,react-error-overlay 通过单击特定的代码块即可轻松打开您的文本编辑器。

Webpack 4

自从首次发布以来,Next.js 一直由 webpack 驱动来捆绑您的代码并重用丰富的插件和扩展生态系统。我们很高兴地宣布 Next.js 现在由最新的 webpack 4 驱动,它带来了许多改进和错误修复。

其中包括

  • 支持.mjs源文件
  • 代码分割改进
  • 更好的tree-shaking(删除未使用的代码)支持

另一个新功能是 WebAssembly 支持,Next.js 甚至可以服务器端渲染 WebAssembly,这是一个示例

注意:此升级是**完全向后兼容的**。但是,如果您通过next.config.js使用自定义 webpack 加载器或插件,则可能需要对其进行升级。

CSS 导入

使用 webpack 4,引入了一种从捆绑包中提取 CSS 的新方法,称为 mini-extract-css-plugin

@zeit/next-css, @zeit/next-less, @zeit/next-sass, 以及 @zeit/next-stylus 现在由mini-extract-css-plugin驱动。

这些 Next.js 插件的新版本**解决了与 CSS 导入相关的 20 个现有问题**;例如,现在支持在动态import()中导入 CSS

components/my-dynamic-component.js
import './my-dynamic-component.css';
 
export default function MyDynamicComponent() {
  return <h1>My dynamic component</h1>;
}
pages/index.js

import dynamic from 'next/dynamic'
 
const MyDynamicComponent = dynamic(import('../components/my-dynamic-component'))
 
export default function Index() {
  return () {
    <div>
      <MyDynamicComponent/>
    </div>
  }
}

一个主要的改进是,您不再需要将以下内容添加到pages/_document.js

<link rel="stylesheet" href="/_next/static/style.css" />

相反,Next.js 会自动注入 CSS 文件。在生产环境中,Next.js 还会自动向 CSS URL 添加内容哈希,这样如果文件发生更改,就可以确保您的最终用户永远不会获得过时的文件版本,并能够引入不可变的永久缓存。

简而言之,要在您的 Next.js 项目中支持导入.css文件,您只需在您的next.config.js中注册withCSS插件即可。

const withCSS = require('@zeit/next-css');
module.exports = withCSS({
  /* my next config */
});

标准化的动态导入

Next.js 从 3 版本开始就支持通过next/dynamic进行动态导入。

作为这项技术的早期采用者,我们不得不编写自己的解决方案来处理import()

因此,Next.js 开始偏离 webpack 后来为其引入的支持,并且缺少一些功能。

正因为如此,Next.js 不支持 webpack 自引入以来的一些import()功能。

例如,无法手动命名和捆绑某些文件。

import(/* webpackChunkName: 'my-chunk' */ '../lib/my-library');

另一个例子是在不包含在next/dynamic模块中的情况下使用import()

从 Next.js 7 开始,我们不再触及默认的import()行为。这意味着您可以**开箱即用地获得完整的import()支持**。

此更改也完全向后兼容。使用动态组件仍然像以下一样简单

pages/index.js

import dynamic from 'next/dynamic';
 
const MyComponent = dynamic(import('../components/my-component'));
 
export default function Index() {
  return (
    <div>
      <MyComponent />
    </div>
  );
}

此示例的作用是为my-component创建一个新的 JavaScript 文件,并且仅在渲染<MyComponent />时加载它。

最重要的是,如果它没有被渲染,则初始 HTML 文档有效负载中不包含<script>标签

为了进一步简化我们的代码库并利用优秀的 React 生态系统,在 Next.js 7 中,next/dynamic被重写为在后台使用react-loadable(并进行了一些小的修改)。这也为动态组件引入了两个很棒的新功能

  • 使用next/dynamic上的timeout选项设置超时。
  • 使用next/dynamic上的delay选项设置加载组件延迟。例如,如果导入非常快,此延迟允许您的loading组件在渲染加载状态之前等待 x 时间。

Babel 7

Next.js 6 在 Babel 7 仍处于测试阶段时引入了它。从那时起,Babel 7 的稳定版本已发布,Next.js 7 现在使用此版本。

有关更改的完整列表,您可以参考 Babel 的发行说明

一些主要功能包括

  • TypeScript 支持,对于 Next.js,您可以使用@zeit/next-typescript
  • Fragment 语法<>支持
  • babel.config.js支持
  • overrides属性,用于仅将预设/插件应用于文件或目录的子集

如果您在 Next.js 项目中没有自定义 Babel 配置,则没有重大更改。

但是,如果您有自定义 Babel 配置,则必须将其相应的自定义插件/预设升级到最新版本。

如果您是从低于 Next.js 6 的版本升级,则可以使用出色的babel-upgrade工具。

除了升级到 Babel 7 之外,Next.js Babel 预设(next/babel)现在默认为在NODE_ENV设置为test时将modules选项设置为commonjs

此配置选项通常是创建 Next.js 项目中的自定义.babelrc的唯一原因

.babelrc
{
  "env": {
    "development": {
      "presets": ["next/babel"]
    },
    "production": {
      "presets": ["next/babel"]
    },
    "test": {
      "presets": [["next/babel", { "preset-env": { "modules": "commonjs" } }]]
    }
  }
}

在 Next.js 7 中,它变为

.babelrc
{
  "presets": ["next/babel"]
}

此时,可以删除.babelrc,因为当没有 Babel 配置时,Next.js 将自动使用next/babel

更小的初始 HTML 有效负载

由于 Next.js 预渲染 HTML,因此它将页面包装在一个包含<html><head><body>和渲染页面所需的 JavaScript 文件的默认结构中。

此初始有效负载之前约为 1.62kB。使用 Next.js 7,我们优化了初始 HTML 有效负载,现在为 1.5kB,减少了 7.4%,使您的页面更精简。

6.07.0变化
文档大小(服务器渲染)1.62kb1.50kb7.4% 更小

我们减少大小的主要方法是

  • 删除了__next-errordiv
  • 缩小了内联脚本,在将来的版本中,它们将被完全删除
  • 当未使用时,编译掉未使用的__NEXT_DATA__属性,例如nextExportassetPrefix属性。

静态 CDN 支持

在 Next.js 5 中,我们引入了assetPrefix支持,这是一种使 Next.js 自动从特定位置(通常是 CDN)加载资产的方法。如果您使用的 CDN 支持代理,此选项效果很好,您可以请求如下 URL:

https://cdn.example.com/_next/static/<buildid>/pages/index.js

通常,CDN 会检查其缓存中是否存在该文件,否则会直接从源服务器请求该文件。

代理资产正是Edge Network的工作原理。

但是,某些解决方案需要将目录直接预上传到 CDN。这样做的问题在于 Next.js 的 URL 结构与.next文件夹内的文件夹结构不匹配。例如,我们之前的示例

https://cdn.example.com/_next/static/<buildid>/pages/index.js
// mapped to:
.next/page/index.js

在 Next.js 7 中,我们已更改.next的目录结构以匹配 url 结构

https://cdn.example.com/_next/static/<buildid>/pages/index.js
// mapped to:
.next/static/<buildid>/pages/index.js

虽然我们确实建议使用代理类型的 CDN,但这种新结构允许不同类型 CDN 的用户将其.next目录上传到他们的 CDN。

Styled JSX v3

我们很高兴推出 styled-jsx 3,Next.js 中默认包含的 CSS-in-JS 解决方案现已准备好用于React Suspense

一个经常不清楚的事情是如何为子组件设置样式,如果该组件不是当前组件范围的一部分,例如,如果您包含一个子组件,该组件仅在父组件内部使用时才需要特定的样式

pages/index.js

const ChildComponent = () => (
  <div>
    <p>some text</p>
  </div>
);
 
export default function Index() {
  return (
    <div>
      <ChildComponent />
      <style jsx>{`
        p {
          color: black;
        }
      `}</style>
    </div>
  );
}

上面的代码尝试选择p标签不起作用,因为 styled-jsx 样式的作用域限定在当前组件,它们不会泄漏到子组件。解决此问题的一种方法是使用:global方法,从p标签中删除前缀。但是,这会引入一个新问题,即样式会泄漏到页面中。

在 styled-jsx 3 中,此问题已通过引入新的 API css.resolve得到解决,该 API 将为给定的 styled-jsx 字符串生成className<style>标签(styles属性)

pages/index.js

import css from 'styled-jsx/css';
 
const ChildComponent = ({ className }) => (
  <div>
    <p className={className}>some text</p>
  </div>
);
 
const { className, styles } = css.resolve`
  p {
    color: black;
  }
`;
 
export default function Index() {
  return (
    <div>
      <ChildComponent className={className} />
      {styles}
    </div>
  );
}

此新 API 允许透明地将自定义样式传递给子组件。

由于这是 styled-jsx 的一个主要版本,因此如果您使用styles-jsx/css,则存在一个重大更改,可以改善捆绑包大小。在 styled-jsx 2 中,即使仅使用“作用域”版本,我们也会生成外部样式的“作用域”和“全局”版本,我们仍然会包含这些外部样式的“全局”版本。

在 styled-jsx 3 中,全局样式必须使用css.global而不是css进行标记,以便 styled-jsx 优化包大小。

有关所有更改,请参阅发行说明

React Context 与 App 和 Pages 之间的 SSR

从 Next.js 7 开始,我们现在支持pages/_app.js和页面组件之间的新 React context API。

以前,无法在服务器端页面之间使用 React context。其原因是 webpack 保留了一个内部模块缓存,而不是使用 require.cache,我们编写了一个自定义 webpack 插件来更改此行为,以便在页面之间共享模块实例。

通过这样做,我们不仅允许使用新的 React context,而且还减少了在页面之间共享代码时 Next.js 的内存占用。

6.07.0变化
内存使用情况57.5MB48.1MB-16% 内存

nextjs.org

随着 Next.js 7 的发布,我们推出了一个完全重新设计的nextjs.org

博客

您当前正在阅读的博文已成为 nextjs.org 上新博客部分的一部分。此博客将成为与 Next.js 相关的通信的新家园,例如新版本公告。

The new nextjs.org
新的 nextjs.org

获取灵感

随着使用 Next.js 的应用程序数量不断增长,我们需要一种方法在一个概述中展示所有这些漂亮的应用程序。认识一下新的/showcase页面

Get inspired on nextjs.org/showcase
在 nextjs.org/showcase 上获取灵感

这个新的展示案例允许我们不断添加使用 Next.js 构建的新应用程序。

我们邀请您访问/showcase以获取灵感,或提交您使用 Next.js 的应用程序!

社区

自从首次发布以来,Next.js 已被用于从财富 500 强公司到个人博客的各种场景。我们非常高兴地看到 Next.js 的采用率在增长。

  • 目前,有超过 12,500 个公开索引的域名使用 Next.js。
  • 我们有超过 500 位贡献者至少提交了 1 次提交。
  • 在 GitHub 上,该项目获得了超过 29,000 次星标。
  • 自首次发布以来,已提交了近 2200 个拉取请求。

Next.js 社区拥有近 2000 名成员。加入我们!