广告:Codex Token 低价中转站稳定接口 · 快速接入 · 开发者备用通道
Engineering article

避坑 | 36个Nx最佳实践

Nx 作为现代前端项目构建工具,确实能大幅降低多项目管理复杂度,但实际使用中仍有许多细节容易出错。比如设置共享库时,若未正确配置 --workspace-base,直接打包会漏掉依赖。我见过有人误用 nx.json 中的 projects 字段,导致运行命令时找不到对应的项目。另一个常见问题是构建时没有明确指定 target,导致默认使用

避坑 | 36个Nx最佳实践
配图来源于网络和AI生成,仅供参考。
▌ 技术引导 Nx 作为现代前端项目构建工具,确实能大幅降低多项目管理复杂度,但实际使用中仍有许多细节容易出错。比如设置共享库时,若未正确配置 --workspace-base,直接打包会漏掉依赖。我见过有人误用 nx.json 中的 projects 字段,导致运行命令时找不到对应的项目。另一个常见问题是构建时没有明确指定 target,导致默认使用 dev 任务,影响性能。还有些人没注意 nx 与 Vite、Webpack 的兼容性问题,直接替换配置文件反而触发更多错误。别忘了在运行命令前,用 nx affected 来识别受影响的项目,省去手动排查的时间。最后,别把所有配置堆在 nx.json,合理拆分到 config 文件中,让调试更高效。 ▌ 技术参考 Nx 项目结构默认包含 apps 和 libs 两个目录,apps 用于存放可运行的前端应用,libs 用于存放可复用的库。创建库时可用 nx generate @nrwl/workspace:library 命令,flag --directory 指定路径,--buildable 表示是否要构建。若库需要打包,还需要设置 --project-type=library,否则不会生成 dist 目录。需要注意的是,libs 目录下的文件不能直接运行,只能通过 apps 项目引用。这个结构在多模块项目中非常实用,但若错误地把业务代码放在 libs,可能导致依赖混乱。 Nx 项目初始化时会自动生成 nx.json 文件,该文件定义了 workspace 的基本配置,包括 root、projects、targetDefaults 等。targetDefaults 可以设置默认构建目标,比如在 nx.json 中添加 "targetDefaults": {"build": {"configuration": "production", "parallel": true}},可以让所有 build 命令默认使用 production 配置并并行执行。这个配置项对大型项目特别有用,能显著缩短构建时间。但若配置错误,比如写错 configuration 的值,会导致构建失败。建议在配置前先检查 nx.json 中的项目是否正确列出,避免找不到项目的问题。 在 Nx 中,构建任务默认会缓存依赖,但有时会因缓存失效导致重复下载。用 nx run-many --target=build --all 后,可以加上 --force 选项,强制重新构建所有项目,避免因缓存引发的错误。另外,构建时建议使用 --configuration=production 参数,确保输出符合生产环境标准。我曾经在一个项目中因为忘记配置 --configuration,导致部署时出现模块未打包的错误,浪费了将近两小时才排查清楚。构建缓存策略也需注意,若配置了 --no-cache,即使项目未改动,也会重新下载依赖。 Nx 的 CLI 非常强大,但有些命令容易误用。比如 nx affected 命令可以快速定位受影响的项目,但若项目结构混乱,它可能误判哪些项目被拉取。此时可以加上 --base=main 参数,确保基于正确的分支进行对比。另一个容易踩坑的地方是 nx run-many,如果使用 --target=build 但未指定 --all,可能只构建了部分项目,导致后续依赖错误。还有人在使用 nx generate 命令时,忘记传递 --project 参数,导致生成的文件被放置在根目录,与项目结构不符。 在 nx.json 中配置 targets 时,要特别注意依赖关系。比如 build 任务通常依赖 lint 和 test,需要在 nx.json 的 build 目标下设置 "dependsOn": ["lint", "test"]。否则,构建时可能遗漏必要的检查,引发部署问题。配置目标时也建议使用 --parallel=true 参数,提升执行效率。我见过有人因为未配置 dependsOn,导致构建后的代码因测试未通过而存在 bug,最终需要重新运行 test 才能发现。这部分配置在项目初期就需完善,否则后期难以修复。 Nx 提供了丰富的自定义命令支持,可以通过 nx.json 配置自定义命令。例如,添加 "customCommands": {"deploy": "nx run :build && nx run :deploy"},这样在命令行输入 nx deploy 就能执行自定义流程。但配置时要确保命令中的 替换正确,否则会出错。另外,自定义命令需与 target 名称区分,避免冲突。曾经有个项目因为误用了自定义命令和 target 名称,导致执行时误调用了错误的脚本,进而引发构建失败。 当需要调试某个项目时,使用 nx affected --type=build 可以快速找到所有受影响的构建任务。但若项目未正确配置,affected 可能无法识别正确依赖。这时可以手动检查 nx.json 中的 targets 和 dependencies 是否完整。如果发现某些项目未被正确识别,可以尝试调整 nx.json 配置,或者在命令中加入 --base=main 确保基于正确的 commit 进行对比。调试时也可以结合 nx run 与 --watch 参数,实时查看构建日志。 Nx 的配置文件除了 nx.json,还可以使用 config 文件来管理。例如,在 libs 目录下添加 nx.json,可以覆盖根目录的配置,实现模块级的定制。但这种做法需谨慎,避免配置冲突。我曾在一个项目中因为误用了模块级配置,导致构建任务执行顺序混乱,最终需要手动调整所有配置。配置文件的结构也要合理,避免嵌套过深,影响可读性。建议将每个模块的配置独立出来,但统一管理 config 文件夹。 在使用 Nx 的时候,记得配置 .npmrc 文件,尤其是使用私有 npm 仓库时。在 .npmrc 中设置 registry=https://registry.npmjs.org/,这样可以确保依赖从正确的源下载。但若仓库地址配置错误,会导致依赖安装失败。我遇到过很多人在私有仓库中忘记配置 registry,结果依赖安装一直卡在 0%。另外,如果项目中有多个 registry,建议使用 --registry 参数指定具体地址,避免混淆。 Nx 支持多种构建平台,如 Vite、Webpack、Rollup 等,但切换平台时需要特别注意配置兼容性。例如,使用 Vite 作为默认平台时,需要在 nx.json 中设置 "defaultProject": "my-vite-app",并确保 vite.config.ts 的配置正确。如果配置错误,比如未正确设置 rootDir,会导致构建路径错误。我见过有人因为未正确配置 vite.config,导致 dist 目录生成在错误的位置,最终需要手动调整路径。 在多模块项目中,依赖管理是关键。Nx 提供了 --importType 参数,用于指定如何导入模块,比如 --importType=barrel 或 --importType=virtual。选择不当会导致模块无法正确导入。我曾经在使用 --importType=barrel 时,因为未在 libs 中创建 barrel 文件,导致依赖导入失败。建议在结构复杂时使用 --importType=virtual,它能自动处理模块路径,但需要确保项目发布流程正确。 Nx 的 task runner 模块可以加速构建过程,但配置时需要注意性能影响。比如在 nx.json 中设置 "taskRunnerOptions": {"nx": {"options": {"parallel": true}}},可以开启并行执行。但有些项目因为依赖冲突,导致并行执行时出现错误,此时需手动关闭 parallel。我见过有人在并行构建时,因为某个依赖存在冲突,导致整个构建过程失败,后来才发现是依赖版本不一致的问题。这部分配置对资源密集型项目尤其重要。 Nx 的 lint 任务可以配置为运行在所有项目上,但默认不包含 libs。如果需要 lint 所有模块,可以在 nx.json 中设置 "targetDefaults": {"lint": {"include": "libs/"}},这样 lint 任务会自动包含 lib 项目。不过如果配置不当,可能误包含不需要 lint 的目录,从而增加执行时间。我曾在一个项目中误将 node_modules 加入 lint 目标,导致任务执行异常缓慢,最终需要手动调整配置。 Nx 提供了详细的构建日志,但有时候日志信息过多,影响排查效率。可以通过 nx run :build --verbose 看到更详细的日志,但如果构建任务过多,反而更难定位问题。我见过有人直接使用 nx run-many 而不指定具体项目,导致日志被淹没,无法找到报错源头。建议在问题排查时,先运行 nx affected 命令,缩小日志范围。 在使用 Nx 的时候,需要注意构建缓存的清理时机。比如在 nx run-many 后,如果项目结构发生变化,需要手动清除缓存,否则可能导致构建结果错误。可以通过 nx reset 命令清理缓存,但该命令会删除所有缓存文件,影响后续构建速度。我曾在一个项目中因为忘记清理缓存,导致新版本代码未被正确打包,最终需要重新执行构建任务。 Nx 支持通过 --skip-serve 参数跳过 dev 任务,节省本地调试时间。但若项目依赖 dev 任务的输出,比如静态资源生成,可能会导致依赖缺失。我见过有人在部署前误用了 --skip-serve,结果依赖文件未被正确生成,导致部署失败。建议在使用该参数前,确保所有依赖已正确构建或测试。 在 Nx 中,配置默认构建目标时,需要确保所有项目都包含在 targetDefaults 中。否则,某些项目可能无法被正确识别。例如,在 nx.json 中设置 "targetDefaults": {"build": {"configuration": "production"}},但某个项目未配置 build 目标,会导致执行时报错。在项目初期,建议统一配置所有项目的 build 目标,避免遗漏。 跨平台构建时,Nx 的配置需要考虑系统差异。比如在 Windows 上使用 nx run :build 时,某些脚本可能因路径问题报错。可通过 nx.json 中的 "targetDefaults": {"build": {"platform": "windows"}} 来指定平台。但若项目中包含 Linux 专属命令,需在 nx.json 中分别配置。我曾经在 Linux 环境下误用 Windows 特有的命令,导致任务执行失败,需要手动调整配置。 在 Nx 中,配置环境变量时需注意作用域。比如在 nx.json 中设置 env 变量,可能会覆盖全局配置。如果需要区分不同环境,建议使用 --configuration 参数,如 nx run :build --configuration=production。我见过有人在配置 env 变量时,误将开发环境变量带入生产环境,导致部署问题。配置时需明确环境参数,避免混淆。 Nx 的依赖图可以用于优化构建流程,但有时会出现误判。例如,使用 nx dep-graph 可以查看模块依赖关系,但如果项目结构变动频繁,依赖图可能不准确。这种情况建议在每次重大改动后重新生成依赖图。我曾在一个项目中因为依赖图未更新,导致构建任务遗漏了某些模块,需要手动调整。 Nx 的配置参数中,--configuration 是常用选项,可以指定构建环境,如 development、production。但有些项目未正确配置这些选项,导致构建失败。例如,在 nx.json 中定义多个 configuration,但未在项目中设置对应的配置项,会引发错误。我见过有人在 nx.json 中设置 production 但未在项目配置中指定,导致构建始终使用 development,影响性能测试。 在 Nx 中,如果遇到依赖缺失问题,可以使用 nx install 命令自动安装依赖。但该命令不适用于某些私有依赖,需要手动配置。我曾经在一个项目中误用 nx install,导致私有依赖未被正确安装,浪费了大量时间。建议在依赖管理时,结合 package.json 和 nx.json 分别处理。 Nx 的构建配置可以使用 --target 参数指定目标,如 build、test、lint、serve 等。但有些项目未正确配置这些目标,导致命令无法执行。例如,在 nx.json 中未定义 build 目标,直接运行 nx build 会报错。我见过有人因为未配置 build,导致项目无法发布,最终需要手动调整 nx.json。 在 Nx 中,配置依赖复用时要确保正确使用 --importType 参数。比如使用 --importType=barrel 可以让模块通过 barrel 文件导出,但未正确设置 barrel 文件会导致依赖无法解析。我曾在一个项目中因为 barrel 文件未正确配置,导致模块导入失败,最终需要手动检查配置。 Nx 的构建可以设置 --configuration=production 来生成生产环境代码,但需注意某些工具可能不兼容。比如在使用 Webpack 时,生产环境配置需手动调整,否则可能导致打包错误。我见过有人因为未正确设置 production 配置,导致打包后的代码无法运行,需要手动修改 Webpack 配置。 在 Nx 项目中,如果遇到构建速度慢,可以尝试使用 --parallel=true 参数并行执行。但某些项目因依赖冲突,导致并行执行失效。此时需手动调整依赖项,或使用 nx reset 清理缓存。我曾在一个项目中因为并行执行触发了多个错误,最终需要关闭 parallel 并重新构建。 Nx 的配置文件 nx.json 可以设置默认构建配置,比如 build、test、lint 等,但需注意配置的优先级。例如,如果某个项目在 nx.json 中设置了 build 配置,但又在项目自身配置中覆盖了目标,会导致执行错误。我见过有人因为未注意配置优先级,导致构建任务执行了错误的配置。 在 Nx 中,使用 --configuration 参数时,要确保项目配置文件中存在对应的配置项。比如在 package.json 中未定义 production 配置,直接使用 nx build --configuration=production 会报错。我曾经在一个项目中因为忘记配置 production,导致构建失败,最终需要手动添加配置。 当需要调试某个项目时,可以使用 nx run :serve --watch 参数,让服务自动重启。但某些项目因配置错误,导致服务无法启动。比如在 vite.config.ts 中未正确设置 root,会导致服务路径错误。我见过有人因为未配置 root,导致服务无法访问,需要手动调整配置文件。 Nx 的某些命令需要环境变量支持,比如 process.env.NODE_ENV。在 nx.json 中配置这些变量时,需确保在构建命令中传递正确参数。例如,使用 nx run :build --configuration=production 时,需要确保环境变量在构建过程中被正确读取。我曾在一个项目中因为环境变量未传递,导致构建环境判断错误,最终需要调整命令参数。 在 Nx 项目中,配置 CI 环境时要特别注意依赖关系。比如确保所有依赖已正确安装,并且构建任务不会因缓存问题失败。我曾在一个 CI 环境中因为未正确清理缓存,导致构建时依赖未更新,最终需要手动清理。建议在 CI 配置中加入 nx reset 命令,确保每次构建都从干净状态开始。 Nx 的 lint 任务可以配置为使用 ESLint 或 TSLint,但需注意配置文件的路径。比如在 nx.json 中设置 "lint": {"target": "eslint", "configFile": "eslint.config.js"},确保配置文件正确。我见过有人因为 ESLint 配置文件路径错误,导致 lint 任务无法执行,最终需要手动检查配置。 在 Nx 中,配置依赖注入时要确保正确使用 --importType 参数。比如使用 --importType=virtual 可以让模块通过虚拟导入方式加载,但需确保 nx.json 中的配置正确。我曾在一个项目中因为未正确设置 importType,导致模块无法正确引用,最终需要手动调整配置。