@icebreakers/monorepo-templates 1.0.15 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/README.md +12 -8
  2. package/README.zh-CN.md +16 -0
  3. package/assets/.changeset/ledger.yaml +51 -0
  4. package/assets/.github/ISSUE_TEMPLATE/config.yml +1 -1
  5. package/assets/.github/workflows/release.yml +22 -97
  6. package/assets/AGENTS.md +5 -4
  7. package/assets/CONTRIBUTING.md +27 -2
  8. package/assets/SECURITY.md +12 -14
  9. package/assets/package.json +18 -10
  10. package/assets/pnpm-workspace.yaml +8 -0
  11. package/package.json +6 -4
  12. package/templates/cli/package.json +11 -4
  13. package/templates/client/package.json +22 -6
  14. package/templates/server/package.json +14 -7
  15. package/templates/server/vitest.config.ts +1 -4
  16. package/templates/tsdown/package.json +11 -4
  17. package/templates/tsdown/vitest.config.ts +1 -4
  18. package/templates/vitepress/.vitepress/config.ts +146 -165
  19. package/templates/vitepress/ai/index.md +12 -23
  20. package/templates/vitepress/ai/llms-txt.md +13 -31
  21. package/templates/vitepress/getting-started.md +3 -32
  22. package/templates/vitepress/index.md +27 -30
  23. package/templates/vitepress/knowledge/index.md +17 -41
  24. package/templates/vitepress/monorepo/commands.md +13 -18
  25. package/templates/vitepress/monorepo/index.md +22 -100
  26. package/templates/vitepress/monorepo/manage.md +15 -227
  27. package/templates/vitepress/monorepo/publish.md +17 -245
  28. package/templates/vitepress/monorepo/templates.md +10 -17
  29. package/templates/vitepress/monorepo/troubleshooting.md +13 -16
  30. package/templates/vitepress/package.json +11 -5
  31. package/templates/vitepress/public/_redirects +3 -0
  32. package/templates/vitepress/repoctl/adopt-existing.md +51 -53
  33. package/templates/vitepress/repoctl/aliases.md +18 -18
  34. package/templates/vitepress/repoctl/checks.md +21 -68
  35. package/templates/vitepress/repoctl/commands.md +16 -64
  36. package/templates/vitepress/repoctl/config.md +14 -35
  37. package/templates/vitepress/repoctl/doctor.md +20 -60
  38. package/templates/vitepress/repoctl/execution-model.md +16 -69
  39. package/templates/vitepress/repoctl/getting-started.md +34 -40
  40. package/templates/vitepress/repoctl/index.md +33 -61
  41. package/templates/vitepress/repoctl/reports.md +20 -74
  42. package/templates/vitepress/repoctl/scenarios.md +26 -28
  43. package/templates/vitepress/repoctl/template-assets.md +19 -88
  44. package/templates/vitepress/repoctl/templates.md +50 -81
  45. package/templates/vitepress/repoctl/troubleshooting.md +32 -46
  46. package/templates/vitepress/repoctl/workflows.md +38 -67
  47. package/templates/vitepress/thinking.md +4 -85
  48. package/templates/vitepress/tools/changeset.md +12 -85
  49. package/templates/vitepress/tools/husky.md +6 -124
  50. package/templates/vitepress/tools/index.md +13 -32
  51. package/templates/vitepress/tools/lint-staged.md +5 -96
  52. package/templates/vitepress/tools/llms-txt.md +4 -6
  53. package/templates/vitepress/tools/pnpm.md +7 -119
  54. package/templates/vitepress/tools/renovate.md +3 -87
  55. package/templates/vitepress/tools/turborepo.md +5 -157
  56. package/templates/vitepress/why/how-to-reuse-js-code.md +6 -247
  57. package/templates/vitepress/why/index.md +14 -1
  58. package/templates/vitepress/why/js-cjs-mjs.md +9 -96
  59. package/templates/vitepress/why/js-keywords.md +4 -129
  60. package/templates/vitepress/why/modern/bundlers.md +3 -50
  61. package/templates/vitepress/why/modern/dts.md +4 -90
  62. package/templates/vitepress/why/modern/esm-vs-cjs.md +4 -81
  63. package/templates/vitepress/why/modern/index.md +10 -51
  64. package/templates/vitepress/why/modern/package-entry-points.md +6 -117
  65. package/templates/vitepress/why/modern/typescript.md +4 -152
  66. package/templates/vitepress/why/publish-basic-npm-package.md +17 -144
  67. package/templates/vitepress/why/what-is-npm-package.md +4 -159
  68. package/templates/vitepress/zh/ai/index.md +33 -0
  69. package/templates/vitepress/zh/ai/llms-txt.md +42 -0
  70. package/templates/vitepress/zh/getting-started.md +40 -0
  71. package/templates/vitepress/zh/index.md +66 -0
  72. package/templates/vitepress/zh/knowledge/index.md +50 -0
  73. package/templates/vitepress/zh/monorepo/commands.md +21 -0
  74. package/templates/vitepress/zh/monorepo/index.md +115 -0
  75. package/templates/vitepress/zh/monorepo/manage.md +243 -0
  76. package/templates/vitepress/zh/monorepo/publish.md +87 -0
  77. package/templates/vitepress/zh/monorepo/templates.md +21 -0
  78. package/templates/vitepress/zh/monorepo/troubleshooting.md +20 -0
  79. package/templates/vitepress/zh/repoctl/adopt-existing.md +135 -0
  80. package/templates/vitepress/{en → zh}/repoctl/aliases.md +18 -18
  81. package/templates/vitepress/zh/repoctl/checks.md +86 -0
  82. package/templates/vitepress/zh/repoctl/commands.md +168 -0
  83. package/templates/vitepress/zh/repoctl/config.md +90 -0
  84. package/templates/vitepress/zh/repoctl/doctor.md +86 -0
  85. package/templates/vitepress/zh/repoctl/execution-model.md +81 -0
  86. package/templates/vitepress/zh/repoctl/getting-started.md +122 -0
  87. package/templates/vitepress/zh/repoctl/index.md +102 -0
  88. package/templates/vitepress/zh/repoctl/reports.md +94 -0
  89. package/templates/vitepress/{en → zh}/repoctl/scenarios.md +28 -26
  90. package/templates/vitepress/zh/repoctl/template-assets.md +116 -0
  91. package/templates/vitepress/zh/repoctl/templates.md +159 -0
  92. package/templates/vitepress/zh/repoctl/troubleshooting.md +110 -0
  93. package/templates/vitepress/zh/repoctl/workflows.md +118 -0
  94. package/templates/vitepress/zh/thinking.md +88 -0
  95. package/templates/vitepress/zh/tools/changeset.md +75 -0
  96. package/templates/vitepress/zh/tools/husky.md +130 -0
  97. package/templates/vitepress/zh/tools/index.md +38 -0
  98. package/templates/vitepress/zh/tools/lint-staged.md +103 -0
  99. package/templates/vitepress/zh/tools/llms-txt.md +9 -0
  100. package/templates/vitepress/zh/tools/pnpm.md +127 -0
  101. package/templates/vitepress/zh/tools/renovate.md +91 -0
  102. package/templates/vitepress/zh/tools/turborepo.md +166 -0
  103. package/templates/vitepress/zh/why/assets/npm-dt.svg +15 -0
  104. package/templates/vitepress/zh/why/assets/npm-ts.svg +19 -0
  105. package/templates/vitepress/zh/why/examples/0.npm-basic-package/index.js +10 -0
  106. package/templates/vitepress/zh/why/examples/0.npm-basic-package/package.json +11 -0
  107. package/templates/vitepress/zh/why/examples/1.npm-basic-package/index.cjs +12 -0
  108. package/templates/vitepress/zh/why/examples/1.npm-basic-package/index.d.ts +1 -0
  109. package/templates/vitepress/zh/why/examples/1.npm-basic-package/index.js +8 -0
  110. package/templates/vitepress/zh/why/examples/1.npm-basic-package/package.json +19 -0
  111. package/templates/vitepress/zh/why/examples/2.npm-basic-package/README.md +1 -0
  112. package/templates/vitepress/zh/why/examples/2.npm-basic-package/package-lock.json +30 -0
  113. package/templates/vitepress/zh/why/examples/2.npm-basic-package/package.json +35 -0
  114. package/templates/vitepress/zh/why/examples/2.npm-basic-package/rename-ext.js +24 -0
  115. package/templates/vitepress/zh/why/examples/2.npm-basic-package/src/index.ts +8 -0
  116. package/templates/vitepress/zh/why/examples/2.npm-basic-package/tsconfig.cjs.json +8 -0
  117. package/templates/vitepress/zh/why/examples/2.npm-basic-package/tsconfig.esm.json +7 -0
  118. package/templates/vitepress/zh/why/examples/2.npm-basic-package/tsconfig.json +18 -0
  119. package/templates/vitepress/zh/why/examples/3.npm-basic-package/README.md +1 -0
  120. package/templates/vitepress/zh/why/examples/3.npm-basic-package/package-lock.json +1496 -0
  121. package/templates/vitepress/zh/why/examples/3.npm-basic-package/package.json +31 -0
  122. package/templates/vitepress/zh/why/examples/3.npm-basic-package/src/index.ts +8 -0
  123. package/templates/vitepress/zh/why/examples/3.npm-basic-package/tsconfig.json +16 -0
  124. package/templates/vitepress/zh/why/examples/3.npm-basic-package/tsdown.config.ts +16 -0
  125. package/templates/vitepress/zh/why/examples/usage-cjs/cjs.cjs +4 -0
  126. package/templates/vitepress/zh/why/examples/usage-cjs/esm.mjs +4 -0
  127. package/templates/vitepress/zh/why/examples/usage-cjs/index.js +8 -0
  128. package/templates/vitepress/zh/why/examples/usage-cjs/package-lock.json +36 -0
  129. package/templates/vitepress/zh/why/examples/usage-cjs/package.json +20 -0
  130. package/templates/vitepress/zh/why/examples/usage-esm/cjs.cjs +4 -0
  131. package/templates/vitepress/zh/why/examples/usage-esm/createRequire.js +7 -0
  132. package/templates/vitepress/zh/why/examples/usage-esm/esm.mjs +4 -0
  133. package/templates/vitepress/zh/why/examples/usage-esm/index.js +8 -0
  134. package/templates/vitepress/zh/why/examples/usage-esm/package-lock.json +36 -0
  135. package/templates/vitepress/zh/why/examples/usage-esm/package.json +21 -0
  136. package/templates/vitepress/zh/why/how-to-reuse-js-code.md +250 -0
  137. package/templates/vitepress/zh/why/index.md +1 -0
  138. package/templates/vitepress/zh/why/js-cjs-mjs.md +99 -0
  139. package/templates/vitepress/zh/why/js-keywords.md +132 -0
  140. package/templates/vitepress/zh/why/modern/bundlers.md +52 -0
  141. package/templates/vitepress/zh/why/modern/dts.md +93 -0
  142. package/templates/vitepress/zh/why/modern/esm-vs-cjs.md +84 -0
  143. package/templates/vitepress/zh/why/modern/index.md +55 -0
  144. package/templates/vitepress/zh/why/modern/package-entry-points.md +128 -0
  145. package/templates/vitepress/zh/why/modern/typescript.md +155 -0
  146. package/templates/vitepress/zh/why/publish-basic-npm-package.md +146 -0
  147. package/templates/vitepress/zh/why/what-is-npm-package.md +162 -0
  148. package/templates/vue-lib/package.json +12 -5
  149. package/templates/vue-lib/vitest.config.ts +1 -1
  150. package/assets/.changeset/config.json +0 -21
  151. package/assets/.changeset/publish-versioned-packages.md +0 -5
  152. package/templates/vitepress/en/index.md +0 -63
  153. package/templates/vitepress/en/knowledge/monorepo.md +0 -37
  154. package/templates/vitepress/en/repoctl/adopt-existing.md +0 -133
  155. package/templates/vitepress/en/repoctl/commands.md +0 -120
  156. package/templates/vitepress/en/repoctl/config.md +0 -69
  157. package/templates/vitepress/en/repoctl/getting-started.md +0 -116
  158. package/templates/vitepress/en/repoctl/index.md +0 -74
  159. package/templates/vitepress/en/repoctl/templates.md +0 -128
  160. package/templates/vitepress/en/repoctl/troubleshooting.md +0 -96
  161. package/templates/vitepress/en/repoctl/workflows.md +0 -89
@@ -1,91 +1,7 @@
1
1
  # Renovate
2
2
 
3
- ## 1. 什么是 Renovate?
3
+ Renovate opens dependency update pull requests according to repository policy.
4
4
 
5
- **Renovate** 是一个开源的 **依赖更新自动化工具**。
6
- 它能帮你在项目中自动检测过期的依赖,并通过 PR(Pull Request)的形式提交更新建议。
5
+ Group related tooling updates, respect pnpm workspace constraints, and let the normal build, lint, typecheck, tsd, and test matrix validate each update. Avoid combining unrelated runtime and tooling upgrades when separate review makes regressions easier to isolate.
7
6
 
8
- 👉 简单来说:
9
-
10
- - 你不需要手动检查 `package.json`、`requirements.txt` 等文件里的依赖是否过期。
11
- - Renovate 会帮你自动发现并发起更新。
12
-
13
- ## 2. Renovate 有什么用?
14
-
15
- ### 🚀 核心价值
16
-
17
- 1. **自动化依赖升级**
18
- - 自动扫描项目依赖(支持 Node.js、Python、Java、Go、Docker 等)。
19
- - 自动检测新版本。
20
- - 自动提交 PR。
21
-
22
- 2. **降低维护成本**
23
- - 避免依赖长期不升级,导致一次性大版本升级困难。
24
- - 减少安全漏洞(及时更新安全补丁版本)。
25
-
26
- 3. **可控性强**
27
- - 你可以配置哪些依赖自动升级,哪些只做提醒。
28
- - 可以选择自动合并 **patch/minor** 版本更新,而 **major** 版本需要人工 review。
29
-
30
- 4. **支持 Monorepo**
31
- - 非常适合 monorepo 项目,能分别更新各个子包的依赖。
32
-
33
- ## 3. Renovate 怎么用?
34
-
35
- ### 方式一:作为 GitHub App
36
-
37
- 1. 打开 [Renovate GitHub App](https://github.com/apps/renovate) 并安装到你的仓库。
38
- 2. 它会自动在项目根目录生成一个配置文件 `renovate.json`(或 `renovate.json5`)。
39
- 3. Renovate 就会定期检查依赖,并创建 PR。
40
-
41
- ### 方式二:自托管
42
-
43
- 如果你不想用 GitHub App,可以自己部署 Renovate(适用于 GitLab、Bitbucket 等环境)。
44
-
45
- ```bash
46
- npx renovate
47
- ```
48
-
49
- ### 配置示例
50
-
51
- 在项目根目录添加 `renovate.json`:
52
-
53
- ```json
54
- {
55
- "extends": ["config:base"],
56
- "packageRules": [
57
- {
58
- "matchUpdateTypes": ["minor", "patch"],
59
- "automerge": true
60
- },
61
- {
62
- "matchUpdateTypes": ["major"],
63
- "automerge": false
64
- }
65
- ]
66
- }
67
- ```
68
-
69
- 解释:
70
-
71
- - 使用基础配置 `"extends": ["config:base"]`。
72
- - **minor/patch 更新** 自动合并。
73
- - **major 更新** 需要人工 review。
74
-
75
- ### 实际效果
76
-
77
- - Renovate 会创建类似这样的 PR:
78
- - `chore(deps): update dependency react from 18.2.0 to 18.3.0`
79
- - `fix(deps): update dependency lodash from 4.17.20 to 4.17.21`
80
-
81
- - 你可以选择直接合并,或者再测试后手动处理。
82
-
83
- ## 4. 总结
84
-
85
- - **Renovate = 自动依赖升级管家**。
86
- - 主要用途:**自动检测依赖更新、自动生成 PR、降低维护成本**。
87
- - 使用方式:安装 GitHub App(最简单),或者自托管运行。
88
- - 适用场景:
89
- - 需要长期维护的项目。
90
- - 对安全性敏感的项目(及时更新补丁)。
91
- - Monorepo 项目,依赖多而复杂。
7
+ repoctl does not replace Renovate. It provides the diagnostic and verification commands that Renovate pull requests can run consistently.
@@ -1,166 +1,14 @@
1
1
  # Turborepo
2
2
 
3
- 在 repoctl 体系里,Turborepo 负责“任务编排和缓存”,repoctl 负责“什么时候该跑哪些任务”。你日常通常不需要直接调用 `turbo`,而是通过根脚本或 `repo check` 间接触发。
3
+ Turborepo runs the monorepo task graph and caches repeatable work.
4
4
 
5
5
  ```bash
6
6
  pnpm build
7
+ pnpm lint
8
+ pnpm typecheck
7
9
  pnpm test
8
- pnpm exec repo check --full
9
- pnpm exec repo check --json --out reports/check-plan.json
10
10
  ```
11
11
 
12
- | 层级 | 作用 |
13
- | --------------------------------- | ----------------------------------------- |
14
- | `repo check` | 决定校验模式,输出可读或可保存的计划 |
15
- | 根脚本 `pnpm build` / `pnpm test` | 调用 `turbo run build` / `turbo run test` |
16
- | `turbo.json` | 定义任务依赖、缓存输出和执行策略 |
12
+ Root scripts delegate to `turbo run`. Package scripts define the actual build, lint, typecheck, and test commands; `turbo.json` defines dependencies, inputs, outputs, and cache behavior.
17
13
 
18
- 继续看:[repoctl 工作流与 CI](../repoctl/workflows.md)。
19
-
20
- ## 1. 什么是 Turborepo?
21
-
22
- **Turborepo** 是由 **Vercel** 推出的一个 **高性能 JavaScript/TypeScript monorepo 构建系统**。
23
-
24
- 它的定位类似于 **NX / Bazel**,但更轻量、更贴合前端生态。
25
- 主要解决 **monorepo(多包/多项目仓库)** 下的构建、缓存和任务调度问题。
26
-
27
- 👉 通俗说:
28
- 在一个仓库里有多个应用和包,**Turborepo 可以帮你高效管理它们的依赖、构建、测试和发布**。
29
-
30
- ## 2. Turborepo 有什么用?
31
-
32
- ### 🚀 性能优化
33
-
34
- - **增量构建**:只重新构建改动过的包,而不是全量重建。
35
- - **智能缓存**:构建结果会缓存,本地和 CI/CD 环境可以共享(比如用远程缓存)。
36
- - **任务并行化**:最大化利用 CPU 核心,减少构建时间。
37
-
38
- ### 📦 Monorepo 管理
39
-
40
- - 可以在一个仓库中维护多个项目(比如 `templates/` 下是模板,`packages/` 下是共享组件或工具)。
41
- - 内置工作区(workspace)支持,自动管理依赖关系。
42
-
43
- ### 🛠 灵活的任务编排
44
-
45
- - 你可以定义 `build`、`test`、`lint` 等任务,Turborepo 会根据依赖关系和缓存情况决定执行策略。
46
-
47
- ### 🌍 和 Vercel 深度集成
48
-
49
- - 在 Vercel 平台上可以直接利用远程缓存,加速 CI/CD。
50
-
51
- ## 3. Turborepo 怎么用?
52
-
53
- ### 安装
54
-
55
- 全局安装(可选):
56
-
57
- ```bash
58
- npm install turbo --global
59
- ```
60
-
61
- 在项目中初始化:
62
-
63
- ```bash
64
- npx create-turbo@latest
65
- ```
66
-
67
- 这会生成一个 monorepo 结构,比如:
68
-
69
- ```txt
70
- .
71
- ├── apps
72
- │ ├── web # 前端应用
73
- │ └── docs # 文档应用
74
- └── packages
75
- ├── ui # UI 组件库
76
- └── config # 配置共享包
77
- ```
78
-
79
- ### 配置 `turbo.json`
80
-
81
- 核心配置文件,放在仓库根目录:
82
-
83
- ```json
84
- {
85
- "$schema": "https://turbo.build/schema.json",
86
- "pipeline": {
87
- "build": {
88
- "dependsOn": ["^build"],
89
- "outputs": ["dist/**", ".next/**"]
90
- },
91
- "lint": {},
92
- "test": {
93
- "dependsOn": ["build"]
94
- }
95
- }
96
- }
97
- ```
98
-
99
- 解释:
100
-
101
- - `build` 任务依赖于上游包的 `build`。
102
- - 缓存 `dist/**` 或 `.next/**` 输出目录。
103
- - `test` 依赖于 `build`。
104
-
105
- ### 运行命令
106
-
107
- 在根目录执行:
108
-
109
- ```bash
110
- turbo run build
111
- ```
112
-
113
- 👉 Turborepo 会:
114
-
115
- - 找到所有定义了 `build` 脚本的项目。
116
- - 根据依赖关系决定执行顺序。
117
- - 如果缓存可用,直接跳过执行,秒完成。
118
-
119
- 同理:
120
-
121
- ```bash
122
- turbo run lint
123
- turbo run test
124
- ```
125
-
126
- ### 远程缓存(可选)
127
-
128
- 如果团队协作或 CI/CD,需要共享缓存:
129
-
130
- ```bash
131
- npx turbo login
132
- npx turbo link
133
- ```
134
-
135
- 这样不同开发者、CI 都可以复用缓存,进一步加速。
136
-
137
- ## 4. 总结
138
-
139
- - **Turborepo = 高性能 monorepo 构建工具**。
140
- - **核心优势**:缓存、增量构建、并行执行、依赖感知。
141
- - **适用场景**:
142
- - 大型 monorepo(多个应用 + 包)。
143
- - 需要快速构建和测试的团队。
144
- - 想用 Vercel 部署的项目。
145
-
146
- 好的 👍,我来帮你把 **Turborepo、Lerna、Nx** 三个常见 **Monorepo 管理工具**做一个对比表。
147
-
148
- ## Turborepo vs Lerna vs Nx
149
-
150
- | 特性 / 工具 | **Turborepo** | **Lerna** | **Nx** |
151
- | ----------------- | ---------------------------------------- | ------------------------------------------- | ----------------------------------------------- |
152
- | **定位** | 高性能构建系统,专注缓存、并行和增量构建 | 最早的 JS monorepo 工具,专注版本管理和发布 | 企业级开发平台,集成构建、测试、代码生成等功能 |
153
- | **核心优势** | ⚡ 高速缓存(本地 & 远程)、并行任务执行 | 📦 包版本管理(独立/统一模式)、发布到 npm | 🛠 丰富的插件生态、代码生成器、强大的依赖图分析 |
154
- | **依赖管理** | 基于 pnpm/yarn/npm workspaces | 基于 npm/yarn workspaces | 内置强依赖图(project graph)管理 |
155
- | **构建/缓存机制** | ✅ 智能缓存 & 增量构建 | ❌ 无缓存机制 | ✅ 强大缓存 & 增量构建(类似 Bazel) |
156
- | **任务编排** | pipeline 模式(`turbo.json`) | 简单顺序执行 | 高度可配置任务调度器(依赖感知) |
157
- | **语言支持** | 主要是 JS/TS 生态 | 主要是 JS/TS 生态 | 多语言支持(JS/TS/Go/Rust/Python 等) |
158
- | **学习成本** | ⭐⭐ 低(配置简洁,前端友好) | ⭐⭐ 低(老牌工具,功能单一) | ⭐⭐⭐ 高(功能多,配置复杂) |
159
- | **社区活跃度** | 🚀 高(Vercel 维护,发展迅速) | ⚠️ 中等(已过巅峰,更多用于发布流程) | 🚀 高(企业应用广泛,社区和插件丰富) |
160
- | **适合场景** | 前端/全栈项目,追求构建速度 & CI/CD 效率 | 多包库发布(如 npm 包集合项目) | 大型企业级 monorepo,跨语言/跨团队复杂项目 |
161
-
162
- ## 对比总结
163
-
164
- - **Turborepo**:主打 **快**,缓存和增量构建体验非常好,适合前端/全栈团队。
165
- - **Lerna**:更像是 **版本管理/发包工具**,现在多和 pnpm/Yarn Workspaces 搭配,用于管理 npm 包版本和发布。
166
- - **Nx**:功能最全,适合大型团队,有可视化依赖图、代码生成、跨语言支持,但学习曲线较陡。
14
+ Mark generated artifacts as task outputs and declare upstream dependencies such as `build` before tests that consume built packages.
@@ -1,250 +1,9 @@
1
- ---
2
- outline: [2, 4]
3
- ---
1
+ # Reusing JavaScript Code
4
2
 
5
- # 如何复用 js 代码
3
+ JavaScript code can be shared through source modules, workspace packages, or published npm packages. The right boundary depends on ownership and consumers.
6
4
 
7
- 我们知道,不论在什么编程语言里,复用代码最简单的方案就是 `复制粘贴`
5
+ - Use a local module for code owned by one package.
6
+ - Use a workspace package when multiple projects in the same repository share versioned behavior.
7
+ - Publish an npm package when external repositories need a stable public API.
8
8
 
9
- 然而,复制粘贴会导致代码冗余、难以维护,修改一处逻辑时易漏改其它处,增加出错概率,违背“不要重复自己”(DRY)原则。
10
-
11
- 假如人人写代码都复制粘贴,这会造成一个工程化的地狱,后期维护成本急剧升高。
12
-
13
- 为此我们需要有效利用 `模块化` 的思路,去提炼,拆分,复用我们写的代码。
14
-
15
- ## **代码的模块化**
16
-
17
- 在现代 `JavaScript` 开发中,**模块化**不仅是一种组织代码的结构化方式,更是实现高效代码复用的核心前提。
18
-
19
- ### 模块化是复用的基础
20
-
21
- 1. **明确边界,职责单一**
22
- 模块化将一个大程序拆分为职责清晰、相互独立的功能块(模块)。每个模块完成一个单一任务,这种**高内聚、低耦合**的结构,为复用提供了天然的土壤。
23
-
24
- 2. **清晰的导入导出机制**
25
- 通过标准的 `export` 和 `import`(或 `CommonJS` 的 `module.exports` / `require`),开发者可以在不同文件、不同项目中复用相同模块,而无需复制粘贴代码。
26
-
27
- 3. **便于维护与测试**
28
- 模块是可单独测试、维护的最小单元。模块化设计使得一个功能变化不会影响其他模块,增强了系统的稳定性和可扩展性。
29
-
30
- 4. **为构建通用库打下基础**
31
- 工具函数库(如 `lodash/es-toolkit`)、业务中间件、配置模块、数据处理逻辑等,都是基于模块化原则设计的。只有当代码被封装为模块,它才可能被提取、封装、共享、发布。
32
-
33
- ### 模块化让复用从被动到主动
34
-
35
- 非模块化时代的“复用”往往是:
36
-
37
- - 复制粘贴代码
38
- - 修改适配不同上下文
39
-
40
- 而模块化之后,“复用”变成了:
41
-
42
- - 明确接口,按需引入
43
- - 参数化、配置化、可扩展
44
-
45
- 这不仅是形式上的进步,更是软件工程层面的范式跃迁。
46
-
47
- ### js 模块的典型格式
48
-
49
- - **ES Modules(现代浏览器/现代 Node.js)**:标准、推荐,使用 `import` / `export`
50
- - **CommonJS(传统 Node.js)**:使用 `require` / `module.exports`
51
- - **UMD / IIFE / SystemJS / AMD**:一些老式模块化兼容方案,仍用于一些库的打包格式
52
-
53
- #### ES Modules (ESM)
54
-
55
- 目前大部分新的 `npm` 包都使用这个格式发包,
56
-
57
- 它最大的特点是,使用 `export` / `import` 将功能函数、类、常量等分别放入独立 `.js` 文件中,动态引入的使用 `import()` 进行引入
58
-
59
- ```js
60
- // utils/math.js
61
- export function add(a, b) {
62
- return a + b
63
- }
64
-
65
- export function multiply(a, b) {
66
- return a * b
67
- }
68
- ```
69
-
70
- ```js
71
- // main.js
72
- import { add, multiply } from './utils/math'
73
-
74
- console.log(add(2, 3)) // 5
75
- console.log(multiply(2, 3)) // 6
76
- ```
77
-
78
- **这是目前的主流,也是未来的方向**
79
-
80
- 注意事项:
81
-
82
- - 在浏览器中引入,需要使用 `<script type="module">`
83
- - 在 `Node.js` 中需要 `package.json` 设置 `"type": "module"`
84
-
85
- ---
86
-
87
- #### CommonJS (CJS)
88
-
89
- 在 `ESM` 规范没有被确立之前的社区模块化方案,低版本 `Node.js` 环境使用,高版本 `Node.js` 同时兼容 `CJS` 和 `ESM` 2 种模块化方案和加载策略
90
-
91
- 最大的特点为,使用 `require` / `module.exports`(`commonjs2`) / `exports`(`commonjs`) 进行模块化
92
-
93
- ```js
94
- // utils/math.js
95
- function add(a, b) {
96
- return a + b
97
- }
98
- module.exports = { add }
99
- ```
100
-
101
- ```js
102
- // app.js
103
- const { add } = require('./utils/math.js')
104
-
105
- console.log(add(5, 10))
106
- ```
107
-
108
- 新的包不会使用这个格式,目前这个格式的 `npm` 包,也正在逐步向 `ESM` 格式进行迁移
109
-
110
- #### AMD (Asynchronous Module Definition)
111
-
112
- AMD 是 RequireJS 推广的模块格式,支持异步加载模块,适用于浏览器。
113
-
114
- ```js
115
- define('myLib', [], () => {
116
- function hello() {
117
- return 'Hello from AMD'
118
- }
119
-
120
- return {
121
- hello
122
- }
123
- })
124
- ```
125
-
126
- **已经过时,不要使用!**
127
-
128
- #### UMD (Universal Module Definition)
129
-
130
- UMD 是为了同时兼容 CommonJS、AMD 和浏览器环境而设计的模块格式。
131
-
132
- ```js
133
- (function (root, factory) {
134
- if (typeof define === 'function' && define.amd) {
135
- // AMD
136
- define([], factory)
137
- }
138
- else if (typeof module === 'object' && module.exports) {
139
- // CommonJS
140
- module.exports = factory()
141
- }
142
- else {
143
- // Browser global
144
- root.myLib = factory()
145
- }
146
- }(this, () => {
147
- // 模块内容
148
- function hello() {
149
- return 'Hello from UMD'
150
- }
151
-
152
- return {
153
- hello
154
- }
155
- }))
156
- ```
157
-
158
- 通常在你使用 `vite` 的 `lib` 模式的时候,除了会打一个 `ESM` 包之外,也会打一个 `UMD` 的包,用于 `CDN` + `SSR` 场景下使用。
159
-
160
- #### IIFE (Immediately Invoked Function Expression)
161
-
162
- IIFE 是立即执行函数表达式,常用于浏览器中,通常暴露到 `window` 上(无模块系统时的“模拟模块”方式)。
163
-
164
- https://developer.mozilla.org/en-US/docs/Glossary/IIFE
165
-
166
- ```js
167
- (function () {
168
- function hello() {
169
- console.log('Hello from IIFE')
170
- }
171
-
172
- // 暴露到全局
173
- window.myLib = {
174
- hello
175
- }
176
- })()
177
- ```
178
-
179
- #### SystemJS / System.register
180
-
181
- `System` 是由 `ES6 Module Loader` 提出的一种格式,现代打包工具(如 `Rollup`)可以输出此格式,用于运行时动态加载 `ES Modules`。
182
-
183
- `SystemJS` 就是帮助你在不支持原生 `ESM` 格式的浏览器上(比如IE11),使用 `ESM` 格式
184
-
185
- ```js
186
- System.register(['./constants'], (exports) => {
187
- return {
188
- execute() {
189
- function hello() {
190
- console.log('Hello from System')
191
- }
192
-
193
- exports('hello', hello)
194
- }
195
- }
196
- })
197
- ```
198
-
199
- 加载方式(需要 `SystemJS` 库):
200
-
201
- ```html
202
- <script src="https://cdn.jsdelivr.net/npm/systemjs/dist/system.js"></script>
203
- <script>
204
- System.import('/path/to/your-module.js').then(({ hello }) => hello())
205
- </script>
206
- ```
207
-
208
- 比如 `@vitejs/plugin-legacy` 这个浏览器降级兼容方案,就是使用 `SystemJS` 在老旧的浏览器里面,加载 `ESM` 格式,从而进行兼容的。
209
-
210
- #### 参考链接
211
-
212
- - [rollupjs](https://rollupjs.org/configuration-options/#output-format)
213
- - [webpackjs](https://webpack.js.org/configuration/output/#module-definition-systems-1)
214
- - [esbuild](https://esbuild.github.io/api/#format)
215
- - [swc](https://swc.rs/docs/configuration/modules)
216
- - [babel](https://babeljs.io/docs/babel-preset-env#modules)
217
- - [typescript](https://www.typescriptlang.org/tsconfig/#module)
218
-
219
- ## 一些复用方式
220
-
221
- ### **利用路径 alias 复用代码**
222
-
223
- 在纯 JS 工程中,如果使用构建工具如 Vite / Webpack,可以配置别名路径:
224
-
225
- ```js
226
- // vite.config.js
227
- export default {
228
- resolve: {
229
- alias: {
230
- '@utils': path.resolve(__dirname, 'src/utils')
231
- }
232
- }
233
- }
234
- ```
235
-
236
- 然后在代码中:
237
-
238
- ```js
239
- import { add } from '@utils/math.js'
240
- ```
241
-
242
- 但是这种方式,仅在构建工具中生效,假如一个项目不用任何的构建工具,这个方案就不行了。
243
-
244
- ### **发布为 npm 本地包 / 私有包 / 公共包**
245
-
246
- 绝大部的场景都应该使用这个方案,来达到跨项目复用代码的目的。
247
-
248
- 这也是官方和社区推荐的方案。
249
-
250
- 接下来让我们开始 `npm` 包发布的旅程吧!
9
+ In a pnpm workspace, declare internal dependencies with the `workspace:` protocol and let the package build produce explicit runtime and type entrypoints.
@@ -1 +1,14 @@
1
- # 从 0 到 1 构建 monorepo
1
+ # Building A Modern npm Package
2
+
3
+ A modern package needs a deliberate module format, export map, declaration strategy, build pipeline, and compatibility policy.
4
+
5
+ ## Guide
6
+
7
+ - [Modern Package Overview](./modern/index.md)
8
+ - [ESM vs CommonJS](./modern/esm-vs-cjs.md)
9
+ - [Type Declarations](./modern/dts.md)
10
+ - [Package Entry Points](./modern/package-entry-points.md)
11
+ - [Bundlers](./modern/bundlers.md)
12
+ - [TypeScript](./modern/typescript.md)
13
+
14
+ Runnable evolution examples remain under `why/examples/` and are intentionally excluded from the generated AI documentation index.
@@ -1,99 +1,12 @@
1
- # js 文件的各种后缀
1
+ # JavaScript Module Extensions
2
2
 
3
- 下面用一张“速查表”+要点说明,把这些扩展名分别讲清楚,并说明各自**在什么情况下会被当作可执行模块加载**,以及**谁来消费它**。
3
+ Node.js uses file extensions and the nearest `package.json` `type` field to determine module format.
4
4
 
5
- ## 速查表
5
+ | Extension | Meaning |
6
+ | --------------- | --------------------------------------------- |
7
+ | `.mjs` | Always ES module |
8
+ | `.cjs` | Always CommonJS |
9
+ | `.js` | Depends on `package.json` `type` |
10
+ | `.mts` / `.cts` | TypeScript source with explicit module intent |
6
11
 
7
- | 扩展名 | 语义 | 由谁执行/消费 | 何时被当作“可运行的模块”加载 |
8
- | ------- | -------------------------------------------------- | ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
9
- | `.js` | JavaScript 源码(CJS 或 ESM,取决于上下文) | Node、浏览器、打包器 | **Node**:受 `package.json` 的 `"type"` 影响——`"type":"module"` 时按 **ESM** 解析,否则按 **CommonJS**。**浏览器**:始终当作 JS,是否是模块取决于 `<script type="module">`(ESM)还是普通 `<script>`(经典脚本)。 |
10
- | `.cjs` | JavaScript(**强制 CommonJS**) | Node、打包器 | **Node**:始终按 **CommonJS** 加载,与 `package.json` 的 `"type"` 无关。 |
11
- | `.mjs` | JavaScript(**强制 ESM**) | Node、浏览器、打包器 | **Node**:始终按 **ESM** 加载。**浏览器**:当作普通 JS 文件;是否作为模块取决于 `<script type="module">`。 |
12
- | `.ts` | TypeScript 源码(模块语义由编译目标/解析策略决定) | **TS 编译器/工具链**(tsc、ts-node、tsx、Vite 等) | 不是原生可执行;需经编译或运行时加载器将其转成 `.js`。在 TS 的 `moduleResolution`=NodeNext/Node16 下,`.ts` 的产物会遵循对应的 CJS/ESM 规则。 |
13
- | `.cts` | TypeScript,**指定生成 CommonJS** | TS 编译器/工具链 | 同上;不由 Node 直接执行。编译后产出 `.cjs/.js`(CJS 语义),并可生成 `.d.cts`。 |
14
- | `.mts` | TypeScript,**指定生成 ESM** | TS 编译器/工具链 | 同上;不由 Node 直接执行。编译后产出 `.mjs/.js`(ESM 语义),并可生成 `.d.mts`。 |
15
- | `.d.ts` | **类型声明文件**(仅类型,无运行时) | TypeScript 编译器、编辑器/语言服务、打包器的类型阶段 | **永不执行**。仅在类型检查/智能提示/发布类型时被“读取”。若包的 `package.json` 有 `"types": "index.d.ts"`(或在 `exports` 的 `types`/ `typesVersions` 配置),TS 会用它做类型来源。也存在 `.d.mts` / `.d.cts` 变体以对应 ESM/CJS。 |
16
-
17
- ## 关键规则与细节
18
-
19
- 1. **Node.js 如何决定 CJS vs ESM(针对 `.js`)**
20
- - 在某个包目录(有 `package.json`)下:
21
- - `package.json` 有 `"type": "module"` → 该目录内的 **`.js`** 默认视作 **ESM**。
22
- - 否则(默认 `"type":"commonjs"`)→ **`.js`** 默认视作 **CommonJS**。
23
-
24
- - **`.mjs` 一律 ESM,`.cjs` 一律 CJS**,不受 `"type"` 影响。
25
- - 混合项目的常见做法:`"type":"module"` + 把需要 CJS 的文件命名为 `.cjs`;或反之。
26
-
27
- 2. **浏览器如何加载**
28
- - 浏览器不关心 `.mjs/.cjs` 这些“Node 语义”扩展名本身;它看的是 `<script>` 标签:
29
- - `<script type="module" src="...">` → ESM 模式(支持 `import`)。
30
- - `<script src="...">` → 经典脚本(全局作用域,无模块语义)。
31
-
32
- - 资源的 **MIME 类型** 需正确(如 `text/javascript`);文件扩展名不是决定性因素。
33
-
34
- 3. **TypeScript 文件(`.ts/.mts/.cts`)何时“会被加载”?**
35
- - **Node 原生不会执行 TS**。你需要:
36
- - 先用 **`tsc`** 编译为 `.js/.mjs/.cjs` 再由 Node 加载;或
37
- - 使用运行时加载器/执行器(如 **ts-node、tsx、Bun** 或打包器 dev server)在内存里**即时转译**后再交给 JS 运行时执行。
38
-
39
- - **`.mts` / `.cts` 的意义**:在 TS 4.7+ 的 `moduleResolution: "NodeNext"/"Node16"` 下,明确告知“这是要编译成 ESM/CJS 的 TS 文件”。这能避免仅用 `.ts` 时的二义性。
40
- - 生成声明文件时会对应地产生 `.d.mts` / `.d.cts`。
41
-
42
- 4. **`.d.ts`(与 `.d.mts/.d.cts`)何时被“读取”**
43
- - **只在类型系统中使用**:编译(`tsc`)、编辑器智能提示、类型检查、`npm publish` 时作为类型入口。
44
- - 定位方式:
45
- - 包内 `package.json` 的 `"types"` / `"typings"` 字段;
46
- - `exports` 的 `types`(或 `typesVersions`);
47
- - `typeRoots`、`types`、三斜线指令 `/// <reference types="...">`;
48
- - `@types/*` 包(DefinitelyTyped)。
49
-
50
- - **运行时绝不加载/执行**。
51
-
52
- 5. **打包器(Vite、Webpack、Rollup、esbuild)**
53
- - 都把 **`.mjs` 当 ESM**、**`.cjs` 当 CJS**。
54
- - 会通过插件/内置加载 TS(把 `.ts/.mts/.cts` 转成 JS)。
55
- - 会遵守 `exports`/`module`/`main`/`type` 等字段来选择入口与格式。
56
- - 对于 Node 产物,常见是同时发布 ESM 与 CJS 两套构建(双包架构),并提供相应的 `.d.ts`。
57
-
58
- ## 示例
59
-
60
- **Node + `"type":"module"` 情况:**
61
-
62
- ```txt
63
- pkg/
64
- package.json // { "type": "module" }
65
- index.js // 按 ESM 解析
66
- legacy.cjs // 按 CJS 解析
67
- util.mjs // 按 ESM 解析
68
- ```
69
-
70
- **TypeScript 在 NodeNext 下的布局:**
71
-
72
- ```txt
73
- src/
74
- index.mts // 编译为 ESM(.mjs);会配套生成 index.d.mts(若开启声明)
75
- loader.cts // 编译为 CJS(.cjs);会配套生成 loader.d.cts
76
- types.d.ts // 仅类型,运行时不参与
77
- ```
78
-
79
- **浏览器:**
80
-
81
- ```html
82
- <!-- 经典脚本(非模块) -->
83
- <script src="/app.js"></script>
84
-
85
- <!-- ESM 模块 -->
86
- <script type="module" src="/main.js"></script>
87
- ```
88
-
89
- ## 实战建议
90
-
91
- - **库作者**:建议产出 **双格式**(CJS+ESM)与**类型声明**,并在 `package.json` 设置:
92
- - `"type": "module"`(若以 ESM 为主),再提供 CJS 入口(`.cjs`);
93
- - 使用 `exports` 指定 `import`/`require` 条目与 `types`。
94
-
95
- - **应用作者**:统一风格更省心。若全量 ESM,就:
96
- - `"type":"module"` + 统一 `.js/.mjs`(或 TS 中用 `.mts`);
97
- - 依赖里若有 CJS 包,让打包器或 Node 的兼容层处理。
98
-
99
- - **TS 工程**:用 **`moduleResolution: "NodeNext"`**,并用 `.mts/.cts` 明确产物语义;发布时别忘了 `.d.ts`/`.d.mts/.d.cts`。
12
+ For published libraries, make the package `exports` map explicit and test both import and require paths when both formats are supported.