🚀 快速安装

复制以下命令并运行,立即安装此 Skill:

npx skills add https://skills.sh/nrwl/nx-ai-agents-config/nx-import

💡 提示:需要 Node.js 和 NPM

快速开始 (Quick Start)

  • nx import 将代码从源仓库或文件夹导入当前工作区,并保留提交历史。
  • 在 nx 22.6.0 之后,nx import 会响应 .ndjson 输出并提出后续问题。对于较早版本,始终使用 --no-interactive 运行并直接指定所有标志。
  • 运行 nx import --help 查看可用选项。
  • 导入前确保目标目录为空。
    示例:目标目录有 libs/utilslibs/models;源目录有 libs/uilibs/data-access — 你不能直接将 libs/ 导入到 libs/。请分别导入每个源库。

主要文档:

如有相应工具,请阅读 nx 文档。

导入策略 (Import Strategy)

逐个子目录导入 (Subdirectory-at-a-time) (nx import <source> apps --source=apps):

  • 推荐用于 monorepo 源 — 文件放置在顶层,没有冗余配置
  • 注意事项:需要多次导入命令(每次产生单独的合并提交);目标目录不能有冲突的目录;根目录配置(依赖、插件、targetDefaults)不会被导入
  • 目录冲突 (Directory conflicts):导入到替代名称的目录(例如 imported-apps/),然后重命名

整个仓库导入 (Whole repo) (nx import <source> imported --source=.):

  • 仅适用于非 monorepo 源(单项目仓库)
  • 对于 monorepo,会产生混乱的嵌套配置(imported/nx.jsonimported/tsconfig.base.json 等)
  • 如果必须这样做:保留导入的 tsconfig.base.json(项目会扩展它),为工作区全局和 executor 路径添加前缀

目录约定 (Directory Conventions)

  • 始终优先采用目标目录的现有约定。源使用 libs/ 但目标使用 packages/?导入到 packages/nx import <source> packages/foo --source=libs/foo)。
  • 如果目标目录没有约定(空工作区),请询问用户。

应用程序与库的识别 (Application vs Library Detection)

导入前,确定源是应用程序还是

  • 应用程序 (Applications):可部署的最终产品。常见标志:
    • 前端 (Frontend)next.config.*vite.config.* 带有构建入口点、特定框架的应用脚手架(CRA、Angular CLI 应用等)
    • 后端 (Node.js) (Backend – Node.js):Express/Fastify/NestJS 服务器入口点,package.json 中没有 "exports" 字段
    • JVM:Maven pom.xml 带有 <packaging>jar</packaging><packaging>war</packaging> 以及一个 main 类;Gradle application 插件或 mainClass 设置
    • .NET.csproj/.fsproj 带有 <OutputType>Exe</OutputType><OutputType>WinExe</OutputType>
    • 通用 (General):Dockerfile、可运行的入口点、没有打算供其他项目导入的公共 API 接口
  • 库 (Libraries):可被其他项目消费的可重用包。常见标志:package.json 中有 "main"/"exports",Maven/Gradle 打包为库 jar,.NET <OutputType>Library</OutputType>,打算供其他包导入的具名导出。

目标目录规则 (Destination directory rules)

  • 应用程序 → apps/<name>。检查工作区 glob 模式(例如 pnpm-workspace.yaml、根目录 package.json 中的 workspaces)是否已有 apps/* 条目。
    • 如果 不存在 apps/*,在导入前添加它:更新工作区 glob 配置并提交(或暂存)更改。
    • 示例:nx import <source> apps/my-app --source=packages/my-app
  • 库 → 遵循目标目录的现有约定(packages/libs/ 等)。

常见问题 (Common Issues)

pnpm 工作区 Glob 模式 (pnpm Workspace Globs) (关键)

nx import 会将导入的目录本身(例如 apps)添加到 pnpm-workspace.yaml而不是 其中的包 glob 模式。跨包导入会失败,报错 Cannot find module

修复 (Fix):将其替换为源配置中的正确 glob 模式(例如 apps/*libs/shared/*),然后 pnpm install

根依赖和配置未被导入 (Root Dependencies and Config Not Imported) (关键)

nx import 不会 从源根目录合并以下内容:

  • package.json 中的 dependencies/devDependencies
  • nx.json 中的 targetDefaults(例如 "@nx/esbuild:esbuild": { "dependsOn": ["^build"] } — 对构建顺序至关重要)
  • nx.json 中的 namedInputs(例如排除测试文件的 production 模式)
  • nx.json 中的插件配置

修复 (Fix):对比源和目标目录的 package.jsonnx.json。添加缺失的依赖,合并相关的 targetDefaultsnamedInputs

TypeScript 项目引用 (TypeScript Project References)

导入后,运行 nx sync --yes。如果它报告没有变化但类型检查仍然失败,请先运行 nx reset,然后再运行 nx sync --yes

显式 Executor 路径修复 (Explicit Executor Path Fixups)

推断的目标(通过 Nx 插件)相对于项目根目录解析配置 — 无需更改。显式的 executor 目标(例如 @nx/esbuild:esbuild)具有工作区根目录的相对路径(mainoutputPathtsConfigassetssourceRoot),这些路径必须加上导入目标目录的前缀。

插件检测 (Plugin Detection)

  • 整个仓库导入 (Whole-repo import)nx import 会检测并提供安装插件的选项。接受它们。
  • 子目录导入 (Subdirectory import):插件不会自动检测。使用 npx nx add @nx/PLUGIN 手动添加。检查 include/exclude 模式 — 默认模式不匹配替代目录(例如 apps-beta/)。
  • 任何插件配置更改后运行 npx nx reset

冗余的根文件(仅整个仓库导入)(Redundant Root Files – Whole-Repo Only)

整个仓库导入会将源的所有根文件带入目标子目录。清理:

  • pnpm-lock.yaml — 过时;目标有自己的锁文件
  • pnpm-workspace.yaml — 源工作区配置;与目标冲突
  • node_modules/ — 指向源文件系统的过时符号链接
  • .gitignore — 与目标根目录的 .gitignore 重复
  • nx.json — 源 Nx 配置;目标有自己的
  • README.md — 可选;保留或删除

不要盲目删除 tsconfig.base.json — 导入的项目可能通过相对路径扩展它。

根 ESLint 配置缺失(子目录导入)(Root ESLint Config Missing – Subdirectory Import)

子目录导入不会带入源的根目录 eslint.config.mjs,但项目配置会引用 ../../eslint.config.mjs

修复顺序 (Fix order)

  1. 首先安装 ESLint 依赖:pnpm add -wD eslint@^9 @nx/eslint-plugin typescript-eslint(加上特定框架的插件)
  2. 创建根目录 eslint.config.mjs(从源复制或使用 @nx/eslint-plugin 基础规则创建)
  3. 然后运行 npx nx add @nx/eslint 以在 nx.json 中注册插件

显式安装 typescript-eslint — pnpm 的严格提升不会自动解析 @nx/eslint-plugin 的这个传递依赖。

ESLint 版本固定 (ESLint Version Pinning) (关键)

将 ESLint 固定到 v9eslint@^9.0.0)。ESLint 10 会破坏 @nx/eslint 和许多插件,报错类似 Cannot read properties of undefined (reading 'version')

@nx/eslint 可能将 ESLint 8 作为对等依赖,导致错误版本被解析。如果 lint 失败并出现 Cannot read properties of undefined (reading 'allow'),添加 pnpm.overrides

{ "pnpm": { "overrides": { "eslint": "^9.0.0" } } }

依赖版本冲突 (Dependency Version Conflicts)

导入后,比较关键依赖(typescripteslint、特定框架)。如果目标使用更新的版本,将导入的包升级以匹配(通常是安全的)。如果源版本更新,可能需要先升级目标。如果需要,使用 pnpm.overrides 强制执行单一版本策略。

模块边界 (Module Boundaries)

导入的项目可能缺少 tags。添加标签或更新 @nx/enforce-module-boundaries 规则。

项目名称冲突(多次导入)(Project Name Collisions – Multi-Import)

源和目标中 package.json 的相同 name 会导致 MultipleProjectsWithSameNameError修复 (Fix):重命名冲突的名称(例如 @org/api@org/teama-api),更新所有依赖引用和 import 语句,然后 pnpm install。每个导入仓库的根目录 package.json 也会成为一个项目 — 也要重命名它们。

工作区依赖导入顺序 (Workspace Dep Import Ordering)

如果在导入过程中某个 "workspace:*" 依赖尚未被导入,pnpm install 会失败。文件操作仍然成功。修复 (Fix):先导入所有项目,然后运行 pnpm install --no-frozen-lockfile

.gitkeep 阻碍子目录导入 (.gitkeep Blocking Subdirectory Import)

TS 预设会创建 packages/.gitkeep。在导入前删除它并提交。

前端 tsconfig 基础设置 (Frontend tsconfig Base Settings) (关键)

TS 预设的默认值(module: "nodenext"moduleResolution: "nodenext"lib: ["es2022"])与前端框架(React、Next.js、Vue、Vite)不兼容。导入前端项目后,验证目标根目录 tsconfig.base.json

  • moduleResolution:必须是 "bundler"(而不是 "nodenext"
  • module:必须是 "esnext"(而不是 "nodenext"
  • lib:必须包含 "dom""dom.iterable"(前端项目需要这些)
  • jsx:对于仅 React 的工作区使用 "react-jsx",对于混合框架则按项目配置

对于子目录导入 (subdirectory imports),目标根目录的 tsconfig 是权威的 — 更新它。对于整个仓库导入 (whole-repo imports),导入的项目可能会扩展它们自己嵌套的 tsconfig.base.json,这使得这个问题不那么关键。

如果目标也有需要 nodenext 的后端项目,请使用按项目覆盖,而不是更改根配置。

注意 (Gotcha):TypeScript 不会合并 lib 数组 — 项目级别的覆盖会完全替换基础数组。在任何项目级别的 lib 中,始终包含所有需要的条目(例如 es2022domdom.iterable)。

@nx/react 库的类型定义 (@nx/react Typings for Libraries)

使用 @nx/react:library 生成的 React 库在其 tsconfig types 中引用了 @nx/react/typings/cssmodule.d.ts@nx/react/typings/image.d.ts。除非目标工作区安装了 @nx/react,否则这些引用会失败,报错 Cannot find type definition file

修复 (Fix)pnpm add -wD @nx/react

Jest 预设缺失(子目录导入)(Jest Preset Missing – Subdirectory Import)

Nx 预设会在工作区根目录创建 jest.preset.js,项目 jest 配置会引用它(例如 ../../jest.preset.js)。子目录导入不会带入这个文件。

修复 (Fix)

  1. 运行 npx nx add @nx/jest — 在 nx.json 中注册 @nx/jest/plugin 并更新 namedInputs
  2. 在工作区根目录创建 jest.preset.js(内容见 references/JEST.md)— nx add 仅在运行生成器时才会创建此文件,而不是在纯粹的 nx add
  3. 安装测试运行器依赖:pnpm add -wD jest jest-environment-jsdom ts-jest @types/jest
  4. 根据需要安装特定框架的测试依赖(参见 references/JEST.md

对于更深入的 Jest 问题(tsconfig.spec.json、Babel 转换、CI 原子化、Jest 与 Vitest 共存),请参阅 references/JEST.md

目标名称前缀(整个仓库导入)(Target Name Prefixing – Whole-Repo Import)

当导入一个带有现有 npm 脚本(builddevstartlint)的项目时,Nx 插件会为推断的目标名称自动添加前缀以避免冲突:例如 next:buildvite:buildeslint:lint

修复 (Fix):从导入的 package.json 中删除由 Nx 重写的 npm 脚本,然后选择:

  • 接受带前缀的名称(例如 nx run app:next:build
  • nx.json 中重命名插件目标名称,以使用不带前缀的名称

非 Nx 源问题 (Non-Nx Source Issues)

当源是没有 nx.json 的普通 pnpm/npm 工作区时。

npm 脚本重写 (npm Script Rewriting) (关键)

Nx 在初始化期间会重写 package.json 脚本,创建错误的命令(例如 vitest runnx test run)。修复 (Fix):删除所有被重写的脚本 — Nx 插件从配置文件推断目标。

noEmitcomposite + emitDeclarationOnly (关键)

普通的 TS 项目使用 "noEmit": true,这与 Nx 项目引用不兼容。

症状 (Symptoms):“typecheck target is disabled because one or more project references set ‘noEmit: true’”或 TS6310 错误。

所有导入的 tsconfig 中修复 (Fix in all imported tsconfigs)

  1. 删除 "noEmit": true。如果通过 extends 链继承,显式设置 "noEmit": false
  2. 添加 "composite": true"emitDeclarationOnly": true"declarationMap": true
  3. 添加 "outDir": "dist""tsBuildInfoFile": "dist/tsconfig.tsbuildinfo"
  4. 如果缺失,添加 "extends": "../../tsconfig.base.json"。删除现在从基础继承的设置。

过时的 node_modules 和锁文件 (Stale node_modules and Lockfiles)

nx import 可能带入 node_modules/(指向源文件系统的 pnpm 符号链接)和来自源的 pnpm-lock.yaml。两者都已过时。

修复 (Fix)rm -rf imported/node_modules imported/pnpm-lock.yaml imported/pnpm-workspace.yaml imported/.gitignore,然后 pnpm install

ESLint 配置处理 (ESLint Config Handling)

  • 旧版 .eslintrc.json(ESLint 8):删除所有 .eslintrc.*,移除 v8 依赖,创建扁平配置 eslint.config.mjs
  • 扁平配置 (eslint.config.js):自包含的配置通常可以保留原样。
  • 无 ESLint:从零开始创建根和项目级别的配置。

TypeScript paths 别名 (TypeScript paths Aliases)

Nx 使用 package.json "exports" + pnpm 工作区链接,而不是 tsconfig "paths"。如果包有正确的 "exports",则 paths 是多余的。否则,为新的目录结构更新 paths。

技术特定指南 (Technology-specific Guidance)

识别源仓库中的技术,然后阅读并应用匹配的参考文件。

可用参考:

  • references/ESLINT.md — ESLint 项目:重复的 lint/eslint:lint 目标、遗留的 .eslintrc.* 对生成文件进行 lint、自 lint 的扁平配置 .cjstypescript-eslint v7/v9 对等依赖冲突、在同一工作区中混合 ESLint v8+v9。
  • references/GRADLE.md
  • references/JEST.md — Jest 测试:@nx/jest/plugin 设置、jest.preset.js、按框架划分的测试依赖、tsconfig.spec.json、Jest 与 Vitest 共存、Babel 转换、CI 原子化。
  • references/NEXT.md — Next.js 项目:@nx/next/plugin 目标、withNx、Next.js TS 配置(noEmitjsx: "preserve")、通过错误的包管理器自动安装依赖、非 Nx create-next-app 导入、Next.js+Vite 混合共存。
  • references/TURBOREPO.md
  • references/VITE.md — Vite 项目(React、Vue 或两者):@nx/vite/plugin typecheck 目标、resolve.alias/__dirname 修复、框架依赖、Vue 特定设置、React+Vue 混合共存。

📄 原始文档

完整文档(英文):

https://skills.sh/nrwl/nx-ai-agents-config/nx-import

💡 提示:点击上方链接查看 skills.sh 原始英文文档,方便对照翻译。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。