跳到内容
返回博客

2018年9月19日,星期三

Next.js 7

发布者

经过 26 个 Canary 版本和 340 万次下载,我们很荣幸地推出生产就绪的 Next.js 7,其特性包括

最后,我们很高兴在新版的 Nextjs.org 上分享这个消息

DX 改进

Next.js 的首要目标之一是提供最佳的生产性能和尽可能最佳的开发者体验。此版本为构建和调试管道带来了许多重大改进

编译速度

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

得益于我们新的增量编译缓存,您对代码所做的更改现在将构建速度提升 40%

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

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

作为一项额外福利,在开发和构建时,由于 webpackbar,您现在将看到更好的实时反馈

使用 React Error Overlay 改进错误报告

渲染准确且有帮助的错误对于良好的开发和调试体验至关重要。到目前为止,我们只会渲染错误消息及其堆栈跟踪。展望未来,我们将使用 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 插件的新版本解决了 20 个与 CSS 导入相关的现有问题;例如,现在支持在动态 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 */
});

标准化的动态导入

自版本 3 以来,Next.js 就通过 next/dynamic 支持动态导入。

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

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

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

例如,手动命名和捆绑某些文件是不可能的

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

另一个例子是使用 import() 而不将其包装在 next/dynamic 模块中。

从 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 /> 时加载它。

最重要的是,如果未渲染,则 <script> 标签不包含在初始 HTML 文档负载中

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

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

Babel 7

Next.js 6 在 Babel 7 仍处于 beta 版时引入了它。从那时起,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)现在默认将 modules 选项设置为 commonjs,当 NODE_ENV 设置为 test 时。

此配置选项通常是在 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-error div
  • 内联脚本已缩小,在未来的版本中将完全移除
  • 当未使用时,编译掉了未使用的 __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 中,我们将生成外部样式的“scoped”和“global”版本,即使仅使用“scoped”版本,我们仍然会包含这些外部样式的“global”版本。

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

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

在 App 和 Pages 之间使用 SSR 的 React Context

从 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 次 commit。
  • 在 GitHub 上,该项目已被 star 超过 29,000 次。
  • 自首次发布以来,已提交了近 2200 个 pull request。

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