2018年9月19日,星期三
Next.js 7
发布者经过26个候选版本发布和340万次下载,我们很自豪地推出可用于生产环境的 Next.js 7,其特色包括
- 开发体验改进:启动速度提升57%,重新编译速度提升42%
- 改进的错误报告 使用 react-error-overlay
- 升级的编译流程:Webpack 4 和 Babel 7
- 标准化的动态导入
- 静态CDN支持
- 更小的初始HTML负载
- 在App和Pages之间使用React Context进行服务器端渲染
最后,我们很高兴能够在全新的Nextjs.org上分享这一消息
开发体验改进
Next.js 的主要目标之一是提供最佳的生产性能和**尽可能好的开发体验**。此版本对构建和调试流程进行了许多重大改进
编译速度
由于 webpack 4、Babel 7 以及我们代码库中的许多改进和优化,Next.js 在开发期间的启动速度现在提高了57%。
由于我们新的增量编译缓存,您对代码所做的更改现在将以**40% 更快的速度构建**。
以下是一些我们收集到的示例数据
6.0 | 7.0 | 变化 | |
---|---|---|---|
启动时间(基本应用) | 1947毫秒 | 835毫秒 | 57% 更快 |
代码更改(基本应用) | 304毫秒 | 178毫秒 | 42% 更快 |
作为额外福利,在开发和构建时,您现在将看到更好的实时反馈,这要归功于 webpackbar
使用 React 错误覆盖改进错误报告
渲染准确并提供帮助错误对于良好的开发和调试体验至关重要。到目前为止,我们会渲染错误消息及其堆栈跟踪。展望未来,我们使用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
import './my-dynamic-component.css';
export default function MyDynamicComponent() {
return <h1>My dynamic component</h1>;
}
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()支持**。
此更改也完全向后兼容。使用动态组件仍然像以下一样简单
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
的唯一原因
{
"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%,使您的页面更精简。
6.0 | 7.0 | 变化 | |
---|---|---|---|
文档大小(服务器渲染) | 1.62kb | 1.50kb | 7.4% 更小 |
我们减少大小的主要方法是
- 删除了
__next-error
div - 缩小了内联脚本,在将来的版本中,它们将被完全删除
- 当未使用时,编译掉未使用的
__NEXT_DATA__
属性,例如nextExport
和assetPrefix
属性。
静态 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。
一个经常不清楚的事情是如何为子组件设置样式,如果该组件不是当前组件范围的一部分,例如,如果您包含一个子组件,该组件仅在父组件内部使用时才需要特定的样式
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
属性)
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.0 | 7.0 | 变化 | |
---|---|---|---|
内存使用情况 | 57.5MB | 48.1MB | -16% 内存 |
nextjs.org
随着 Next.js 7 的发布,我们推出了一个完全重新设计的nextjs.org。
博客
您当前正在阅读的博文已成为 nextjs.org 上新博客部分的一部分。此博客将成为与 Next.js 相关的通信的新家园,例如新版本公告。
获取灵感
随着使用 Next.js 的应用程序数量不断增长,我们需要一种方法在一个概述中展示所有这些漂亮的应用程序。认识一下新的/showcase
页面
这个新的展示案例允许我们不断添加使用 Next.js 构建的新应用程序。
我们邀请您访问/showcase
以获取灵感,或提交您使用 Next.js 的应用程序!
社区
自从首次发布以来,Next.js 已被用于从财富 500 强公司到个人博客的各种场景。我们非常高兴地看到 Next.js 的采用率在增长。
- 目前,有超过 12,500 个公开索引的域名使用 Next.js。
- 我们有超过 500 位贡献者至少提交了 1 次提交。
- 在 GitHub 上,该项目获得了超过 29,000 次星标。
- 自首次发布以来,已提交了近 2200 个拉取请求。
Next.js 社区拥有近 2000 名成员。加入我们!