跳到内容
返回博客

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');

另一个示例是在不包装在 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 /> 时加载它。

最重要的是,如果未渲染,则 <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 之外,当 NODE_ENV 设置为 test 时,Next.js Babel 预设 (next/babel) 现在默认将 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-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 中,我们将生成外部样式的“作用域”和“全局”版本,即使仅使用“作用域”版本,我们仍然会包含这些外部样式的“全局”版本。

使用 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 上获取灵感

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

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

社区

自从首次发布以来,Next.js 已被应用于从财富 500 强公司到个人博客的各种领域。我们很高兴看到 Next.js 的采用率不断增长。

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

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