AI 年度盘点与2025发展趋势展望,50+案例解析亮相AICon 了解详情
写点什么

Next.js 7.0 正式发布:重新编译速度提高 42%,支持 WebAssembly

  • 2018-10-13
  • 本文字数:7366 字

    阅读完需:约 24 分钟

在经过 26 次金丝雀发布和 340 万次下载之后,现在,我们正式推出生产就绪的 Next.js 7。

  • DX 改进:启动速度提高 57%,重新编译速度提高 42%;
  • 使用 react-error-overlay 更好地报告错误;
  • 编译管道升级:Webpack 4 和 Babel 7;
  • 标准化的动态导入;
  • 静态 CDN 支持;
  • 较小的初始 HTML 载荷;
  • App 和 Page 之间的 React Context(服务器端渲染)。

DX 改进

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

得益于 Webpack 4 和 Babel 7,以及我们对代码库做出的很多改进和优化,Next.js 现在在开发过程中的启动速度提高了 57%。

我们新增了增量编译缓存,让变更代码的构建速度快了 40%。

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

因为使用了 webpackbar,在开发和构建的同时可以看到更好的实时反馈:

使用 react-error-overlay 更好地报告错误

准确地渲染错误对于良好的开发和调试体验来说是至关重要的。到目前为止,我们可以渲染错误消息和堆栈跟踪信息。我们在此基础上更进一步,我们使用 react-error-overlay 来丰富堆栈跟踪信息:

  • 准确的服务器端和客户端错误位置;
  • 高亮显示错误来源;
  • 完整的堆栈跟踪信息。

这是之前和之后的错误显示比较:

另外,借助 react-error-overlay,你只需单击特定代码块就可以轻松打开文本编辑器。

Webpack 4

从发布第一个版本以来,Next.js 一直使用 Webpack 来打包代码和重用丰富的插件。Next.js 现在使用了最新的 Webpack 4,其中包含很多改进和 bug 修复。

  • 支持.mjs 源文件;
  • 代码拆分改进;
  • 更好的摇树优化(删除未使用的代码)支持。

另一个新功能是支持 WebAssembly,Next.js 甚至可以进行 WebAssembly 服务器渲染,这里有一个例子

CSS 导入

因为使用了 Webpack 4,我们引入了一种从捆绑包中提取 CSS 的新方法,这个插件叫作 mini-extract-css-plugin

mini-extract-css-plugin 提供了 @zeit/next-css、@zeit/next-less、@zeit/next-sass 和 @zeit/next-stylus。

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

复制代码
// components/my-dynamic-component.js
import './my-dynamic-component.css'
export default () => <h1>My dynamic component</h1>
复制代码
// pages/index.js
import dynamic from 'next/dynamic'
const MyDynamicComponent = dynamic(import('../components/my-dynamic-component'))
export default () => <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 后来引入的一些功能,包括 import()。

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

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

另一个例子是在 next/dyanmic 模块之外使用 import()。

从 Next.js 7 开始,我们不再直接使用默认的 import(),Next.js 为我们提供了开箱即用的 import() 支持。

这个变更也是完全向后兼容的。使用动态组件非常简单:

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

这段代码的作用是为 my-component 创建一个新的 JavaScript 文件,并只在渲染 <MyComponent/> 时加载它。

最重要的是,如果没有进行渲染,<script> 标记就不会出现在初始 HTML 文档中。

为了进一步简化我们的代码库并利用优秀的 React 生态系统,在 Next.js 7 中,我们使用 react-loadable 重写了 next/dynamic 模块。这为动态组件引入了两个很棒的新特性:

  • 使用 next/dynamic 的 timeout 选项设置超时;
  • 使用 next/dynamic 的 delay 选项设置组件加载延迟。例如,如果导入非常快,可以通过这个选项让加载组件在渲染加载状态之前等待一小段时间。

Babel 7

Next.js 6 中就已经引入了 Babel 7 测试版。后来 Babel 7 稳定版本发布,现在,Next.js 7 正在使用这个新发布的稳定版 Babel 7。

一些主要特性:

  • Typescript 支持,在 Next.js 中可以使用 @zeit/next-typescript;
  • 片段语法 <> 支持;
  • 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 的唯一理由:

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

使用 Next.js 7,这将变成:

{
  "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%,让页面变得更加精简。

我们主要通过以下几种方式来缩小文件:

  • 移除 __next-error div;
  • 内联脚本被最小化,在未来的版本中,它们将被完全移除;
  • 去掉未使用的 __NEXT_DATA__ 属性,例如 nextExport 和 assetPrefix 属性。

静态 CDN 支持

在 Next.js 5 中,我们引入了 assetPrefix 支持,让 Next.js 可以自动从某个位置(通常是 CDN)加载资源。如果你的 CDN 支持代理,可以使用这种办法。你可以像这样请求资源:

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

通常,CDN 先检查缓存中是否包含这个文件,否则直接从源中请求文件。

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

https://cdn.example.com/_next/static/<buildid>/pages/index.js
// 映射到:
.next/page/index.js

在 Next.js 7 中,我们改变了.next 的目录结构,让它与 URL 结构相匹配:

https://cdn.example.com/_next/static/<buildid>/pages/index.js
// 映射到:
.next/static/<buildid>/pages/index.js

尽管我们建议使用代理类型的 CDN,但新结构也允许不同类型 CDN 的用户将.next 目录上传到 CDN。

styled-jsx 3

我们也引入了 styled-jsx 3,Next.js 的默认 CSS-in-JS 解决方案,现在已经为 React Suspense 做好了准备。

如果一个组件不属于当前组件作用域的一部分,那么该如何设置这个子组件的样式呢?例如,如果你将一个组件包含在父组件中,并只有当它被用在父组件中时才需要特定的样式:

const ChildComponent = () => <div>
  <p>some text</p>
</div>

export default () => <div>
  <ChildComponent />
  <style jsx>{`
    p { color: black }
  `}</style>
</div>

上面的代码试图选择 p 标签,但其实不起作用,因为 styled-jsx 样式被限定在当前组件,并没有泄漏到子组件中。解决这个问题的一种方法是使用:global 方法,将 p 标记的前缀移除。但这样又引入了一个新问题,即样式泄露到了整个页面中。

在 styled-jsx 3 中,通过引入一个新的 API css.resolve 解决了这个问题,它将为给定的 syled-jsx 字符串生成 className 和 <style> 标签(styles 属性):

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 () => <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 和 Page 之间的 React Context(服务器端渲染)

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

以前,我们无法在服务器端的页面之间使用 React 上下文。原因是 Webpack 保留了内部缓存模块而不是使用 require.cache,我们开发了一个自定义 Webpack 插件来改变这种行为,以便在页面之间共享模块实例。

这样我们不仅可以使用新的 React 上下文,在页面之间共享代码时还能减少 Next.js 的内存占用。

社区

从 Next.js 首次发布以来,就已获得相当多的用户,从财富 500 强公司到个人博客。我们非常高兴看到 Next.js 的采用量一直在增长。

  • 目前,超过 12,500 个被公开索引的域名在使用 Next.js。
  • 我们有超过 500 名贡献者,他们至少提交过一次代码。
  • 在 GitHub 上,这个项目已经有 29,000 个 star。
  • 自首次发布以来,已提交了大约 2200 个拉取请求。

Next.js 社区在 spectrum.chat/next-js 上拥有近 2000 名成员。

英文原文: https://nextjs.org/blog/next-7

2018-10-13 07:223174
用户头像

发布了 731 篇内容, 共 450.6 次阅读, 收获喜欢 2002 次。

关注

评论 1 条评论

发布
暂无评论
发现更多内容

国家网信办:“滴滴出行” 下架整改!

学神来啦

免费分享学习Java框架Netty的优秀图书

Java入门到架构

Java 书籍推荐

并发王者课-铂金7:整齐划一-CountDownLatch如何协调多线程的开始和结束

MetaThoughts

Java 多线程 并发

一文讲懂Hive高可用、HiveServer2高可用及Metastore高可用

白贺BaiHe

数据仓库 7月日更 HiveServer2高可用 Metastore高可用 Hive高可用

并发王者课-铂金6:青出于蓝-Condition如何把等待与通知玩出新花样

MetaThoughts

Java 多线程 并发

合肥智慧社区平台建设解决方案,平安小区建设

系统故障防不胜防?不存在的,让大佬来给你上一课!

TakinTalks稳定性社区

高可用 测试 全链路压测 测试工具 生产环境全链路压测

Serverless 崛起背后的五大挑战

Serverless Devs

Serverless

从零实现一个 k-v 存储引擎

roseduan

存储 Go 语言 KV存储引擎 存储系统

聊聊数据仓库中维度表设计的二三事

云祁

数据仓库 维度建模 7月日更

今天,「浪潮云说」直播间开讲啦!

云计算

并发王者课-铂金8:峡谷幽会-看CyclicBarrier如何跨越重峦叠嶂

MetaThoughts

Java 并发 多线

Flink 的底层API

五分钟学大数据

flink 7月日更

云图说 | 华为云医疗智能体智联大健康:AI医学影像

华为云开发者联盟

AI 医学影像 医疗智能体 华为云医疗智能体 大健康

《持之以恒的从事运动》二

Changing Lin

Java开发从二面被拒到收割阿里架构offer,我花了一年时间,复盘成功经历!

Java架构追梦

Java 阿里巴巴 架构 offer 成长笔记

Rust从0到1-Cargo-安装来自Crates.io的程序

rust cargo install

iOS开发 · iOS音视频开发 - ARKit 教学:如何搭配SceneKit来建立一个简单的ARKit Demo

iOSer

ios ios开发 ARKit iOSAR.

iOS不行?还是个人能力有限?

ios 程序员 IT 编程之路

2022秋招vue面试题+答案

buchila11

Vue Vue 3

从结构体、内存池初始化到申请释放,详细解读鸿蒙轻内核的动态内存管理

华为云开发者联盟

鸿蒙

CloudQuery 使用教程 No.4 数据查询(下)

BinTools图尔兹

dba 数据库管理工具 国产数据库 运维开发

阿里技术分享:闲鱼IM基于Flutter的移动端跨端改造实践

JackJiang

flutter 即时通讯 IM

NumPy_2021.07.05

Flychen

DDD笔记

topsion

涨薪50%,从小厂逆袭,坐上美团L8技术专家(面经+心得)

Java 编程 程序员 面试

不愧是阿里内部“SpringCloudAlibaba学习笔记”竟然在GitHub霸榜月余

Java 编程 架构 微服务

数字化转型提升太平洋保险风险治理能力

数据湖洞见

大数据

Nacos配置中心交互模型是 push 还是 pull ?你应该这么回答

程序员小富

Java 编程 程序员 分布式 nacos

阿里P8耗时半年总结的Java核心面试知识,助我轻松拿下蚂蚁offer

Java 程序员 面试 java编程 java技术宅

论文解读丨文档结构分析

华为云开发者联盟

模型 文档 文档结构分析 分割 文档结构

Next.js 7.0正式发布:重新编译速度提高42%,支持WebAssembly_JavaScript_Next.js博客_InfoQ精选文章