在构建期间,Next.js 会自动追踪每个页面及其依赖项,以确定部署应用程序生产版本所需的所有文件。
此功能有助于大幅减小部署的规模。以前,使用 Docker 进行部署时,您需要安装包的 dependencies 中的所有文件才能运行 next start。从 Next.js 12 开始,您可以利用 .next/ 目录中的输出文件追踪(Output File Tracing)功能,只包含必要的文件。
此外,这消除了对已弃用的 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须知:
- 如果您的项目需要监听特定的端口或主机名,您可以在运行
server.js之前定义PORT或HOSTNAME环境变量。例如,运行PORT=8080 HOSTNAME=0.0.0.0 node server.js以在http://0.0.0.0:8080启动服务器。
须知:
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启动服务器。
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.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/ 下的路径,因为它们是相对于 project root 解析的。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'],
},
}这些选项适用于服务器追踪,不影响不生成服务器追踪文件的路由:
在 monorepos 中,或者当您需要包含应用程序文件夹之外的文件时,请将 outputFileTracingRoot 与 includes 结合使用:
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/**/*'],
},
}