2018 年 2 月 5 日,星期一
Next.js 5:通用 Webpack、CSS 导入、插件和区域
发布者我们非常高兴向世界介绍 Next.js 5.0。它已在 npm 上发布并立即生效。要升级,请运行
npm i next@latest react@latest react-dom@latest
除了升级 Next.js 之外,我们还升级了对等依赖项
react
和react-dom
Next.js 是一个用于通用、服务器渲染(或静态预渲染)React.js 应用程序的工具包。开始开发任何规模的应用程序都非常容易,只需执行 next
即可。(阅读更多。)
每次发布新版本时,我们都致力于保持向后兼容性,提供简单的升级路径,并且仅在绝对必要时才进行 API 更改。Next.js 5.0 也不例外。
然而,在底层,Next.js 经历了彻底的转型,以实现强大的新用例和可扩展性。我们首先让 Next.js 为服务器和客户端代码共享通用的 Webpack 管道。
通用 Webpack 和 Next 插件
Next.js 利用了 Webpack、Babel 和 Uglify 等现有的强大工具,并以非常简单的界面呈现给最终用户:next
(用于开发)、next build
(用于生产准备)和 next start
(用于服务)或 next export
(用于预渲染为静态文件)。
我们早期做出的决定之一是为如何配置这些工具提供非常强大的可扩展点。我们不仅希望易于使用,还希望能够灵活地扩展工具包,满足您的任何需求。
例如,您可以通过在 next.config.js
中设置 webpack
属性来扩展 Next.js webpack 配置。
由于 webpack 在生产环境和开发环境中执行方式不同,因此我们当时决定将其设为一个函数,用于装饰我们的默认 webpack 配置
module.exports = {
webpack(config, { dev }) {
// modify it!
return config;
},
};
可选的
next.config.js
文件示例
但是,Webpack 只会在客户端(浏览器)捆绑包上执行,并且您将错过使用这个出色的工具链进行服务器端渲染的可能性。
我们很高兴地宣布,我们已经广泛重构了我们的代码库,以使 Webpack 通用化。
从您的角度来看,所有更改只是在上面的装饰器函数中传递了一个额外的 isServer
属性。但是,新的语义意味着现在您可以广泛使用 Webpack 加载器生态系统。
CSS、LESS、SASS、SCSS 和 CSS Modules
我们最受用户欢迎的功能之一是能够导入 CSS 文件并利用 Webpack 加载器
import './index.css';
export default function Index() {
return (
<div>
<p>I love CSS!</p>
</div>
);
}
一个示例页面 (
pages/index.js
) 使用 CSS 导入,这要归功于通用 Webpack
为了使此功能生效,您可以将所需的加载器作为对等依赖项引入
npm i --save css-loader style-loader postcss-loader
Next.js 让您可以自由选择所需的加载器,并随意将其升级到不同的版本。
然后扩展配置以配置您的加载器。在 next.config.js
中
module.exports = {
webpack(config, options) {
const { dev, isServer } = options;
const extractCSSPlugin = new ExtractTextPlugin({
filename: 'static/style.css',
disable: dev,
});
config.module.rules.push({
test: /\\.css$/,
use: cssLoaderConfig(extractCSSPlugin, {
cssModules,
dev,
isServer,
}),
});
return config;
},
};
扩展原始 webpack 配置为您提供了极大的灵活性和控制权
虽然我们的一般建议是使用组件本地样式解决方案,例如包含的 styled-jsx
babel 插件,但我们认为 CSS 加载器具有许多重要的优势,例如可以轻松重用现有的 CSS 代码库,并大大简化将旧代码库迁移到 Next.js 的过程。
我们没有默认启用所有可以想象到的功能和加载器,而是引入了 Next.js 插件,它们是装饰您的配置的简单函数。您无需像上面那样手动扩展配置来设置加载器,只需执行以下操作即可
const withCss = require('next-css');
module.exports = withCss({
/* extra optional config */
});
启用导入
.css
文件所需的全部操作是引入next-css
阅读有关 CSS 加载器 在 Next.JS 中的用法,或参考我们已为您创建的一些软件包
我们的目标是授权社区开发和发展实用的简单扩展生态系统。为此,我们开放了 next-plugins monorepo,供 Next.js 社区维护。欢迎所有 PR!
TypeScript 支持
TypeScript 是 JavaScript 生态系统中增长最快的技术之一。以至于它正在成为 Babel 7 的官方支持,这意味着只需自定义您的 .babelrc,Next.js 自然会支持它。
与此同时,得益于我们新的通用 Webpack 支持,您今天已经可以获得完整的 TypeScript 支持!
您可以像这样扩展您的 webpack 配置
module.exports = {
webpack(config, options) {
const { dir, defaultLoaders } = options;
config.resolve.extensions.push('.ts', '.tsx');
config.module.rules.push({
test: /\\.+(ts|tsx)$/,
include: [dir],
exclude: /node_modules/,
use: [
defaultLoaders.babel,
{ loader: 'ts-loader', options: { transpileOnly: true } },
],
});
return config;
},
};
我们所要做的就是启用
ts-loader
与 CSS 加载器和预处理器一样,TypeScript 一直是最受用户欢迎的功能之一。为了使其像其他任何加载器一样轻松地集成到项目中,我们现在有一个 next-typescript
插件,您可以将其包含在您的 next.config.js
文件中
const withTs = require('next-typescript');
module.exports = withTs({
/* additional config*/
});
插件可以轻松组合:它们只是函数
更好地支持 React Altlibs 和模块重载
随着时间的推移,涌现了许多 React 的直接替代实现。其中一些值得注意的包括 [preact
](https://preact.reactjs.ac.cn/)、nervjs
和 inferno
。
其他库专注于替换 DOM 渲染器,例如 react-dom-lite
,它的目标是通过在浏览器兼容性方面做出一些小的权衡来创建一个更小的 React 构建。
通用 Webpack 支持使将这些库作为直接替代品合并的过程更加容易。与其他插件类似,这就是您使用 preact 使用 Next.js 所需做的全部操作
npm i @zeit/next-preact preact preact-compat
我们安装 preact 插件和必要的对等依赖项
const withPreact = require('@zeit/next-preact');
module.exports = withPreact();
我们的新
next.config.js
已为 preact 做好准备
查看非常简单的 @zeit/next-preact 模块或创建您自己的模块!
生产环境中的可选外部 Sourcemaps
现在 Next.js 将 webpack 用于客户端和服务器代码,在生产构建中启用 source-maps 只需对其配置进行微小的调整。
在开发环境中,source map 是自动启用的,因此我们针对生产环境对其进行不同的配置
module.exports = {
webpack(config, { dev }) {
if (!dev) {
config.devtool = 'source-map';
}
return config;
},
};
当不在开发环境中时,我们只需配置不同的
devtool
选项
区域
从一开始,Next.js 的既定目标之一就是恢复并保留 Web 的简洁性。
服务器端渲染、一种简单且不可知的获取数据方法以及基于文件系统结构的声明式页面是我们根据这种想法引入的一些功能。
Web 服务和网站经常被忽视的一个方面是它们天然的可组合性和可扩展性。
例如,mydomain.com/settings
和 mydomain.com/
可能是两个完全不同的应用程序,它们可以独立部署、独立扩展,甚至可以运行同一软件的不同版本。
将它们“粘合在一起”,为最终用户提供统一体验所需的全部操作是后端路由层或负载均衡器的一些简单配置,将它们暴露给世界。我们现在非常高兴能够带来使用 Next.js 构建的组合多个应用程序的能力,这些应用程序使用普通的 <Link>
组件连接在一起。我们将此功能称为区域。
例如,考虑以下两个独立的 Next.js 应用程序,它们部署到 Vercel
- https://front.vercel.app
- https://zeit-docs-zbqbsrucga.vercel.app/docs https://zeit-docs-zbqbsrucga.vercel.app/api

当我们改进我们的文档时,我们希望尽可能轻松地接受社区贡献。
我们决定将文档“迷你网站”拆分到其自己的存储库中。此外,每当提交拉取请求并提出更改时,我们都会自动隔离部署它

我们最终得到的是两个区域,它们使用我们的路径别名功能汇集到父域 https://vercel.com
中。它看起来像这样
{
"rules": [
{ "pathname": "/docs", "dest": "our-docs.vercel.app" },
{ "pathname": "/api", "dest": "our-docs.vercel.app" },
{ "dest": "my-main-website.vercel.app" }
]
}
这些简单的规则允许您将微服务和区域组合在一起
剩下的就是调用 now alias
命令
now alias -r rules.json my-domain.com
我们的使命是使部署尽可能通用和开放。为了帮助本地开发,我们最近开源了 micro-proxy
,这是一个使用与上面看到的相同配置格式的工具。
您也可以使用其他解决方案(如 Nginx、HAProxy 或 API Gateway)将区域连接在一起。
更快的生产构建时间
我们认为开发者体验和用户体验是息息相关的。编写、测试和部署更改的效率越高,添加新功能、修复错误和改善整体用户体验的速度就越快。
因此,我们仍然专注于不断迭代系统最基本构建模块的性能配置文件。
使用 Next.js 5.0,我们有机会再次审视 next build
,这是您在部署到生产环境或将 Next.js 应用程序导出为静态站点之前运行的命令。
我们很高兴地报告,对于 vercel.com,一个由数千个组件组成的 React 应用程序,我们已经看到 Next.js 5.0 带来了非常显著的改进,生产构建时间加快了 23.6%

改进了动态导入的缓存
每当您使用动态 import()
时,这都会向 WebPack 发出信号,表明存在新的代码拆分入口点。
在构建时,这意味着为模块的相应子树生成特定的捆绑包。
在 Next.js 5.0 之前,动态捆绑包将收到类似于以下的 URL
/_next/1517592683901/webpack/chunks/components_hello1_1345d10fc951cd6717c5676c467579a6.js
现在,我们将动态导入转换为子树内容的基于内容的哈希值
/_next/webpack/chunks/components_hello1_1345d10fc951cd6717c5676c467579a6-b7874680a9e21fb6eb89.js
这意味着在跨部署时,您的用户和客户无需不必要地重新下载他们已经使用过的代码。
片段
Next.js 构建了一个顶级的 <Document>
组件,该组件与每个页面一起进行服务器端渲染。重载此组件使您可以完全控制标记,从而实现许多高级用例。
初始标记的一部分是 Next.js 需要在客户端评估的脚本列表。自定义 _document
看起来像这样
import Document, { Head, Main, NextScript } from 'next/document';
export default class extends Document {
render() {
return (
<html>
<Head />
<body>
<Main />
<NextScript />
</body>
</html>
);
}
}
Document
允许您自定义页面的整个服务器端渲染输出
直到最近,我们还被迫将脚本包装在 <div>
中。
使用 Next.js 5.0,我们现在利用了新的 Fragment
支持,这转化为更轻量级的页面,并完全控制页面的样式,而没有多余的标记。
更准确的错误信息
Node.js 不支持 source map,服务器端发生的错误会附带指向已编译代码的堆栈跟踪。
在 Next 5 中,我们改进了服务器端的 source map 支持。服务器端渲染时发生的错误现在指向正确的函数和行号。

结论
通用 Webpack 巩固了 Next.js 的基础,使其更具面向未来的特性。总的来说,不再有人为地将插件或加载器区分为哪些适用于 Next.js,哪些不适用。
本着零配置的精神,我们很高兴推出 Next 插件,这是一个社区存储库,用于自动扩展 Next.js 功能的配方,而无需调整特定的旋钮。
有了这个,我们现在支持 CSS 解决方案的整个范围,编译为 js 的语言(如 TypeScript)和 React 替代方案(如 Nerve),只需引入一个额外的模块并在 next.config.js
中明确包含它即可。简单而不晦涩。
区域允许互连并非根植于同一存储库甚至服务器的 Next.js 应用程序。我们认为这是“团队可扩展性”类别改进中非常重要的里程碑。
因此,Next.js 成为由多个团队维护的大型应用程序的绝佳选择。他们现在可以同时部署改进,减少错误面,提高迭代速度,甚至可以尝试除我们核心之外的不同技术,例如许多不同的状态管理或数据获取方法。
我们要借此机会感谢 Deep Varma 和 Trulia 工程团队,他们贡献了关键的见解、代码和测试,从而促成了此功能的设计。
与往常一样,如果没有许多开源贡献者和我们出色的社区,此版本是不可能实现的。