ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于 nx import 迁移 Next.js 项目到 Nx Monorepo:目标推断、TypeScript 配置与全量修复实战指南

基于 nx import 迁移 Next.js 项目到 Nx Monorepo:目标推断、TypeScript 配置与全量修复实战指南 基于 nx import 迁移 Next.js 项目到 Nx Monorepo目标推断、TypeScript 配置与全量修复实战指南【免费下载链接】nxThe Monorepo Platform that amplifies both developers and AI agents. Nx optimizes your builds, scales your CI, and fixes failed PRs automatically. Ship in half the time.项目地址: https://gitcode.com/GitHub_Trending/nx/nx本文是.opencode/skills/nx-import技能中 NEXT.md 的完整展开聚焦nx import在导入 Next.js 项目时的专项问题nx/next/plugin的目标推断机制、withNx包装、TypeScript 配置冲突、npm scripts 重写以及 Nx 源CNW next preset与非 Nx 源create-next-app两种导入路径的完整修复顺序。读完你将能独立把 Next.js 应用含与 Vite 混布的 workspace迁移进 Nx并让typecheck / build / test / lint全绿。nx import是 Nx 提供的把外部仓库或仓库子目录导入到当前 workspace 的命令。当目标源项目是 Next.js 时除了 SKILL.md 中描述的通用问题pnpm globs、根依赖、项目引用、名称冲突、ESLint、前端 tsconfig base 设置、nx/react类型、Jest preset、目标名前缀、非 Nx 源处理还有一批Next.js 特有的行为需要专门处理。本文按“推断目标 → 配置项 → 常见坑 → 非 Nx 源 → 混合 workspace → 修复顺序 → 实战记录”的顺序逐一展开。nx/next/plugin推断目标next.config 驱动的目标生成Nx 的推断插件inference plugin机制会在 workspace 中扫描特定配置文件自动为项目生成 target。nx/next/plugin的识别规则在 packages/next/src/plugins/plugin.ts 中定义const nextConfigBlob **/next.config.{ts,js,cjs,mjs};即只要某个目录下存在next.config.ts/next.config.js/next.config.cjs/next.config.mjs之一且该目录同时含有package.json或project.json见filterNextConfigsplugin.ts该目录就会被识别为 Next.js 项目并自动生成以下 targetTarget实际命令关键属性buildnext builddependsOn: [^build]cache: trueoutputs指向.next或distDirdevnext devcontinuous: truestartnext startcontinuous: truedependsOn: [build]serve-static与start相同兼容旧配置deprecated建议改用startTargetNamebuild-deps/watch-deps由nx/js/internal的addBuildAndWatchDepsTargets注入仅 TS solution setupisUsingTsSolutionSetup()为真时生成上述行为在源码中有完整对应buildNextTargets()依次注册buildTargetName、devTargetName、startTargetName、serveStaticTargetName并在 TS solution 模式下追加build-deps/watch-depsplugin.ts。默认 target 名在normalizeOptions中固化plugin.tsoptions.buildTargetName ?? build; options.devTargetName ?? dev; options.startTargetName ?? start; options.serveStaticTargetName ?? serve-static;build 目标的细节getBuildTargetConfigplugin.ts生成的buildtarget 值得注意command: next buildoptions.cwd指向项目根目录dependsOn: [^build]保证依赖库先构建这是 monorepo 中库产物可用的关键options.tty false非 TTY 模式下 Next.js 对 SIGINT 会以退出码 0 结束避免 CI 中假失败outputs通过getOutputs()计算plugin.ts若next.config是函数形式会用PHASE_PRODUCTION_BUILD调用一次来读取distDir默认.nextTS solution 模式下会附加syncGenerators: [nx/js:typescript-sync]inputs包含externalDependencies: [next]与dependentTasksOutputFiles: **/*.d.tstransitive保证库的类型声明变更能正确触发重构建plugin.ts。没有独立的 typecheck targetNext.js 应用没有独立的 typecheck target ——next build内部会执行 TypeScript 类型检查。workspace 中非 Next 库的独立typechecktarget 由nx/js/typescript插件提供。build target 冲突nx/next/plugin胜出nx/next/plugin与nx/js/typescript都定义buildtarget。由于插件扫描的是不同的配置文件next.config.*vstsconfig.lib.json对 Next.js 项目而言nx/next/plugin胜出并接管build而nx/js/typescript负责带tsconfig.lib.json的库。无需重命名二者自然共存。withNx与composePlugins保留即可Nx 生成的 Next.js 项目其next.config.js模板使用composePlugins(withNx)见 next.config.js 模板// eslint-disable-next-line typescript-eslint/no-var-requires const { composePlugins, withNx } require(nx/next); /** * type {import(nx/next/plugins/with-nx).WithNxOptions} **/ const nextConfig { nx: {}, }; const plugins [withNx]; module.exports composePlugins(...plugins)(nextConfig);composePlugins与withNx均从nx/next导出packages/next/index.ts。withNx的核心逻辑在 packages/next/plugins/with-nx.ts在PHASE_PRODUCTION_SERVER生产服务器阶段构建已完成、graph 创建期间global.NX_GRAPH_CREATION、或非 Nx task 环境下直接剥离nx字段返回原配置不做任何干预在 Nx task 环境中则读取 project graph自动把 workspace 内依赖库加入transpilePackages针对 Next.js ≥ 13.1读取outputPath/NX_NEXT_OUTPUT_PATH设置distDir并支持nx.fileReplacements、nx.assets等 Nx 特有选项见WithNxOptionswith-nx.ts。对nx import的意义通过推断插件运行的next build只是执行裸命令withNx包装对它是可选的但它提供了 Nx 特有的配置能力transpilePackages、distDir 对齐等所以若导入的配置中已存在就保留。注意模板第 13 行的// eslint-disable-next-line typescript-eslint/no-var-requires注释与后文 lint 警告一节直接相关。Next.js 根依赖清单在通用根依赖问题见 SKILL.md之外Next.js 项目通常还需要核心运行时react、react-dom、types/react、types/react-dom、types/node、nx/reactnx/react提供 CSS module / 图片的类型定义详见 SKILL.md 中nx/reacttypings 一节Nx 插件nx/nextnx import会自动安装、nx/eslint、nx/jest测试见 SKILL.md 的 “Jest Preset Missing” 一节涉及jest.preset.js、jest-environment-jsdom、ts-jestESLintnext/eslint-plugin-next在通用 ESLint 依赖之外。安装命令根目录、devDependenciespnpm add -wD types/react types/react-dom types/node nx/react pnpm add -wD next/eslint-plugin-next经典坑Next.js 用错误包管理器自动安装依赖Next.js 在next build时若检测到types/react缺失会尝试用yarn add安装 —— 无论 workspace 实际使用什么包管理器。在 pnpm workspace 中这会导致nearest package directory isnt part of the project根因根devDependencies中缺少types/react。修复构建前先在根目录安装pnpm add -wD types/react types/react-dom在 迭代日志 的 Scenario 1 中这正是导入 CNW next preset 项目时遇到的第 5 个错误。Next.js TypeScript 配置的独特模式与 Vite 项目相比Next.js 应用的 tsconfig 有一批独特模式noEmit: trueemitDeclarationOnly: falseNext.js 自己负责产物输出TS 只做类型检查。这与 TS solution setup 要求的composite: true冲突types: [jest, node]测试类型直接包含在主 tsconfig 中没有单独的tsconfig.app.jsonplugins: [{ name: next }]供 IDE 集成使用include引用.next/types/**/*.tsNext.js 自动生成的类型jsx: preserveNext.js 使用自己的 JSX transform而非 React 的。GotchanoEmit: true会禁用 composite 模式Next.js tsconfig 的noEmit: true会禁用composite模式。这没问题因为 Next.js 项目用next build构建而非tscnx/js/typescript插件的typechecktarget 对 Next.js 应用并非必需。next.config.js的 lint 警告导入的 Next.js 配置常带有// eslint-disable-next-line typescript-eslint/no-var-requires注释模板自带见上文但项目的 ESLint 配置启用的是不同的规则集于是产生Unused eslint-disable directive警告。这无害 —— 删除该注释或忽略即可。nx/next:init会重写全部 npm scripts整仓导入在整仓导入whole-repo import场景下nx/next:init运行时会像 Nx init 一样把项目的package.jsonscripts 重写为带前缀的nx调用{ dev: nx next:dev, build: nx next:build, start: nx next:start }这是 SKILL.md 中 “npm Script Rewriting” 问题的变体只是触发者是nx/next:init而非 Nx init。修复从package.json删除所有被重写的 scripts —— 因为nx/next/plugin已从next.config.*推断出全部 target不需要这些 script 转发。init生成器的实现细节可参见 packages/next/src/generators/init/init.ts它先移除nx/next再按仓库版本重装并在默认开启插件推断NX_ADD_PLUGINS ! false且nxJson.useInferencePlugins ! false时为nx/next/plugin注册start/next:start/next-start等目标名别名。非 Nx 源create-next-app推荐整仓导入对于单项目的create-next-app仓库建议整仓导入到子目录nx import /path/to/source apps/web --refmain --source. --no-interactive--no-interactive是 AI/CI 环境下的非交互模式nx import的参数定义sourceRepository、ref、source、destination、depth、interactive、plugins等可参见 packages/nx/src/command-line/import/import.tsAI 模式下还会强制关闭交互并一次性汇报缺失参数。导入前请确保目标仓库无未提交变更import.ts。next-env.d.ts不进版本库next build会在项目根自动生成next-env.d.ts。它由框架生成不应提交—— 把它加入目标根目录dest root的.gitignore。ESLint自包含的eslint-config-nextcreate-next-app生成的 flat ESLint 配置使用eslint-config-next自带全套插件。它是自包含的无需根eslint.config.mjs无需nx/eslint-plugin依赖。nx/eslint/plugin会检测到它并自动创建linttarget。TypeScript无需改动非 Nx 的 Next.js 项目 tsconfig 自包含noEmit: true、自己的lib/module/moduleResolution/jsx设置。由于next build内部处理类型检查tsconfig 无需任何修改也不要求继承tsconfig.base.json。Gotcha因为不存在tsconfig.lib.jsonnx/js/typescript插件不会创建typechecktarget —— 这没问题用next:build做类型检查即可。noEmit: true与 TS solution setup 的冲突非 Nx 的 Next.js 项目使用noEmit: true与 Nx TS solution setup 的composite: true冲突。如果目标 workspace 使用项目引用project references、且你希望 Next.js 应用参与其中移除noEmit: true添加composite: true、emitDeclarationOnly: true添加extends: ../../tsconfig.base.json添加outDir与tsBuildInfoFile。但是这对不向其他 workspace 项目导出类型的独立 Next.js 应用是可选的。Tailwind / PostCSS带 Tailwind 的create-next-app会生成postcss.config.mjs。导入后原样可用—— PostCSS 以项目根为基准解析路径无需改动路径。Next.js Vite 混合共存当 workspace 中同时存在 Next.js 与 Vite 项目详见 VITE.md 的 Scenario 6。插件共存nx/next/plugin与nx/vite/plugin可以在nx.json中共存它们检测不同的配置文件next.config.*vsvite.config.*互不冲突库由nx/js/typescript插件处理。Vite 独立项目的 tsconfig 修复Vite 独立项目以整仓方式导入的 tsconfig 是自包含的没有composite: true。而nx/js/typescript插件的 typecheck target 运行tsc --build --emitDeclarationOnly这要求 composite。修复步骤在项目根 tsconfig 添加extends: ../../tsconfig.base.json在tsconfig.app.json与tsconfig.spec.json添加composite: true、declaration: true、declarationMap: true、tsBuildInfoFile将moduleResolution从node改为bundler把源文件加入tsconfig.spec.json的include—— spec 会 import 应用代码而 composite 模式要求列出所有文件。Typecheck 目标命名nx/vite/plugin默认typecheckTargetName为vite:typechecknx/js/typescript使用typecheckNext.js 项目没有独立 typecheck target类型检查在next build中进行。框架之间无命名冲突。修复顺序Nx 源子目录导入将 Next.js 应用导入apps/name见 SKILL.md 的 “Application vs Library Detection”应用 SKILL.md 中的通用修复pnpm globs、根依赖、.gitkeep移除、前端 tsconfig base 设置、nx/reacttypings安装 Next.js 专项依赖pnpm add -wD next/eslint-plugin-nextESLint 配置见 SKILL.md 的 “Root ESLint Config Missing”Jest 配置见 SKILL.md 的 “Jest Preset Missing”验证nx reset nx sync --yes nx run-many -t typecheck,build,test,lint非 Nx 源create-next-app导入到apps/name见 SKILL.md 的 “Application vs Library Detection”应用 SKILL.md 中的通用修复pnpm globs、陈旧文件清理、script 重写、目标名前缀可选若应用需要向其他 workspace 项目导出类型修复noEmit→composite见 SKILL.md验证nx reset nx run-many -t next:build,eslint:lint若目标已重命名则用不带前缀的名字。实战记录三个已通过的迁移场景Scenario 1Nx Next.js App Router 共享库 → TS presetPASS源CNW next presetNext.js 16App Routernx/react:libraryshared-ui目标CNW ts presetNx 23方式逐子目录导入apps、libs 分开发现并修复的错误pnpm-workspace.yamlapps/libs→apps/*/libs/*根 tsconfignodenext→bundlerlib添加dom/dom.iterable添加jsx: react-jsx缺失nx/react库需要 CSS module / 图片类型定义缺失types/react、types/react-dom、types/nodeNext.js 尝试yarn add types/react—— 在根安装解决缺失nx/eslint、根eslint.config.mjs、ESLint 插件缺失nx/jest、jest.preset.js、jest-environment-jsdom、ts-jest结果typecheck、build、test、lint 全绿。Scenario 3非 Nx create-next-appApp Router Tailwind→ TS presetPASS源create-next-applatestNext.js 16.1.6App RouterTailwind v4flat ESLint 配置目标CNW ts presetNx 23方式整仓导入到apps/web发现并修复的错误pnpm-workspace.yamlapps/web→apps/*陈旧文件node_modules/、pnpm-lock.yaml、pnpm-workspace.yaml、.gitignore—— 删除Nx 重写的 npm scriptsbuild: nx next:build等—— 移除无需 tsconfig 改动自包含配置noEmit: trueESLint 通过eslint-config-next自包含无需根配置无测试配置create-next-app 不带测试结果next:build、eslint:lint 全绿。Scenario 4非 Nx create-next-app与 Vite、React Router 7、TanStack、CRA 并存→ TS presetPASS完整多导入场景见 VITE.md 的 Scenario 6Next.js 专项发现nx/next:init把所有 scripts 重写为nx next:*格式 —— 全部移除陈旧文件node_modules/、package-lock.json、.gitignore—— 删除npm workspace无 pnpm 文件ESLint 通过eslint-config-next自包含无需根配置无需 tsconfig 改动 ——noEmit: true保留next build负责类型检查目标next:build、next:dev、next:start、eslint:lint。Scenario 5混合 Next.jsNx 源 Vite React独立项目→ TS presetPASS源 ACNW next presetNext.js 16App Router—— 子目录导入apps/源 BCNW react-standalone presetVite 7React 19—— 整仓导入apps/vite-app目标CNW ts presetNx 23发现并修复的错误Next.js 应用应用 Scenario 1 的全部修复Vite 源的陈旧文件node_modules/、pnpm-lock.yaml、pnpm-workspace.yaml、.gitignore、nx.json—— 删除移除 Vite 应用package.json中被重写的 scriptsESLint 8 vs 9 冲突 ——nx/eslint的 peer 依赖在 ESLint 8 上解析到了错误版本用pnpm.overrides修复Vite tsconfig 缺失composite: true、declaration: true——tsc --build --emitDeclarationOnly必需Vitetsconfig.spec.json的include缺失源文件 —— spec 会 import 应用代码Vite tsconfigmoduleResolution: node→bundler添加extends: ../../tsconfig.base.json结果两个项目的 typecheck、build、test、lint 全绿。小结nx import迁移 Next.js 项目的核心心智模型可以归纳为三条目标全部来自推断nx/next/plugin只认next.config.*build/dev/start/serve-static以及 TS solution 下的build-deps/watch-deps全部自动生成因此被nx/next:init重写的 npm scripts 可以直接删除TypeScript 交给next buildNext.js 应用不需要独立的typechecktargetnoEmit: true与composite的冲突对独立应用可以忽略只有需要导出类型参与 project references 时才做composite改造依赖与配置分层处理types/react等根依赖必须前置安装否则 Next.js 会用错误的yarn addESLint 视来源决定走根配置Nx 源还是自包含的eslint-config-next非 Nx 源最后统一用nx reset nx run-many验证全绿。把这些规则与 SKILL.md、ESLINT.md、JEST.md、VITE.md 配合使用即可覆盖 Next.js 项目迁移的绝大多数场景。【免费下载链接】nxThe Monorepo Platform that amplifies both developers and AI agents. Nx optimizes your builds, scales your CI, and fixes failed PRs automatically. Ship in half the time.项目地址: https://gitcode.com/GitHub_Trending/nx/nx创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表