output
在构建过程中,Next.js 会自动追踪每个页面及其依赖项,以确定部署应用程序生产版本所需的所有文件。
此功能有助于大幅减小部署大小。以前,使用 Docker 进行部署时,您需要安装 package 的所有 `dependencies` 文件才能运行 `next start`。从 Next.js 12 开始,您可以利用 `.next/` 目录中的输出文件追踪来仅包含必要的文件。
此外,这消除了对已弃用的 `serverless` 目标的需要,该目标可能导致各种问题并创建不必要的重复。
工作原理
在 `next build` 期间,Next.js 将使用 `@vercel/nft` 静态分析 `import`、`require` 和 `fs` 用法,以确定页面可能加载的所有文件。
Next.js 的生产服务器也对其所需的文件进行了跟踪,并输出到 `.next/next-server.js.nft.json`,这可以在生产中使用。
要利用 `.next` 输出目录中发出的 `.nft.json` 文件,您可以读取每个追踪中相对于 `.nft.json` 文件的文件列表,然后将其复制到您的部署位置。
自动复制追踪文件
Next.js 可以自动创建一个 `standalone` 文件夹,其中仅复制生产部署所需的文件,包括 `node_modules` 中的选定文件。
要在 `next.config.js` 中启用此自动复制功能。
module.exports = {
output: 'standalone',
}这将在 `.next/standalone` 处创建一个文件夹,然后可以单独部署,而无需安装 `node_modules`。
此外,还会输出一个最小的 `server.js` 文件,可以代替 `next start` 使用。此最小服务器默认不复制 `public` 或 `.next/static` 文件夹,因为这些文件夹理想情况下应由 CDN 处理,尽管这些文件夹可以手动复制到 `standalone/public` 和 `standalone/.next/static` 文件夹中,之后 `server.js` 文件将自动提供这些文件。
要手动复制这些文件,您可以在 `next build` 之后使用 `cp` 命令行工具。
cp -r public .next/standalone/ && cp -r .next/static .next/standalone/.next/要在本地启动您的最小 `server.js` 文件,请运行以下命令。
node .next/standalone/server.js须知:
- `next.config.js` 在 `next build` 期间读取并序列化到 `server.js` 输出文件中。
- 如果您的项目需要监听特定的端口或主机名,您可以在运行 `server.js` 之前定义 `PORT` 或 `HOSTNAME` 环境变量。例如,运行 `PORT=8080 HOSTNAME=0.0.0.0 node server.js` 以在 `http://0.0.0.0:8080` 上启动服务器。
注意事项
- 在 monorepo 设置中进行追踪时,项目目录默认用于追踪。对于 `next build packages/web-app`,`packages/web-app` 将是追踪根目录,此文件夹之外的任何文件都不会被包含。要包含此文件夹之外的文件,您可以在 `next.config.js` 中设置 `outputFileTracingRoot`。
const path = require('path')
module.exports = {
// this includes files from the monorepo base two directories up
outputFileTracingRoot: path.join(__dirname, '../../'),
}- 在某些情况下,Next.js 可能无法包含所需文件,或者可能错误地包含了未使用的文件。在这些情况下,您可以在 `next.config.js` 中分别利用 `outputFileTracingExcludes` 和 `outputFileTracingIncludes`。每个选项都接受一个对象,其键是**路由 glob**(使用 picomatch 针对路由路径进行匹配,例如 `'/api/hello'`),其值是**从项目根目录解析的 glob 模式**,用于指定要包含或排除在跟踪中的文件。
须知:在 monorepo 中,`project root` 指的是 Next.js 项目根目录(包含 next.config.js 的文件夹,例如 packages/web-app),不一定是 monorepo 根目录。
module.exports = {
outputFileTracingExcludes: {
'/api/hello': ['./un-necessary-folder/**/*'],
},
outputFileTracingIncludes: {
'/api/another': ['./necessary-folder/**/*'],
'/api/login/\\[\\[\\.\\.\\.slug\\]\\]': [
'./node_modules/aws-crt/dist/bin/**/*',
],
},
}使用 `src/` 目录并不会改变您编写这些选项的方式。
- 键仍然匹配路由路径(`'/api/hello'`、`'/products/[id]'` 等)。
- 值可以引用 `src/` 下的路径,因为它们是相对于项目根目录解析的。
module.exports = {
outputFileTracingIncludes: {
'/products/*': ['src/lib/payments/**/*'],
'/*': ['src/config/runtime/**/*.json'],
},
outputFileTracingExcludes: {
'/api/*': ['src/temp/**/*', 'public/large-logs/**/*'],
},
}您还可以使用全局键(例如 `/*`)来定位所有路由。
module.exports = {
outputFileTracingIncludes: {
'/*': ['src/i18n/locales/**/*.json'],
},
}这些选项适用于服务器追踪,不影响不生成服务器追踪文件的路由。
- Edge Runtime 路由不受影响。
- 完全静态的页面不受影响。
在 Monorepo 或需要包含应用程序文件夹之外的文件时,将 `outputFileTracingRoot` 与 include 结合使用。
const path = require('path')
module.exports = {
// Trace from the monorepo root
outputFileTracingRoot: path.join(__dirname, '../../'),
outputFileTracingIncludes: {
'/route1': ['../shared/assets/**/*'],
},
}须知:
- 为实现跨平台兼容性,在模式中优先使用正斜杠(`/`)。
- 尽可能缩小模式范围,以避免过大的跟踪文件(避免在仓库根目录使用 `**/*`)。
本机/运行时资产的常见包含模式。
module.exports = {
outputFileTracingIncludes: {
'/*': ['node_modules/sharp/**/*', 'node_modules/aws-crt/dist/bin/**/*'],
},
}这有帮助吗?