@icebreakers/monorepo-templates 1.1.0 → 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.
- package/README.md +12 -8
- package/README.zh-CN.md +16 -0
- package/assets/.changeset/ledger.yaml +25 -0
- package/assets/.github/ISSUE_TEMPLATE/config.yml +1 -1
- package/assets/AGENTS.md +4 -3
- package/assets/CONTRIBUTING.md +27 -2
- package/assets/SECURITY.md +12 -14
- package/assets/package.json +13 -4
- package/package.json +6 -4
- package/templates/cli/package.json +11 -4
- package/templates/client/package.json +17 -1
- package/templates/server/package.json +11 -4
- package/templates/tsdown/package.json +11 -4
- package/templates/vitepress/.vitepress/config.ts +146 -165
- package/templates/vitepress/ai/index.md +12 -23
- package/templates/vitepress/ai/llms-txt.md +13 -31
- package/templates/vitepress/getting-started.md +3 -32
- package/templates/vitepress/index.md +27 -30
- package/templates/vitepress/knowledge/index.md +17 -41
- package/templates/vitepress/monorepo/commands.md +13 -18
- package/templates/vitepress/monorepo/index.md +22 -100
- package/templates/vitepress/monorepo/manage.md +15 -227
- package/templates/vitepress/monorepo/publish.md +15 -70
- package/templates/vitepress/monorepo/templates.md +10 -17
- package/templates/vitepress/monorepo/troubleshooting.md +13 -16
- package/templates/vitepress/package.json +10 -4
- package/templates/vitepress/public/_redirects +3 -0
- package/templates/vitepress/repoctl/adopt-existing.md +51 -53
- package/templates/vitepress/repoctl/aliases.md +18 -18
- package/templates/vitepress/repoctl/checks.md +21 -68
- package/templates/vitepress/repoctl/commands.md +16 -64
- package/templates/vitepress/repoctl/config.md +14 -35
- package/templates/vitepress/repoctl/doctor.md +20 -60
- package/templates/vitepress/repoctl/execution-model.md +16 -69
- package/templates/vitepress/repoctl/getting-started.md +34 -40
- package/templates/vitepress/repoctl/index.md +33 -61
- package/templates/vitepress/repoctl/reports.md +20 -74
- package/templates/vitepress/repoctl/scenarios.md +26 -28
- package/templates/vitepress/repoctl/template-assets.md +19 -88
- package/templates/vitepress/repoctl/templates.md +50 -81
- package/templates/vitepress/repoctl/troubleshooting.md +32 -46
- package/templates/vitepress/repoctl/workflows.md +38 -67
- package/templates/vitepress/thinking.md +4 -85
- package/templates/vitepress/tools/changeset.md +9 -59
- package/templates/vitepress/tools/husky.md +6 -124
- package/templates/vitepress/tools/index.md +13 -32
- package/templates/vitepress/tools/lint-staged.md +5 -96
- package/templates/vitepress/tools/llms-txt.md +4 -6
- package/templates/vitepress/tools/pnpm.md +7 -119
- package/templates/vitepress/tools/renovate.md +3 -87
- package/templates/vitepress/tools/turborepo.md +5 -157
- package/templates/vitepress/why/how-to-reuse-js-code.md +6 -247
- package/templates/vitepress/why/index.md +14 -1
- package/templates/vitepress/why/js-cjs-mjs.md +9 -96
- package/templates/vitepress/why/js-keywords.md +4 -129
- package/templates/vitepress/why/modern/bundlers.md +3 -50
- package/templates/vitepress/why/modern/dts.md +4 -90
- package/templates/vitepress/why/modern/esm-vs-cjs.md +4 -81
- package/templates/vitepress/why/modern/index.md +10 -51
- package/templates/vitepress/why/modern/package-entry-points.md +6 -117
- package/templates/vitepress/why/modern/typescript.md +4 -152
- package/templates/vitepress/why/publish-basic-npm-package.md +17 -144
- package/templates/vitepress/why/what-is-npm-package.md +4 -159
- package/templates/vitepress/zh/ai/index.md +33 -0
- package/templates/vitepress/zh/ai/llms-txt.md +42 -0
- package/templates/vitepress/zh/getting-started.md +40 -0
- package/templates/vitepress/zh/index.md +66 -0
- package/templates/vitepress/zh/knowledge/index.md +50 -0
- package/templates/vitepress/zh/monorepo/commands.md +21 -0
- package/templates/vitepress/zh/monorepo/index.md +115 -0
- package/templates/vitepress/zh/monorepo/manage.md +243 -0
- package/templates/vitepress/zh/monorepo/publish.md +87 -0
- package/templates/vitepress/zh/monorepo/templates.md +21 -0
- package/templates/vitepress/zh/monorepo/troubleshooting.md +20 -0
- package/templates/vitepress/zh/repoctl/adopt-existing.md +135 -0
- package/templates/vitepress/{en → zh}/repoctl/aliases.md +18 -18
- package/templates/vitepress/zh/repoctl/checks.md +86 -0
- package/templates/vitepress/zh/repoctl/commands.md +168 -0
- package/templates/vitepress/zh/repoctl/config.md +90 -0
- package/templates/vitepress/zh/repoctl/doctor.md +86 -0
- package/templates/vitepress/zh/repoctl/execution-model.md +81 -0
- package/templates/vitepress/zh/repoctl/getting-started.md +122 -0
- package/templates/vitepress/zh/repoctl/index.md +102 -0
- package/templates/vitepress/zh/repoctl/reports.md +94 -0
- package/templates/vitepress/{en → zh}/repoctl/scenarios.md +28 -26
- package/templates/vitepress/zh/repoctl/template-assets.md +116 -0
- package/templates/vitepress/zh/repoctl/templates.md +159 -0
- package/templates/vitepress/zh/repoctl/troubleshooting.md +110 -0
- package/templates/vitepress/zh/repoctl/workflows.md +118 -0
- package/templates/vitepress/zh/thinking.md +88 -0
- package/templates/vitepress/zh/tools/changeset.md +75 -0
- package/templates/vitepress/zh/tools/husky.md +130 -0
- package/templates/vitepress/zh/tools/index.md +38 -0
- package/templates/vitepress/zh/tools/lint-staged.md +103 -0
- package/templates/vitepress/zh/tools/llms-txt.md +9 -0
- package/templates/vitepress/zh/tools/pnpm.md +127 -0
- package/templates/vitepress/zh/tools/renovate.md +91 -0
- package/templates/vitepress/zh/tools/turborepo.md +166 -0
- package/templates/vitepress/zh/why/assets/npm-dt.svg +15 -0
- package/templates/vitepress/zh/why/assets/npm-ts.svg +19 -0
- package/templates/vitepress/zh/why/examples/0.npm-basic-package/index.js +10 -0
- package/templates/vitepress/zh/why/examples/0.npm-basic-package/package.json +11 -0
- package/templates/vitepress/zh/why/examples/1.npm-basic-package/index.cjs +12 -0
- package/templates/vitepress/zh/why/examples/1.npm-basic-package/index.d.ts +1 -0
- package/templates/vitepress/zh/why/examples/1.npm-basic-package/index.js +8 -0
- package/templates/vitepress/zh/why/examples/1.npm-basic-package/package.json +19 -0
- package/templates/vitepress/zh/why/examples/2.npm-basic-package/README.md +1 -0
- package/templates/vitepress/zh/why/examples/2.npm-basic-package/package-lock.json +30 -0
- package/templates/vitepress/zh/why/examples/2.npm-basic-package/package.json +35 -0
- package/templates/vitepress/zh/why/examples/2.npm-basic-package/rename-ext.js +24 -0
- package/templates/vitepress/zh/why/examples/2.npm-basic-package/src/index.ts +8 -0
- package/templates/vitepress/zh/why/examples/2.npm-basic-package/tsconfig.cjs.json +8 -0
- package/templates/vitepress/zh/why/examples/2.npm-basic-package/tsconfig.esm.json +7 -0
- package/templates/vitepress/zh/why/examples/2.npm-basic-package/tsconfig.json +18 -0
- package/templates/vitepress/zh/why/examples/3.npm-basic-package/README.md +1 -0
- package/templates/vitepress/zh/why/examples/3.npm-basic-package/package-lock.json +1496 -0
- package/templates/vitepress/zh/why/examples/3.npm-basic-package/package.json +31 -0
- package/templates/vitepress/zh/why/examples/3.npm-basic-package/src/index.ts +8 -0
- package/templates/vitepress/zh/why/examples/3.npm-basic-package/tsconfig.json +16 -0
- package/templates/vitepress/zh/why/examples/3.npm-basic-package/tsdown.config.ts +16 -0
- package/templates/vitepress/zh/why/examples/usage-cjs/cjs.cjs +4 -0
- package/templates/vitepress/zh/why/examples/usage-cjs/esm.mjs +4 -0
- package/templates/vitepress/zh/why/examples/usage-cjs/index.js +8 -0
- package/templates/vitepress/zh/why/examples/usage-cjs/package-lock.json +36 -0
- package/templates/vitepress/zh/why/examples/usage-cjs/package.json +20 -0
- package/templates/vitepress/zh/why/examples/usage-esm/cjs.cjs +4 -0
- package/templates/vitepress/zh/why/examples/usage-esm/createRequire.js +7 -0
- package/templates/vitepress/zh/why/examples/usage-esm/esm.mjs +4 -0
- package/templates/vitepress/zh/why/examples/usage-esm/index.js +8 -0
- package/templates/vitepress/zh/why/examples/usage-esm/package-lock.json +36 -0
- package/templates/vitepress/zh/why/examples/usage-esm/package.json +21 -0
- package/templates/vitepress/zh/why/how-to-reuse-js-code.md +250 -0
- package/templates/vitepress/zh/why/index.md +1 -0
- package/templates/vitepress/zh/why/js-cjs-mjs.md +99 -0
- package/templates/vitepress/zh/why/js-keywords.md +132 -0
- package/templates/vitepress/zh/why/modern/bundlers.md +52 -0
- package/templates/vitepress/zh/why/modern/dts.md +93 -0
- package/templates/vitepress/zh/why/modern/esm-vs-cjs.md +84 -0
- package/templates/vitepress/zh/why/modern/index.md +55 -0
- package/templates/vitepress/zh/why/modern/package-entry-points.md +128 -0
- package/templates/vitepress/zh/why/modern/typescript.md +155 -0
- package/templates/vitepress/zh/why/publish-basic-npm-package.md +146 -0
- package/templates/vitepress/zh/why/what-is-npm-package.md +162 -0
- package/templates/vue-lib/package.json +12 -5
- package/templates/vitepress/en/index.md +0 -63
- package/templates/vitepress/en/knowledge/monorepo.md +0 -37
- package/templates/vitepress/en/repoctl/adopt-existing.md +0 -133
- package/templates/vitepress/en/repoctl/commands.md +0 -120
- package/templates/vitepress/en/repoctl/config.md +0 -69
- package/templates/vitepress/en/repoctl/getting-started.md +0 -116
- package/templates/vitepress/en/repoctl/index.md +0 -74
- package/templates/vitepress/en/repoctl/templates.md +0 -128
- package/templates/vitepress/en/repoctl/troubleshooting.md +0 -96
- package/templates/vitepress/en/repoctl/workflows.md +0 -89
|
@@ -1,99 +1,12 @@
|
|
|
1
|
-
#
|
|
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.
|
|
@@ -1,132 +1,7 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ESM and CommonJS Runtime Globals
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
CommonJS provides `require`, `module`, `exports`, `__filename`, and `__dirname`. ES modules use `import`, `export`, `import.meta.url`, and `createRequire` when interoperability is required.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Avoid assuming CommonJS globals exist inside ESM. Resolve file paths with `fileURLToPath(import.meta.url)` and prefer static imports so bundlers and type checkers can understand dependencies.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- **`require`**
|
|
10
|
-
用于导入模块,例如:`const fs = require("fs")`
|
|
11
|
-
- **`module.exports`**
|
|
12
|
-
导出一个模块的接口对象。
|
|
13
|
-
- **`exports`**
|
|
14
|
-
是 `module.exports` 的引用,常用于简写导出。
|
|
15
|
-
- **`__filename`**
|
|
16
|
-
当前模块的绝对路径(包含文件名)。
|
|
17
|
-
- **`__dirname`**
|
|
18
|
-
当前模块所在目录的绝对路径。
|
|
19
|
-
- **`arguments`**
|
|
20
|
-
在函数中依然可用,但不是模块特有的(ESM 中的顶层不再支持)。
|
|
21
|
-
|
|
22
|
-
### 特点
|
|
23
|
-
|
|
24
|
-
- 模块加载是 **同步的**(`require` 立即执行)。
|
|
25
|
-
- 每个文件就是一个模块,作用域隔离。
|
|
26
|
-
- Node.js 原生支持。
|
|
27
|
-
|
|
28
|
-
## 🌐 ECMAScript Modules (ESM)
|
|
29
|
-
|
|
30
|
-
ESM 是 JavaScript 官方标准,现代浏览器和 Node.js 都支持(需要 `.mjs` 或 `package.json` 配置 `"type": "module"`)。
|
|
31
|
-
|
|
32
|
-
### 核心关键字 / 特性
|
|
33
|
-
|
|
34
|
-
- **`import`**
|
|
35
|
-
用于引入模块:
|
|
36
|
-
- `import fs from "fs"`
|
|
37
|
-
- `import { readFile } from "fs"`
|
|
38
|
-
|
|
39
|
-
- **`export`**
|
|
40
|
-
导出模块:
|
|
41
|
-
- `export default function() {}`
|
|
42
|
-
- `export const x = 1`
|
|
43
|
-
|
|
44
|
-
- **`import.meta`**
|
|
45
|
-
提供关于当前模块的元信息(例如:`import.meta.url` 获取模块的文件路径 URL)。
|
|
46
|
-
- **`top-level await`**
|
|
47
|
-
在 ESM 顶层作用域中可以直接使用 `await`。
|
|
48
|
-
|
|
49
|
-
### 特点
|
|
50
|
-
|
|
51
|
-
- 模块加载是 **异步的**。
|
|
52
|
-
- 静态结构,编译时可确定依赖关系。
|
|
53
|
-
- 更加标准化,支持 Tree-shaking(构建时优化)。
|
|
54
|
-
|
|
55
|
-
## 🚧 差异对照表
|
|
56
|
-
|
|
57
|
-
| 特性 | CommonJS (CJS) | ECMAScript Modules (ESM) |
|
|
58
|
-
| ---------------- | ---------------------------- | --------------------------------- |
|
|
59
|
-
| 导入 | `require()` | `import` |
|
|
60
|
-
| 导出 | `module.exports` / `exports` | `export` / `export default` |
|
|
61
|
-
| 文件扩展名 | `.cjs` / `.js` | `.mjs` / `.js` |
|
|
62
|
-
| 文件路径变量 | `__filename`, `__dirname` | ❌(可用 `import.meta.url` 替代) |
|
|
63
|
-
| 模块元信息 | ❌ | `import.meta` |
|
|
64
|
-
| 异步顶层 `await` | ❌ | ✅ |
|
|
65
|
-
| 加载方式 | 同步 | 异步 |
|
|
66
|
-
|
|
67
|
-
---
|
|
68
|
-
|
|
69
|
-
👉 例如,ESM 中没有 `__filename` 和 `__dirname`,你需要用以下方式替代:
|
|
70
|
-
|
|
71
|
-
```js
|
|
72
|
-
import { dirname } from 'node:path'
|
|
73
|
-
// ESM 中获取 __dirname 效果
|
|
74
|
-
import { fileURLToPath } from 'node:url'
|
|
75
|
-
|
|
76
|
-
const __filename = fileURLToPath(import.meta.url)
|
|
77
|
-
const __dirname = dirname(__filename)
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## 📦 CommonJS (CJS) — 清除模块缓存
|
|
81
|
-
|
|
82
|
-
CJS 使用 `require()` 加载模块时,**会把模块对象缓存在 `require.cache` 里**。如果想清除缓存,可以操作这个对象。
|
|
83
|
-
|
|
84
|
-
### 关键方式
|
|
85
|
-
|
|
86
|
-
```js
|
|
87
|
-
// 加载模块
|
|
88
|
-
const mod = require('./foo.js')
|
|
89
|
-
|
|
90
|
-
// 清除缓存
|
|
91
|
-
delete require.cache[require.resolve('./foo.js')]
|
|
92
|
-
|
|
93
|
-
// 重新加载
|
|
94
|
-
const freshMod = require('./foo.js')
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
- `require.resolve()` 会返回模块的绝对路径,用它作为 key 来删除缓存。
|
|
98
|
-
- 删除后,再次 `require()` 会重新执行模块代码。
|
|
99
|
-
|
|
100
|
-
⚠️ 注意:
|
|
101
|
-
|
|
102
|
-
- 如果模块被多个文件引用,删除缓存只影响 **当前模块**,依赖树中的引用关系可能导致“旧对象”仍在内存中。
|
|
103
|
-
- 所以要真正“重载”模块,有时需要递归删除依赖树的缓存。
|
|
104
|
-
|
|
105
|
-
## 🌐 ECMAScript Modules (ESM) — 清除模块缓存
|
|
106
|
-
|
|
107
|
-
ESM 的模块缓存存放在 **`import` 的内部 Module Map** 中,规范里没有暴露直接操作缓存的方法。
|
|
108
|
-
不过在 **Node.js 环境** 中,可以通过 **动态导入 (`import()`)** + **带查询参数** 或 **利用 `vm` / Loader Hooks** 来实现类似效果。
|
|
109
|
-
|
|
110
|
-
### 常用方式 1:加查询参数绕缓存
|
|
111
|
-
|
|
112
|
-
```js
|
|
113
|
-
const mod1 = await import(`./foo.js?update=${Date.now()}`)
|
|
114
|
-
const mod2 = await import(`./foo.js?update=${Date.now()}`)
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
- 每次加上不同的 querystring,就会绕过缓存,强制重新加载。
|
|
118
|
-
|
|
119
|
-
### 常用方式 2:使用 `import()` + `Module.createRequire`
|
|
120
|
-
|
|
121
|
-
在 Node.js 18+ 里,可以通过 `vm` 的上下文重新加载模块,不过相对复杂。一般开发调试时用 **动态 `import()` 加 query** 就够了。
|
|
122
|
-
|
|
123
|
-
## 🚧 对比总结
|
|
124
|
-
|
|
125
|
-
| 功能 | CommonJS (CJS) | ECMAScript Modules (ESM) |
|
|
126
|
-
| ------------------ | ----------------------------------------- | ----------------------------------- |
|
|
127
|
-
| 缓存位置 | `require.cache` | 内部 **Module Map**(不可直接访问) |
|
|
128
|
-
| 清除缓存方法 | `delete require.cache[require.resolve()]` | ❌ 无官方 API |
|
|
129
|
-
| 实际可行的清除方法 | 直接删除缓存并重新 `require()` | 动态 `import()` 加唯一参数绕过缓存 |
|
|
130
|
-
| 典型应用场景 | 热重载、插件系统 | 热重载、调试时强制刷新模块 |
|
|
131
|
-
|
|
132
|
-
<!-- 👉 要不要我帮你写一个 **CJS + ESM 通用的“热重载工具函数”**,比如 `reloadModule(path)`,可以自动检测当前运行环境,然后清除缓存并重新加载?这样你写代码时可以直接用,而不用区分 require/import。 -->
|
|
7
|
+
See [ESM vs CommonJS](./modern/esm-vs-cjs.md) for package-level guidance.
|
|
@@ -1,52 +1,5 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Bundlers
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Library bundlers turn source modules into publishable runtime and declaration artifacts. The repository's TypeScript library asset uses [tsdown](https://github.com/sonofmagic/repoctl/tree/main/templates/tsdown), while the Vue library asset adds Vue-specific build and type checking.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
- `webpack` 我不用,因为打出来的产物代码丑,配置复杂
|
|
8
|
-
- `rollup` 我最早用的就是这个,现在不用因为要装的包太多了,而且需要你对打包器有一定的理解,在打包复杂需要高度自定义的场景下使用
|
|
9
|
-
- `esbuild` 用的少,直接用不是很方便,但是可以基于它做高度自定义(写插件)
|
|
10
|
-
- `vite` 在 Vite 8 中默认基于 `rolldown` + `oxc`,假如你需要构建前端组件,这个就是首选,毕竟你也懒得去自己处理各种各样的样式文件吧,比如打包新版本 `vue` 组件,只能使用这个的库模式进行打包。
|
|
11
|
-
- `rolldown`/`tsdown` 适合更偏向库构建和工具链场景,但生态兼容面和迁移经验仍然不如 `vite`/`rollup` 成熟,是否采用要看你的实际约束
|
|
12
|
-
|
|
13
|
-
当前这个仓库已经把通用类库模板收敛到 `tsdown`,组件库则继续使用 `vite` 库模式。
|
|
14
|
-
|
|
15
|
-
## 过时的方案
|
|
16
|
-
|
|
17
|
-
:::warning 不推荐继续使用
|
|
18
|
-
`tsup` 和 `unbuild` 在这个模板仓库里已经被标记为过时方案,不再作为新项目的推荐构建工具。
|
|
19
|
-
:::
|
|
20
|
-
|
|
21
|
-
- `tsup` 曾经用于部分 TypeScript 包和服务模板,但现在这些模板已经迁移到 `tsdown`。如果旧项目里还有 `tsup.config.ts`,建议改成 `tsdown.config.ts`,并把 `build` / `dev` 脚本切到 `tsdown`。
|
|
22
|
-
- `unbuild` 曾经用于库包开发时的 stub 流程,但这里的新模板已经统一使用 `tsdown --watch` 处理开发构建。新项目不要继续引入 `unbuild`。
|
|
23
|
-
|
|
24
|
-
新建 TypeScript 类库优先使用 `tsdown` 模板;Vue 组件库继续使用 `vite` 库模式。
|
|
25
|
-
|
|
26
|
-
## tsdown
|
|
27
|
-
|
|
28
|
-
本项目当前的通用类库模板是 [tsdown](https://github.com/sonofmagic/monorepo-template/tree/main/templates/tsdown)
|
|
29
|
-
|
|
30
|
-
:::code-group
|
|
31
|
-
|
|
32
|
-
```ts [tsdown.config.ts]
|
|
33
|
-
import { defineConfig } from 'tsdown'
|
|
34
|
-
|
|
35
|
-
export default defineConfig({
|
|
36
|
-
entry: ['./src/index.ts'],
|
|
37
|
-
format: ['cjs', 'esm'],
|
|
38
|
-
dts: true,
|
|
39
|
-
clean: true,
|
|
40
|
-
target: 'node18',
|
|
41
|
-
})
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
:::
|
|
45
|
-
|
|
46
|
-
## vite
|
|
47
|
-
|
|
48
|
-
本项目的模板之一 [vue-lib](https://github.com/sonofmagic/monorepo-template/tree/main/templates/vue-lib)
|
|
49
|
-
|
|
50
|
-
你可以在 [`vite` 库模式官方文档](https://vite.dev/guide/build.html#library-mode) 来查看打包 `vue` 组件的方式
|
|
51
|
-
|
|
52
|
-
当然这些都已经被配置在 [vue-lib](https://github.com/sonofmagic/monorepo-template/tree/main/templates/vue-lib) 中了
|
|
5
|
+
Configure entrypoints, external dependencies, output formats, source maps, and declarations according to the package contract. Applications and libraries have different goals: application builds optimize deployment; library builds preserve reusable public boundaries.
|
|
@@ -1,93 +1,7 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Type Declarations
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Type declarations are part of a TypeScript package's public API.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Generate `.d.ts` files from the same source revision as runtime output, point `types` and export conditions at files included in the tarball, and use `tsd` tests for important inference and error behavior.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
这是因为你没有为你的包提供任何的 `dts`, 也就是 `xxx.d.ts` 文件
|
|
10
|
-
|
|
11
|
-
下面这 2 个标志想必大家在 `npmjs` 进行搜索的时候都见到过。
|
|
12
|
-
|
|
13
|
-
<img width="40" src="../assets/npm-ts.svg" alt="TypeScript built-in types badge" />
|
|
14
|
-
|
|
15
|
-
这个标志代表这个包发布的时候,本身包里面就自己提供了 `dts`,这个需要在打包生成出 `dts` 之后,在 `package.json` 中,通过 `types` 字段指定了 `dts` 的位置
|
|
16
|
-
|
|
17
|
-
比如我发的所有包 [weapp-tailwindcss](https://www.npmjs.com/package/weapp-tailwindcss), [weapp-vite](https://www.npmjs.com/package/weapp-vite), [modern-ahocorasick](https://www.npmjs.com/package/modern-ahocorasick) 等等...
|
|
18
|
-
|
|
19
|
-
<img width="40" src="../assets/npm-dt.svg" alt="DefinitelyTyped badge" />
|
|
20
|
-
|
|
21
|
-
这个标志代表这个包发布的时候,本身包里面没有 `dts`,但是有好心人给他写了 `dts`,并发布到了 `@types/*` 这个作用域下了,所以这个包等同于也有 `dts`,而且 `vscode` 也在发现你安装了这样的包之后,也会去下载 `@types/*` 这样的包,当然更好的方式是你要显式安装 `@types` 包
|
|
22
|
-
|
|
23
|
-
举个例子,比如 [lodash](https://www.npmjs.com/package/lodash) 和 [@types/lodash](https://www.npmjs.com/package/@types/lodash),点击 [lodash](https://www.npmjs.com/package/lodash) `npm` 主页面的这个标志,就直接跳转到 [@types/lodash](https://www.npmjs.com/package/@types/lodash)
|
|
24
|
-
|
|
25
|
-
> [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped) 这个是微软的仓库,用于发布管理所有的 `@types` 包
|
|
26
|
-
|
|
27
|
-
这里就需要提到包的质量判断标准,一般来说呈现下面的趋势:
|
|
28
|
-
|
|
29
|
-
<div class="flex justify-center">
|
|
30
|
-
<div class="flex items-center border p-6">
|
|
31
|
-
|
|
32
|
-
<img class="w-12" src="../assets/npm-ts.svg" alt="TypeScript built-in types badge" />
|
|
33
|
-
<div class="text-5xl mx-5">></div>
|
|
34
|
-
<img class="w-12" src="../assets/npm-dt.svg" alt="DefinitelyTyped badge" />
|
|
35
|
-
<div class="text-5xl mx-5">></div>
|
|
36
|
-
<div>什么标志都没有的包</div>
|
|
37
|
-
</div>
|
|
38
|
-
</div>
|
|
39
|
-
|
|
40
|
-
---
|
|
41
|
-
|
|
42
|
-
### `.d.ts` 文件的作用
|
|
43
|
-
|
|
44
|
-
- **描述模块或库的类型结构**,使 TypeScript 可以进行类型检查和代码补全。
|
|
45
|
-
- **为 JavaScript 库提供类型支持**,例如 jQuery、Lodash、React 等第三方库。
|
|
46
|
-
- **声明全局变量、模块、类、接口、函数等**,而不提供实际实现。
|
|
47
|
-
|
|
48
|
-
---
|
|
49
|
-
|
|
50
|
-
### 举个简单例子
|
|
51
|
-
|
|
52
|
-
假设你有一个 JavaScript 文件 `math.js`:
|
|
53
|
-
|
|
54
|
-
```js
|
|
55
|
-
// math.js
|
|
56
|
-
function add(a, b) {
|
|
57
|
-
return a + b
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
你可以写一个 `.d.ts` 文件来告诉 TypeScript 这个模块的类型:
|
|
62
|
-
|
|
63
|
-
```ts
|
|
64
|
-
// math.d.ts
|
|
65
|
-
declare function add(a: number, b: number): number
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
这样你在 TypeScript 中使用 `add` 函数时就能获得类型检查和智能提示了。
|
|
69
|
-
|
|
70
|
-
---
|
|
71
|
-
|
|
72
|
-
### 使用场景
|
|
73
|
-
|
|
74
|
-
1. **第三方库没有内置类型定义时**
|
|
75
|
-
- 可以使用 DefinitelyTyped 的类型库(安装例如 `@types/lodash`);
|
|
76
|
-
- 或者自己写 `.d.ts` 文件。
|
|
77
|
-
|
|
78
|
-
2. **为已有的 JS 代码添加类型支持**
|
|
79
|
-
- 特别是在从 JS 项目逐步迁移到 TS 时。
|
|
80
|
-
|
|
81
|
-
3. **定义公共 API 接口或模块类型**
|
|
82
|
-
- 比如声明一个共享的接口模块 `types.d.ts`,全项目通用。
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
### 类型声明的获取方式
|
|
87
|
-
|
|
88
|
-
- 手动编写 `.d.ts`
|
|
89
|
-
- 自动生成(例如通过 `tsc --declaration`)
|
|
90
|
-
- 安装类型定义包:
|
|
91
|
-
```bash
|
|
92
|
-
npm install --save-dev @types/express
|
|
93
|
-
```
|
|
7
|
+
Declaration bundling can simplify public output, but it must preserve module augmentation, generics, and referenced types. Always inspect the packed artifact rather than testing source imports alone.
|
|
@@ -1,84 +1,7 @@
|
|
|
1
|
-
# ESM vs
|
|
1
|
+
# ESM vs CommonJS
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
ES modules are the preferred format for new packages. CommonJS remains relevant when consumers or toolchains still require `require()`.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Choose ESM-only when your supported runtime matrix allows it. Publish dual formats only when the compatibility benefit justifies duplicate builds and interop testing.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- **ESM 是 ECMAScript 的官方模块规范**,跨平台和跨环境(如浏览器、Deno)都支持。
|
|
10
|
-
- 更有利于代码的可移植性和与未来标准兼容。
|
|
11
|
-
|
|
12
|
-
### 2. **静态分析能力更强**
|
|
13
|
-
|
|
14
|
-
- ESM 使用 `import` / `export`,**在解析阶段即可确定依赖关系**,这让:
|
|
15
|
-
- Tree Shaking(去除无用代码)成为可能。
|
|
16
|
-
- 更好地进行工具分析(如 Webpack、Rollup)。
|
|
17
|
-
|
|
18
|
-
### 3. **支持异步加载**
|
|
19
|
-
|
|
20
|
-
- ESM 模块加载是**异步的**,允许更灵活的模块加载策略(尤其适合在浏览器环境或网络环境下)。
|
|
21
|
-
- 支持 `import()` 动态导入,可以实现按需加载。
|
|
22
|
-
|
|
23
|
-
### 4. **更好的模块作用域**
|
|
24
|
-
|
|
25
|
-
- 每个 ESM 模块都有自己的作用域,**默认是严格模式**(`use strict`),无需显式声明。
|
|
26
|
-
- 避免了 CJS 中的某些副作用或全局变量污染问题。
|
|
27
|
-
|
|
28
|
-
### 5. **顶层 `await` 支持**
|
|
29
|
-
|
|
30
|
-
- 在支持的环境下,ESM 模块可以使用**顶层 await**,这在处理异步初始化逻辑时非常方便。
|
|
31
|
-
|
|
32
|
-
### 6. **统一生态趋势**
|
|
33
|
-
|
|
34
|
-
- 越来越多的现代 JavaScript 项目和库采用 ESM,比如 Vite、ESBuild、Deno 等工具链优先支持 ESM。
|
|
35
|
-
|
|
36
|
-
---
|
|
37
|
-
|
|
38
|
-
## 对比小结
|
|
39
|
-
|
|
40
|
-
| 特性 | ESM | CommonJS (CJS) |
|
|
41
|
-
| ----------------- | --------------------- | ---------------------------- |
|
|
42
|
-
| 模块语法 | `import` / `export` | `require` / `module.exports` |
|
|
43
|
-
| 加载方式 | 静态分析 + 异步加载 | 运行时同步加载 |
|
|
44
|
-
| 标准化 | 是(ECMAScript 标准) | 否(Node.js 专有) |
|
|
45
|
-
| Tree Shaking 支持 | ✅ | ❌ |
|
|
46
|
-
| 顶层 await 支持 | ✅(Node.js ≥ 14.8) | ❌ |
|
|
47
|
-
| 浏览器支持 | ✅ | ❌ |
|
|
48
|
-
| 动态导入 | `import()` | `require()` |
|
|
49
|
-
|
|
50
|
-
---
|
|
51
|
-
|
|
52
|
-
## 使用 ESM 的注意事项(在 Node.js 中)
|
|
53
|
-
|
|
54
|
-
- `package.json` 中需要设置 `"type": "module"`。
|
|
55
|
-
- 文件扩展名必须为 `.mjs` 或 `.js`(视 `type` 而定)。
|
|
56
|
-
- `__filename`、`__dirname` 等 Node.js CJS 特有变量不可直接使用(需 `import.meta.url` 代替, 高版本 `Nodejs` 可以使用 `import.meta.dirname` 和 `import.meta.filename`)。
|
|
57
|
-
|
|
58
|
-
---
|
|
59
|
-
|
|
60
|
-
## 适合使用 ESM 的场景
|
|
61
|
-
|
|
62
|
-
- 对于新项目,不论是前端还是服务端,你应该始终使用 `ESM`。
|
|
63
|
-
- 需要兼容浏览器或打包工具的项目
|
|
64
|
-
- 有 `Tree Shaking` 需求的库开发
|
|
65
|
-
|
|
66
|
-
## esm 中使用 require
|
|
67
|
-
|
|
68
|
-
在 `esm` 格式中的 `js` 中使用 `require` 会报错
|
|
69
|
-
|
|
70
|
-
```sh
|
|
71
|
-
ReferenceError: require is not defined in ES module scope, you can use import instead
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
另外也有一种适用于 `nodejs` 的 `esm` 中使用 `require` 做法:
|
|
75
|
-
|
|
76
|
-
```js
|
|
77
|
-
import { createRequire } from 'node:module'
|
|
78
|
-
|
|
79
|
-
const require = createRequire(import.meta.filename)
|
|
80
|
-
|
|
81
|
-
const { sayHello } = require('icebreaker-npm-basic-package')
|
|
82
|
-
|
|
83
|
-
sayHello()
|
|
84
|
-
```
|
|
7
|
+
For dual packages, map `import`, `require`, and `types` conditions explicitly and test each consumer path. Avoid exporting different logical module instances from the two formats.
|
|
@@ -1,55 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
outline: [2, 4]
|
|
3
|
-
---
|
|
1
|
+
# Modern Package Guide
|
|
4
2
|
|
|
5
|
-
|
|
3
|
+
Modern packages should expose a small, explicit API and generate artifacts that match their declared contract.
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
## Checklist
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
- Choose ESM-only or intentional dual-package support.
|
|
8
|
+
- Declare every public subpath in `exports`.
|
|
9
|
+
- Emit and test type declarations.
|
|
10
|
+
- Keep development-only files out of the package tarball.
|
|
11
|
+
- Validate the supported Node and bundler matrix.
|
|
12
|
+
- Record public changes through repository versioning.
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
此代码的演变用例见 [examples](https://github.com/sonofmagic/monorepo-template/tree/main/templates/vitepress/why/examples)
|
|
18
|
-
|
|
19
|
-
## 确定包的模块入口点
|
|
20
|
-
|
|
21
|
-
详见 [package-entry-points](./package-entry-points)
|
|
22
|
-
|
|
23
|
-
## 添加 DTS
|
|
24
|
-
|
|
25
|
-
类型提示其实就是最好的文档,为了让使用者,能在IDE里面直接点出来方法,类型和枚举,我们需要添加它
|
|
26
|
-
|
|
27
|
-
详见 [DTS](./dts.md)
|
|
28
|
-
|
|
29
|
-
## 更改为 ESM 格式优先
|
|
30
|
-
|
|
31
|
-
优先 ESM 格式符合我们面向未来编程的原则。
|
|
32
|
-
|
|
33
|
-
详见 [ESM vs CJS](./esm-vs-cjs.md)
|
|
34
|
-
|
|
35
|
-
## 使用 TypeScript 进行编写
|
|
36
|
-
|
|
37
|
-
既然我们都要使用一份代码,去生成 `cjs` / `esm` / `dts`,那么我们当然可以完全使用 `TypeScript` 进行编写,去生成对应的产物即可
|
|
38
|
-
|
|
39
|
-
详见 [使用 TypeScript 编写代码](./typescript)
|
|
40
|
-
|
|
41
|
-
## 使用打包器
|
|
42
|
-
|
|
43
|
-
`TypeScript` 自带的 `tsc` 功能太弱了,当我们要进行一些前端工程化的改造时候,光使用 `tsc` + `script脚本` 的方式已经满足不了我们的需求
|
|
44
|
-
|
|
45
|
-
所有我们这时候需要引入打包器,来和 `TypeScript` 一起协作
|
|
46
|
-
|
|
47
|
-
详见 [使用打包器](./bundlers)
|
|
48
|
-
|
|
49
|
-
## 写一份可读的 README
|
|
50
|
-
|
|
51
|
-
假如你写的 `npm` 包已经复杂到一个 `README.md` 文档无法解决开发者的遇到的问题了,那么就准备一个文档网站
|
|
52
|
-
|
|
53
|
-
## 添加单元测试(额外)
|
|
54
|
-
|
|
55
|
-
本模板使用的就是 `vitest`,具体使用方式见 `vitest` 文档
|
|
14
|
+
Start with [ESM vs CommonJS](./esm-vs-cjs.md), then review [entry points](./package-entry-points.md) and [declarations](./dts.md).
|