@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,128 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
outline: [2, 4]
|
|
3
|
-
---
|
|
1
|
+
# Package Entry Points
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
在 `package.json` 中,定义模块的入口点 (`entry point`) 字段是及其重要的
|
|
8
|
-
|
|
9
|
-
## package.json 代码示例
|
|
10
|
-
|
|
11
|
-
```jsonc
|
|
12
|
-
{
|
|
13
|
-
"name": "icebreaker-npm-basic-package",
|
|
14
|
-
"version": "1.0.0",
|
|
15
|
-
"type": "module",
|
|
16
|
-
"main": "./index.cjs", // CommonJS 主入口(用于 Node require)
|
|
17
|
-
"module": "./index.mjs", // 非标准,但很多构建工具支持(ESM)
|
|
18
|
-
"types": "./index.d.ts", // TypeScript 类型定义
|
|
19
|
-
"exports": {
|
|
20
|
-
".": {
|
|
21
|
-
"types": "./index.d.ts", // TypeScript 类型定义
|
|
22
|
-
"require": "./index.cjs", // Node require 使用 CommonJS
|
|
23
|
-
"import": "./index.mjs" // Node import 使用 ESM
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
### 📝 字段说明:
|
|
30
|
-
|
|
31
|
-
| 字段 | 说明 |
|
|
32
|
-
| ------------------ | ------------------------------------------------ |
|
|
33
|
-
| `"type": "module"` | 默认将 `.js` 文件视为 ESM |
|
|
34
|
-
| `"main"` | Node 中 `require('pkg')` 会使用 CommonJS 文件 |
|
|
35
|
-
| `"module"` | 给打包工具提供 ESM 入口,非标准,但有用 |
|
|
36
|
-
| `"exports"` | 更现代且明确的方式,指明模块格式,兼容 Node >=12 |
|
|
37
|
-
| `"types"` | 给 TypeScript 指明类型定义文件的位置 |
|
|
38
|
-
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
官方文档: [package-entry-points](https://nodejs.org/api/packages.html#package-entry-points)
|
|
42
|
-
|
|
43
|
-
## 为什么说 module 是非标准的?
|
|
44
|
-
|
|
45
|
-
在 `package.json` 中,`"module"` 字段是一个 **非标准的字段**,但在现代前端工具(如 Webpack、Rollup、Vite 等)中被广泛使用,用于指向 **ES Module 格式的入口文件**,以便这些工具能够做更好的静态分析与 tree-shaking。
|
|
46
|
-
|
|
47
|
-
下面是不同工具/环境下可能会读取 `"module"` 字段的情况:
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
### ✅ **什么情况下会加载 `"module"` 字段?**
|
|
52
|
-
|
|
53
|
-
#### **打包工具(Webpack、Rollup、Vite、Snowpack, Parcel 等)**
|
|
54
|
-
|
|
55
|
-
- 当你使用这些工具打包代码时,它们会优先尝试读取:
|
|
56
|
-
1. `"exports"` 字段(如果存在,优先于其他字段)
|
|
57
|
-
2. `"module"` 字段(通常表示 ESM 格式)
|
|
58
|
-
3. `"main"` 字段(通常表示 CommonJS 格式)
|
|
59
|
-
|
|
60
|
-
示例:
|
|
61
|
-
|
|
62
|
-
```js
|
|
63
|
-
// 在 Webpack 中引入某个 npm 包时,如果该包的 package.json 有 module 字段
|
|
64
|
-
// Webpack 会优先使用这个字段所指向的 ESM 文件
|
|
65
|
-
import foo from 'icebreaker-npm-basic-package'
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
> `Vite、Snowpack, Parcel` 这些工具天生以 ESM 为主,会优先读取 `"module"` 字段。
|
|
69
|
-
|
|
70
|
-
---
|
|
71
|
-
|
|
72
|
-
### 🚫 **不会加载 `"module"` 字段的情况**
|
|
73
|
-
|
|
74
|
-
#### **Node.js 本身**
|
|
75
|
-
|
|
76
|
-
- Node.js 并不识别 `"module"` 字段,加载模块时它依赖的是:
|
|
77
|
-
- `"type"` 字段(决定是否为 ESM 模式)
|
|
78
|
-
- `"main"` 字段(默认入口)
|
|
79
|
-
- 或者直接通过 `"exports"` 字段(推荐现代做法)
|
|
80
|
-
|
|
81
|
-
例如,在你的 `package.json` 中:
|
|
3
|
+
Use the `exports` field to define the package's supported public paths.
|
|
82
4
|
|
|
83
5
|
```json
|
|
84
|
-
{
|
|
85
|
-
"type": "module",
|
|
86
|
-
"main": "index.cjs",
|
|
87
|
-
"module": "index.js"
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
- 你运行 `node .` 时,Node 会根据 `"main"` 加载 `index.cjs`
|
|
92
|
-
- 如果你运行 `node index.js`,它会根据文件扩展名和 `"type": "module"` 以 ESM 模式运行,但并不会自动从 `"module"` 字段寻找入口
|
|
93
|
-
|
|
94
|
-
---
|
|
95
|
-
|
|
96
|
-
### 推荐现代做法(如要兼容多种环境):
|
|
97
|
-
|
|
98
|
-
可以使用 `exports` 字段更明确地配置入口文件:
|
|
99
|
-
|
|
100
|
-
```jsonc
|
|
101
6
|
{
|
|
102
7
|
"exports": {
|
|
103
8
|
".": {
|
|
104
|
-
"types": "./index.d.ts",
|
|
105
|
-
"
|
|
106
|
-
"import": "./index.js"
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
107
11
|
},
|
|
108
|
-
"./
|
|
109
|
-
"types": "./xxx.d.ts",
|
|
110
|
-
"require": "./xxx.cjs",
|
|
111
|
-
"import": "./xxx.js"
|
|
112
|
-
}
|
|
12
|
+
"./package.json": "./package.json"
|
|
113
13
|
}
|
|
114
14
|
}
|
|
115
15
|
```
|
|
116
16
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
---
|
|
120
|
-
|
|
121
|
-
### 总结:
|
|
122
|
-
|
|
123
|
-
| 环境/工具 | 是否使用 `"module"` 字段 | 说明 |
|
|
124
|
-
| -------------- | ------------------------ | ----------------------------- |
|
|
125
|
-
| Node.js | ❌ 不会使用 | 使用 `"main"` 或 `"exports"` |
|
|
126
|
-
| Webpack/Rollup | ✅ 会使用 | 优先用来加载 ESM 版本 |
|
|
127
|
-
| Vite/Snowpack | ✅ 会使用 | 用于选择 ESM 格式 |
|
|
128
|
-
| TypeScript | ❌ 不直接使用 | 会用 `"types"` 字段找类型声明 |
|
|
17
|
+
Do not rely on consumers reaching into undeclared internal files. Every exported path should have runtime output, types where applicable, and a compatibility test.
|
|
@@ -1,155 +1,7 @@
|
|
|
1
|
-
#
|
|
1
|
+
# TypeScript Packages
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Use TypeScript to validate source and to publish a precise consumer contract.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Keep the source typecheck separate from artifact generation, enable strict settings appropriate for libraries, and avoid path aliases that cannot be resolved by consumers. Vue packages should run `vue-tsc`; non-Vue TypeScript packages should run `tsc`.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
安装 `typescript` 以及完成初始化创建 `tsconfig.json`
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
npm i -D typescript # 安装 typescript
|
|
13
|
-
npx tsc --init # 创建 tsconfig.json
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
添加 `src` 目录,在里面创建 `index.ts` 文件
|
|
17
|
-
|
|
18
|
-
```ts
|
|
19
|
-
export function sayHello() {
|
|
20
|
-
const message = 'hello world typescript'
|
|
21
|
-
console.log(message)
|
|
22
|
-
return message
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
console.log(`load package icebreaker-npm-basic-package`)
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## 调整 `tsconfig.json`
|
|
29
|
-
|
|
30
|
-
```jsonc
|
|
31
|
-
{
|
|
32
|
-
"compilerOptions": {
|
|
33
|
-
"target": "ES2020",
|
|
34
|
-
"rootDir": "./src",
|
|
35
|
-
"module": "ESNext",
|
|
36
|
-
"moduleResolution": "bundler",
|
|
37
|
-
"resolveJsonModule": true, // 支持 import json
|
|
38
|
-
"strict": true, // 严格模式
|
|
39
|
-
"declaration": true, // 生成 dts
|
|
40
|
-
"declarationMap": true, // dts 的 sourcemap
|
|
41
|
-
"outDir": "./dist", // 生成 dts 的目录
|
|
42
|
-
"sourceMap": true, // 生成 sourcemap
|
|
43
|
-
"esModuleInterop": true,
|
|
44
|
-
"forceConsistentCasingInFileNames": true,
|
|
45
|
-
"skipLibCheck": true
|
|
46
|
-
},
|
|
47
|
-
"include": ["src"]
|
|
48
|
-
}
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
更多的配置 https://www.typescriptlang.org/tsconfig/
|
|
52
|
-
|
|
53
|
-
## 创建 `cjs` 和 `esm` 各自格式的 `tsconfig.json`
|
|
54
|
-
|
|
55
|
-
:::code-group
|
|
56
|
-
|
|
57
|
-
```jsonc [tsconfig.esm.json]
|
|
58
|
-
{
|
|
59
|
-
"extends": "./tsconfig.json",
|
|
60
|
-
"compilerOptions": {
|
|
61
|
-
"module": "ESNext",
|
|
62
|
-
"outDir": "./dist/esm"
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
```jsonc [tsconfig.cjs.json]
|
|
68
|
-
{
|
|
69
|
-
"extends": "./tsconfig.json",
|
|
70
|
-
"compilerOptions": {
|
|
71
|
-
"module": "commonjs",
|
|
72
|
-
"moduleResolution": "node10",
|
|
73
|
-
"outDir": "./dist/cjs"
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
:::
|
|
79
|
-
|
|
80
|
-
## 开始编译
|
|
81
|
-
|
|
82
|
-
在 `package.json` 的 `scripts` 中添加脚本
|
|
83
|
-
|
|
84
|
-
```jsonc
|
|
85
|
-
{
|
|
86
|
-
"build:cjs": "tsc --project tsconfig.cjs.json && node rename-ext.js dist/cjs .js .cjs && node rename-ext.js dist/cjs .js.map .cjs.map",
|
|
87
|
-
"build:esm": "tsc --project tsconfig.esm.json",
|
|
88
|
-
"build": "npm run build:cjs && npm run build:esm"
|
|
89
|
-
}
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
为什么这里还需要执行 `rename-ext`? 因为你安装使用一个 `npm` 包的时候,默认情况下会使用 `package.json` 中的 `type` 字段去决定这个包 `js` 代码模块加载器
|
|
93
|
-
|
|
94
|
-
通常 `nodejs` 中会存在 `2` 个模块加载器:
|
|
95
|
-
|
|
96
|
-
- [Modules: CommonJS modules](https://nodejs.org/docs/latest/api/modules.html)
|
|
97
|
-
- [Modules: ECMAScript modules](https://nodejs.org/docs/latest/api/esm.html)
|
|
98
|
-
|
|
99
|
-
假如你声明了 `"type": "module"`,那么 `nodejs` 会使用 `ESM` 模块加载器,去加载这个包下面的所有 `.js`
|
|
100
|
-
|
|
101
|
-
反之,则使用 `CJS` 模块加载器,去加载这个包下面的所有 `.js`
|
|
102
|
-
|
|
103
|
-
但是有 `2` 个后缀是特例,`.cjs` 和 `.mjs` , 他们在 `js` 前面加了 `c` 和 `m` 代表指定 `cjs`/`esm` 模块加载器,去加载这个 `js` 代码
|
|
104
|
-
|
|
105
|
-
而我们这个包,已经被声明了 `"type": "module"`,所以是无法直接运行后缀是 `.js` 的 `cjs` 文件的,必须把后缀从 `.js` 转变为 `.cjs`
|
|
106
|
-
|
|
107
|
-
## 更改 `package.json` 中模块入口点
|
|
108
|
-
|
|
109
|
-
```jsonc
|
|
110
|
-
{
|
|
111
|
-
"name": "icebreaker-npm-basic-package",
|
|
112
|
-
"type": "module",
|
|
113
|
-
"exports": {
|
|
114
|
-
".": {
|
|
115
|
-
"import": {
|
|
116
|
-
"types": "./dist/esm/index.d.ts",
|
|
117
|
-
"default": "./dist/esm/index.js"
|
|
118
|
-
},
|
|
119
|
-
"require": {
|
|
120
|
-
"types": "./dist/cjs/index.d.ts",
|
|
121
|
-
"default": "./dist/cjs/index.cjs"
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
},
|
|
125
|
-
"files": [
|
|
126
|
-
"dist" // [!code highlight]
|
|
127
|
-
]
|
|
128
|
-
}
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
给不同的引入方式,设置不同的模块入口,和不同的类型提示。
|
|
132
|
-
|
|
133
|
-
同时也要注意这里我们添加了 `files` 字段,因为此时 `src` 目录下的源代码是不需要发布到 `npmjs` 上去的
|
|
134
|
-
|
|
135
|
-
你也可以通过执行 `npm pack --dry-run` 查看当前哪些文件会在发布的时候,被上传到 `npmjs` 上去
|
|
136
|
-
|
|
137
|
-
## 调试项目
|
|
138
|
-
|
|
139
|
-
### 利用 `sourcemap` 调试项目
|
|
140
|
-
|
|
141
|
-
`source map`(源码映射) 是一种用来 把编译/打包/压缩后的代码映射回原始代码 的技术
|
|
142
|
-
|
|
143
|
-
它是用来解决 生成的代码和原始代码不一样, 无法直接调试源代码,这样一个问题。
|
|
144
|
-
|
|
145
|
-
使用方式,在打开 `sourcemap` 选项后,生成对应的 `sourcemap` 文件,然后就可以在 `ts` 代码中打上断点,直接调试源代码了。
|
|
146
|
-
|
|
147
|
-
### 直接运行 `typescript` 调试项目
|
|
148
|
-
|
|
149
|
-
过去我们使用 `ts-node` 来直接运行 `ts`,随着时代的发展,`ts-node` 已经逐渐被 `tsx` 所取代
|
|
150
|
-
|
|
151
|
-
当然市面上直接转译运行 `typescript` 的工具还是非常多的,比如 `tsx` 和 `bundle-require` 都是基于 `esbuild`
|
|
152
|
-
|
|
153
|
-
`jiti` 这种基于 `babel` 的,还有 `swc-node` 这种基于 `swc` 的, `@oxc-node/core` 这种基于 `oxc` 的
|
|
154
|
-
|
|
155
|
-
当然,在不使用 `emitDecoratorMetadata` 这种 `typescript` 的装饰器的高级用法的情况下,使用 `tsx` 是比较好的选择
|
|
7
|
+
Public type behavior belongs in `tsd` tests. Runtime tests should import built output so module resolution matches delivery.
|
|
@@ -1,146 +1,19 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
18
|
-
},
|
|
19
|
-
"author": "",
|
|
20
|
-
"license": "ISC",
|
|
21
|
-
"description": ""
|
|
22
|
-
}
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
> 你操作到这里,`package.json` 的 `name` 一定要换成你自己的,因为这个包我已经发布了,所以名字已经被我占据了你用不了
|
|
26
|
-
|
|
27
|
-
## 创建一个 `index.js`
|
|
28
|
-
|
|
29
|
-
在你的 `package.json` 同目录下创建一个 `index.js`,内容如下
|
|
30
|
-
|
|
31
|
-
```js
|
|
32
|
-
console.log(`load ${__filename}`)
|
|
33
|
-
|
|
34
|
-
function sayHello() {
|
|
35
|
-
console.log('hello world')
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
module.exports = {
|
|
39
|
-
sayHello
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
> 按照现代包的要求,其实是优先 esm 格式的,但是上面的例子还是用的 cjs,这个会在下个章节提到
|
|
44
|
-
|
|
45
|
-
## 发包到 npmjs
|
|
46
|
-
|
|
47
|
-
然后你在 `package.json` 同级目录下,执行 `npm publish`
|
|
48
|
-
|
|
49
|
-
然后恭喜你,你失败了!
|
|
50
|
-
|
|
51
|
-
为什么失败?你连 `npmjs` 账号都还没有注册呢!
|
|
52
|
-
|
|
53
|
-
执行 `npm publish` 是需要先 `npm login` 登录你的 `npmjs` 账号的
|
|
54
|
-
|
|
55
|
-
赶紧去 [`www.npmjs.com`](https://www.npmjs.com/) 右上角注册一个账号吧!
|
|
56
|
-
|
|
57
|
-
## 获取 Access Token
|
|
58
|
-
|
|
59
|
-
注册好一个账号之后,再执行 `npm login`, 你就可以在弹出来的页面中,登录你的账号
|
|
60
|
-
|
|
61
|
-
登录成功之后,默认情况下,他会给你去生成一个 `Access Token` 作为你的发包凭证
|
|
62
|
-
|
|
63
|
-
此时会写入到你全局 `.npmrc` 的文件中,类似于下面一行
|
|
64
|
-
|
|
65
|
-
```txt
|
|
66
|
-
registry.npmjs.org/:_authToken=npm_hashhashhashhashhashhashhashhashhash
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
假如这一行存在,说明你本地的 `npm Access Token` 就设置好了,然后你才有发包的权限。
|
|
70
|
-
|
|
71
|
-
> 你也可以在 `https://www.npmjs.com/settings/<你的用户名>/tokens` 中管理你的 `token`,给不同的 `token` 设置不同的作用域,有效期(目前最长 90 天)和 `ip` 限制,帮助你适配正常开发,`CI/CD`,`Token` 分发的各种场景;如需避免手动轮换,CI 场景推荐使用 npm 官方的 OIDC 方案获取临时 `NODE_AUTH_TOKEN`,并在工作流开启 `id-token: write` 权限。
|
|
72
|
-
|
|
73
|
-
同样发私有源包也是同理:
|
|
74
|
-
|
|
75
|
-
```txt
|
|
76
|
-
//npm.icebreaker.top/:_authToken=npm_hashhashhashhashhashhashhashhashhash
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
你必须有这个凭证,你才有这个权限。
|
|
80
|
-
|
|
81
|
-
## 成功发包
|
|
82
|
-
|
|
83
|
-
配置好 `npm Access Token` 执行 `npm publish` 然后就能发包成功了
|
|
84
|
-
|
|
85
|
-
```sh
|
|
86
|
-
npm notice
|
|
87
|
-
npm notice 📦 icebreaker-npm-basic-package@1.0.0
|
|
88
|
-
npm notice Tarball Contents
|
|
89
|
-
npm notice 120B index.js
|
|
90
|
-
npm notice 187B package.json
|
|
91
|
-
npm notice Tarball Details
|
|
92
|
-
npm notice name: icebreaker-npm-basic-package
|
|
93
|
-
npm notice version: 1.0.0
|
|
94
|
-
npm notice filename: icebreaker-npm-basic-package-1.0.0.tgz
|
|
95
|
-
npm notice package size: 326 B
|
|
96
|
-
npm notice unpacked size: 307 B
|
|
97
|
-
npm notice shasum: fc4624e7bddd96a6ffac505f672b62de55898d6b
|
|
98
|
-
npm notice integrity: sha512-2UtWkYX5tEUyu[...]ZFF64Wvq+Vw0Q==
|
|
99
|
-
npm notice total files: 2
|
|
100
|
-
npm notice
|
|
101
|
-
npm notice Publishing to https://registry.npmjs.org/ with tag latest and default access
|
|
102
|
-
+ icebreaker-npm-basic-package@1.0.0
|
|
1
|
+
# Publishing An npm Package
|
|
2
|
+
|
|
3
|
+
1. Define explicit runtime and type entrypoints.
|
|
4
|
+
2. Build the package and run tests against built artifacts.
|
|
5
|
+
3. Inspect `pnpm pack` output.
|
|
6
|
+
4. Record a change intent and verify the version plan.
|
|
7
|
+
5. Publish with provenance and the intended access level.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm build
|
|
11
|
+
pnpm lint
|
|
12
|
+
pnpm typecheck
|
|
13
|
+
pnpm tsd
|
|
14
|
+
pnpm test
|
|
15
|
+
pnpm pack
|
|
16
|
+
pnpm change
|
|
103
17
|
```
|
|
104
18
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
比如我这个包就能通过 `https://www.npmjs.com/package/icebreaker-npm-basic-package` 直接访问
|
|
108
|
-
|
|
109
|
-
## 安装调用
|
|
110
|
-
|
|
111
|
-
你可以执行 `npm i <你的包名>` 直接获取到你的包,进行调用了。
|
|
112
|
-
|
|
113
|
-
> 假如你没有使用官方的 `registry.npmjs.org`,反而使用的是 `npmmirror.com` 这种国内的淘宝镜像源,那么你的包同步到国内镜像源,可能需要一段时间
|
|
114
|
-
>
|
|
115
|
-
> 你可以通过 `npm i -g cnpm`, `cnpm sync <你的包名>` 进行手动同步,加快这个流程。
|
|
116
|
-
|
|
117
|
-
安装好之后,使用 `nodejs` 执行代码:
|
|
118
|
-
|
|
119
|
-
```js
|
|
120
|
-
const { sayHello } = require('icebreaker-npm-basic-package')
|
|
121
|
-
|
|
122
|
-
sayHello()
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
出现
|
|
126
|
-
|
|
127
|
-
```txt
|
|
128
|
-
load /your/path/to/node_modules/icebreaker-npm-basic-package/index.js
|
|
129
|
-
hello world
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
证明你安装调用成功了!实际上很简单吧!
|
|
133
|
-
|
|
134
|
-
## 更进一步
|
|
135
|
-
|
|
136
|
-
恭喜你,你已经踏出了你的第一步,你已经来到了 `Nodejs` 这座高山的山脚下准备进行攀登。
|
|
137
|
-
|
|
138
|
-
山上云雾缭绕,看不到顶,攀登的路上, 险象环生,爬的越高越感觉举步维艰。
|
|
139
|
-
|
|
140
|
-
但是也用不着害怕,正如荀子在《劝学》篇所写下的: `不积跬步,无以至千里。不积小流,无以成江海`。
|
|
141
|
-
|
|
142
|
-
量变促成质变,等你到达那个质变的点,你就会发现自己看待代码的眼光已经完全改变了,从新的角度去看,很容易一眼看出问题的本质。
|
|
143
|
-
|
|
144
|
-
所以,多看优秀的代码,多去调试开源项目的源代码,多写代码多思考,你就成长了!
|
|
145
|
-
|
|
146
|
-
接下来让我们改进一下这个包,让他更加的现代化。
|
|
19
|
+
Never publish template source workspaces that are intentionally marked `private: true`.
|
|
@@ -1,162 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
outline: [2, 4]
|
|
3
|
-
---
|
|
1
|
+
# What Is An npm Package?
|
|
4
2
|
|
|
5
|
-
|
|
3
|
+
An npm package is a directory described by `package.json`. It can expose runtime code, types, command-line bins, assets, or configuration.
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
The public contract includes the package name, version, `exports`, `types`, `bin`, supported runtimes, files included in the tarball, and semantic versioning behavior. Treat these fields as API design, not publishing metadata afterthoughts.
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
**npm(Node Package Manager)** 是 Node.js 的官方包管理工具,用于:
|
|
12
|
-
|
|
13
|
-
- 安装依赖库;
|
|
14
|
-
- 管理项目依赖;
|
|
15
|
-
- 发布自己的模块到 npm 生态。
|
|
16
|
-
|
|
17
|
-
命令行工具:`npm install`, `npm update`, `npm publish` 等。
|
|
18
|
-
|
|
19
|
-
同样 `yarn` / `pnpm` 也是 **npm(Node Package Manager)**,不过他们是非 `Nodejs` 官方的
|
|
20
|
-
|
|
21
|
-
他们的出现或多或少的解决了官方 `npm` 的很多问题,完全可以作为官方 `npm` 工具的平替,在社区里备受推崇,展现出 `Nodejs` 社区旺盛的生命力。
|
|
22
|
-
|
|
23
|
-
尤其是 `pnpm`,比官方 `npm` 好用太多,目前大家把很多对 `npm` 包管理器的期望都寄托在他身上。
|
|
24
|
-
|
|
25
|
-
> `pnpm` 对于 `Nodejs`,地位类似于 [`uv`](https://github.com/astral-sh/uv) 对于 `Python` 他们都不是官方项目,但是却逐渐成为了主流
|
|
26
|
-
|
|
27
|
-
<!-- `deno` / `bun` -->
|
|
28
|
-
|
|
29
|
-
---
|
|
30
|
-
|
|
31
|
-
## 什么是一个 npm 包?
|
|
32
|
-
|
|
33
|
-
一个 **npm 包** 通常具有以下结构:
|
|
34
|
-
|
|
35
|
-
```txt
|
|
36
|
-
my-package/
|
|
37
|
-
├── package.json // 包的元数据(名字、版本、依赖等)
|
|
38
|
-
├── index.js // 主文件(或其它入口)
|
|
39
|
-
└── lib/ // 模块代码
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
`package.json` 是核心文件,定义了:
|
|
43
|
-
|
|
44
|
-
- `name`:包的名称(唯一,不能与其它包冲突)
|
|
45
|
-
- `version`:版本号(如 `1.0.0`)
|
|
46
|
-
- `main`:主入口文件(默认是 `index.js`)
|
|
47
|
-
- `dependencies`:依赖的其他 npm 包
|
|
48
|
-
- `files`: 哪些文件应该被上传,用于忽略掉不需要的文件类型
|
|
49
|
-
|
|
50
|
-
> 更多字段,可以查看 [`configuring-npm/package-json`](https://docs.npmjs.com/cli/v11/configuring-npm/package-json)
|
|
51
|
-
|
|
52
|
-
### npm 包关系类型
|
|
53
|
-
|
|
54
|
-
#### **公共包**
|
|
55
|
-
|
|
56
|
-
来自 [npmjs.com](https://www.npmjs.com/) ,如 `lodash`, `react`, `axios`
|
|
57
|
-
|
|
58
|
-
[yarnpkg.com](https://yarnpkg.com/), [npmmirror(淘宝源)](https://npmmirror.com/) 这种本质上都是 [npmjs.com](https://www.npmjs.com/) 的镜像源,定期从 [npmjs.com](https://www.npmjs.com/) 同步包到他们的源上 (所以 `npmmirror` 有 `cnpm sync` 命令和 `同步功能` 就是为了在自动同步不及时的时候,手动同步的)
|
|
59
|
-
|
|
60
|
-
假如我们要发 **公共包**,那肯定把包发到 [npmjs.com](https://www.npmjs.com/) 上的,因为发其他公共源没有意义。
|
|
61
|
-
|
|
62
|
-
#### **私有包**
|
|
63
|
-
|
|
64
|
-
企业内部发布的包,需配置私有 `npm registry`。
|
|
65
|
-
|
|
66
|
-
注册源可以在用户本地 `User` 全局的 `.npmrc`, 或者是项目中的 `.npmrc` 进行配置
|
|
67
|
-
|
|
68
|
-
比如:
|
|
69
|
-
|
|
70
|
-
```txt
|
|
71
|
-
registry=https://registry.npmmirror.com/
|
|
72
|
-
@ice:registry=http://npm.icebreaker.top
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
就代表所有 `@ice/xxx` 这种包都从 `http://npm.icebreaker.top` 这里获取,其他包从 `https://registry.npmmirror.com/`
|
|
76
|
-
|
|
77
|
-
假如你不设置 `registry` 默认从最官方的源 `https://registry.npmjs.org/` 中获取包
|
|
78
|
-
|
|
79
|
-
假如你对 `npm私有源` 的搭建感兴趣,可以看看我写的这篇文章 [使用 Verdaccio 私有化 npm 源指南](https://juejin.cn/post/7357016488698839050)
|
|
80
|
-
|
|
81
|
-
#### **本地包**
|
|
82
|
-
|
|
83
|
-
可直接从 `文件夹`, `Git 仓库`, `monorepo workspace` 安装的包
|
|
84
|
-
|
|
85
|
-
因为其实我们在 `dependencies` 和 `devDependencies` 注册的包,协议可以是多种多样的,比如:
|
|
86
|
-
|
|
87
|
-
```jsonc
|
|
88
|
-
{
|
|
89
|
-
"dependencies": {
|
|
90
|
-
// npm 注册源上拿
|
|
91
|
-
"foo": "1.0.0 - 2.9999.9999",
|
|
92
|
-
"bar": ">=1.0.2 <2.1.2",
|
|
93
|
-
"baz": ">1.0.2 <=2.3.4",
|
|
94
|
-
"boo": "2.0.1",
|
|
95
|
-
"qux": "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0",
|
|
96
|
-
"til": "~1.2",
|
|
97
|
-
"elf": "~1.2.3",
|
|
98
|
-
"two": "2.x",
|
|
99
|
-
"thr": "3.3.x",
|
|
100
|
-
"lat": "latest",
|
|
101
|
-
// http 协议拿
|
|
102
|
-
"asd": "http://npmjs.com/example.tar.gz",
|
|
103
|
-
// git 协议拿
|
|
104
|
-
"xxx": "git+ssh://git@github.com:npm/cli#semver:^5.0",
|
|
105
|
-
// 从 github 拿
|
|
106
|
-
"express": "expressjs/express",
|
|
107
|
-
"mocha": "mochajs/mocha#4727d357ea",
|
|
108
|
-
"module": "npm/example-github-repo#feature/branch",
|
|
109
|
-
// 本地文件协议拿
|
|
110
|
-
"dyl": "file:../dyl",
|
|
111
|
-
"kpg": "file:../foo/bar",
|
|
112
|
-
// monorepo workspace
|
|
113
|
-
"xya": "workspace:*"
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
详见官方文档 [dependencies详解](https://docs.npmjs.com/cli/v11/configuring-npm/package-json#dependencies)
|
|
119
|
-
|
|
120
|
-
### 注意点
|
|
121
|
-
|
|
122
|
-
值得注意的是,这个包的类型只和它的来源还有和当前包的关系有关,也就是说一个包,既可以是公共包,也可以是私有包,也可以是本地包。
|
|
123
|
-
|
|
124
|
-
比如在本 `monorepo` 中,`@icebraekers/monorepo` 是公共包,因为它已经发布到了 `https://www.npmjs.com` 上了
|
|
125
|
-
|
|
126
|
-
同时它也是一个本地包,因为本 `monorepo` 中,其他项目使用 `workspace` 的方式直接使用了这个包。
|
|
127
|
-
|
|
128
|
-
它也可以是一个私有包,比如你在公司内部网络,快速使用 [verdaccio](https://www.npmjs.com/package/verdaccio) 搭建一个私有源, 然后把 `@icebraekers/monorepo` 发布上去,那它就变成一个内网里的私有包了。
|
|
129
|
-
|
|
130
|
-
### 使用 npm 包的示例
|
|
131
|
-
|
|
132
|
-
这里我以一个最简单的一个 `cowsay` 包为例,这个包作用就是输出一个牛说话的字符画
|
|
133
|
-
|
|
134
|
-
- **安装第三方包:**
|
|
135
|
-
|
|
136
|
-
```bash
|
|
137
|
-
npm install cowsay
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
- **在代码中使用:**
|
|
141
|
-
|
|
142
|
-
```js
|
|
143
|
-
const cowsay = require('cowsay')
|
|
144
|
-
|
|
145
|
-
console.log(cowsay.say({
|
|
146
|
-
text: '我爱中国!',
|
|
147
|
-
e: 'oO',
|
|
148
|
-
T: 'U '
|
|
149
|
-
}))
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
- **在 CLI 中使用 :**
|
|
153
|
-
|
|
154
|
-
```bash
|
|
155
|
-
npx cowsay 我爱中国!
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
> `npx` 是 Node.js 提供的一个命令行工具,用来直接运行 npm 包,无需全局安装。
|
|
159
|
-
|
|
160
|
-
---
|
|
161
|
-
|
|
162
|
-
接下来,就让我们开始 `npm` 包的发布之旅吧
|
|
7
|
+
Use `pnpm pack` to inspect the exact artifact before publishing.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: repoctl 文档站的 AI 文档入口,说明如何为 AI 编程工具提供 llms.txt 和页面 Markdown。
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# AI 文档
|
|
6
|
+
|
|
7
|
+
AI 文档入口用于给 Cursor、Claude Code、Codex 和其他 AI 编程工具提供更容易读取的上下文。它和工具专题分开维护,避免 llms.txt 被埋在普通工具列表里。
|
|
8
|
+
|
|
9
|
+
## 1. 推荐入口
|
|
10
|
+
|
|
11
|
+
| 入口 | 用途 |
|
|
12
|
+
| ------------------------------ | ------------------------------------------------ |
|
|
13
|
+
| `/llms.txt` | 轻量文档索引,适合先交给 AI 工具判断要读哪些页面 |
|
|
14
|
+
| `/llms-full.txt` | 合并后的完整文档,适合需要一次性提供上下文的场景 |
|
|
15
|
+
| [llms.txt 说明](./llms-txt.md) | 维护约定、访问方式和页面 frontmatter 要求 |
|
|
16
|
+
|
|
17
|
+
## 2. 在 AI 工具里怎么用
|
|
18
|
+
|
|
19
|
+
优先把 `https://repo.icebreaker.top/llms.txt` 作为入口提供给 AI 工具。只有当工具不能继续抓取链接,或者你需要离线提供完整上下文时,再使用 `https://repo.icebreaker.top/llms-full.txt`。
|
|
20
|
+
|
|
21
|
+
```txt
|
|
22
|
+
先给 llms.txt
|
|
23
|
+
-> AI 选择相关页面
|
|
24
|
+
-> 必要时补充 llms-full.txt
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## 3. 维护原则
|
|
28
|
+
|
|
29
|
+
| 维护动作 | 原因 |
|
|
30
|
+
| --------------------------------- | ---------------------------------------- |
|
|
31
|
+
| 新增重要页面时写 `description` | 让 llms 索引更容易被模型理解 |
|
|
32
|
+
| 页面标题保持具体 | 避免 AI 只看到泛化标题,无法判断页面用途 |
|
|
33
|
+
| repoctl、知识库、工具专题分开组织 | 让 AI 工具能按任务类型检索上下文 |
|