@farris/cli 2.3.7 → 2.3.9

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 (171) hide show
  1. package/lib/commands/add-app.js +5 -5
  2. package/lib/commands/add-app.js.map +1 -1
  3. package/lib/commands/add-lib.js +5 -5
  4. package/lib/commands/add-lib.js.map +1 -1
  5. package/lib/commands/add-micro.js +12 -0
  6. package/lib/commands/add-micro.js.map +1 -0
  7. package/lib/commands/add-project.js +196 -194
  8. package/lib/commands/add-project.js.map +1 -1
  9. package/lib/commands/build-components.js +60 -60
  10. package/lib/commands/build-components.js.map +1 -1
  11. package/lib/commands/build-css.js +38 -38
  12. package/lib/commands/build-css.js.map +1 -1
  13. package/lib/commands/build-lib.js +30 -30
  14. package/lib/commands/build-lib.js.map +1 -1
  15. package/lib/commands/build.js +19 -19
  16. package/lib/commands/build.js.map +1 -1
  17. package/lib/commands/create-app-options.js +85 -74
  18. package/lib/commands/create-app-options.js.map +1 -1
  19. package/lib/commands/create-app.js +131 -131
  20. package/lib/commands/create-app.js.map +1 -1
  21. package/lib/commands/create-options.js +58 -32
  22. package/lib/commands/create-options.js.map +1 -1
  23. package/lib/commands/create.js +341 -331
  24. package/lib/commands/create.js.map +1 -1
  25. package/lib/commands/dev-serve.js +18 -18
  26. package/lib/commands/extract-i18n.js +74 -74
  27. package/lib/commands/extract-i18n.js.map +1 -1
  28. package/lib/commands/generate/api.js +124 -124
  29. package/lib/commands/generate/api.js.map +1 -1
  30. package/lib/commands/generate/common.js +101 -101
  31. package/lib/commands/generate/common.js.map +1 -1
  32. package/lib/commands/generate/component.js +156 -156
  33. package/lib/commands/generate/component.js.map +1 -1
  34. package/lib/commands/generate/view.js +168 -168
  35. package/lib/commands/generate/view.js.map +1 -1
  36. package/lib/commands/preview-serve.js +16 -16
  37. package/lib/commands/workspace/add-app.js +15 -15
  38. package/lib/commands/workspace/add-app.js.map +1 -1
  39. package/lib/commands/workspace/create.js +62 -62
  40. package/lib/commands/workspace/create.js.map +1 -1
  41. package/lib/commands/workspace/inspect.js +30 -30
  42. package/lib/commands/workspace/inspect.js.map +1 -1
  43. package/lib/commands/workspace/verify.js +38 -38
  44. package/lib/commands/workspace/verify.js.map +1 -1
  45. package/lib/common/agents-doc.js +33 -33
  46. package/lib/common/agents-doc.js.map +1 -1
  47. package/lib/common/apply-catalog-deps.js +15 -15
  48. package/lib/common/apply-catalog-deps.js.map +1 -1
  49. package/lib/common/component-file-name.js +3 -3
  50. package/lib/common/constant.js +85 -84
  51. package/lib/common/constant.js.map +1 -1
  52. package/lib/common/create-app-target.js +46 -46
  53. package/lib/common/create-app-target.js.map +1 -1
  54. package/lib/common/generate-app.js +106 -109
  55. package/lib/common/generate-app.js.map +1 -1
  56. package/lib/common/get-dependencies.js +9 -9
  57. package/lib/common/get-farris-config.js +25 -25
  58. package/lib/common/get-farris-config.js.map +1 -1
  59. package/lib/common/get-version.js +6 -6
  60. package/lib/common/get-vite-config.js +192 -192
  61. package/lib/common/get-vite-config.js.map +1 -1
  62. package/lib/common/lib-package-exports.js +24 -24
  63. package/lib/common/lib-package-exports.js.map +1 -1
  64. package/lib/common/list-lib-components.js +23 -23
  65. package/lib/common/list-lib-components.js.map +1 -1
  66. package/lib/common/output.js +164 -164
  67. package/lib/common/output.js.map +1 -1
  68. package/lib/common/project-layout.js +155 -183
  69. package/lib/common/project-layout.js.map +1 -1
  70. package/lib/common/safety.js +172 -173
  71. package/lib/common/safety.js.map +1 -1
  72. package/lib/common/template-manifest.js +18 -14
  73. package/lib/common/template-manifest.js.map +1 -1
  74. package/lib/common/template-renderer.js +114 -114
  75. package/lib/common/template-renderer.js.map +1 -1
  76. package/lib/common/transaction.js +83 -83
  77. package/lib/common/transaction.js.map +1 -1
  78. package/lib/common/verifier.js +187 -201
  79. package/lib/common/verifier.js.map +1 -1
  80. package/lib/common/workspace-contract.js +191 -157
  81. package/lib/common/workspace-contract.js.map +1 -1
  82. package/lib/config/vite-app.js +13 -13
  83. package/lib/config/vite-common.js +20 -20
  84. package/lib/config/vite-common.js.map +1 -1
  85. package/lib/config/vite-component.js +32 -32
  86. package/lib/config/vite-component.js.map +1 -1
  87. package/lib/config/vite-lib.js +26 -26
  88. package/lib/config/vite-lib.js.map +1 -1
  89. package/lib/index.js +261 -238
  90. package/lib/index.js.map +1 -1
  91. package/lib/plugins/create-app-package-json.js +23 -23
  92. package/lib/plugins/create-component-style.js +44 -44
  93. package/lib/plugins/create-package-json.js +48 -48
  94. package/lib/plugins/create-package-json.js.map +1 -1
  95. package/lib/plugins/dts.js +8 -8
  96. package/lib/plugins/html-system.js +9 -9
  97. package/lib/plugins/mock.js +240 -292
  98. package/lib/plugins/mock.js.map +1 -1
  99. package/lib/plugins/msw-adapter.js +141 -0
  100. package/lib/plugins/msw-adapter.js.map +1 -0
  101. package/lib/plugins/replace.js +17 -17
  102. package/lib/plugins/systemjs-bundle.js +15 -15
  103. package/lib/plugins/systemjs-bundle.js.map +1 -1
  104. package/package.json +6 -1
  105. package/templates/create/.gitignore.tpl +28 -8
  106. package/templates/create/AGENTS.md +76 -45
  107. package/templates/create/README.md +44 -11
  108. package/templates/create/package.json +2 -1
  109. package/templates/lib/.gitignore.tpl +31 -1
  110. package/templates/lib/.gitlab-ci.yml +2 -2
  111. package/templates/lib/README.md +24 -1
  112. package/templates/lib/{test → components/__tests__}/index.spec.ts +1 -1
  113. package/templates/lib/{test → components/__tests__}/index.spec.tsx +2 -2
  114. package/templates/lib/farris.config.mjs +2 -2
  115. package/templates/lib/package.json +1 -1
  116. package/templates/lib/tsconfig.json +1 -2
  117. package/templates/lib/vitest.config.ts +4 -2
  118. package/templates/micro/.eslintrc.cjs +15 -0
  119. package/templates/micro/.gitignore.tpl +33 -0
  120. package/templates/micro/.gitlab-ci.yml +59 -0
  121. package/templates/micro/.prettierrc.json +8 -0
  122. package/templates/micro/farris.config.mjs +34 -0
  123. package/templates/micro/index.html +12 -0
  124. package/templates/micro/mock/README.md +53 -0
  125. package/templates/micro/mock/tsconfig.json +10 -0
  126. package/templates/micro/package.json +47 -0
  127. package/templates/micro/src/App.tsx +25 -0
  128. package/templates/micro/src/locales/index.ts +5 -0
  129. package/templates/micro/src/locales/zh-CHS.json +1 -0
  130. package/templates/micro/src/main.ts +47 -0
  131. package/templates/micro/src/router/index.ts +24 -0
  132. package/templates/micro/src/views/AboutView.tsx +12 -0
  133. package/templates/micro/src/views/HomeView.tsx +13 -0
  134. package/templates/micro/src/views/__tests__/AboutView.spec.tsx +11 -0
  135. package/templates/micro/src/views/__tests__/HomeView.spec.tsx +11 -0
  136. package/templates/micro/tsconfig.json +18 -0
  137. package/templates/micro/vitest.config.ts +12 -0
  138. package/templates/mobile/.gitignore.tpl +25 -24
  139. package/templates/mobile/farris.config.mjs +2 -2
  140. package/templates/mobile/mock/README.md +39 -20
  141. package/templates/mobile/mock/tsconfig.json +10 -0
  142. package/templates/mobile/package.json +5 -2
  143. package/templates/mobile/src/main.ts +5 -40
  144. package/templates/mobile/src/views/HomeView.tsx +2 -2
  145. package/templates/mobile/src/views/__tests__/AboutView.spec.tsx +11 -0
  146. package/templates/mobile/src/views/__tests__/HomeView.spec.tsx +11 -0
  147. package/templates/mobile/tsconfig.json +1 -2
  148. package/templates/mobile/vitest.config.ts +4 -2
  149. package/templates/web/.gitignore.tpl +25 -24
  150. package/templates/web/farris.config.mjs +2 -2
  151. package/templates/web/mock/README.md +39 -20
  152. package/templates/web/mock/tsconfig.json +10 -0
  153. package/templates/web/package.json +5 -2
  154. package/templates/web/src/App.tsx +0 -4
  155. package/templates/web/src/main.ts +5 -40
  156. package/templates/web/src/views/HomeView.tsx +2 -2
  157. package/templates/web/src/views/__tests__/AboutView.spec.tsx +11 -0
  158. package/templates/web/src/views/__tests__/HomeView.spec.tsx +11 -0
  159. package/templates/web/tsconfig.json +1 -2
  160. package/templates/web/vitest.config.ts +4 -2
  161. package/templates/mobile/src/components/TheButton.tsx +0 -9
  162. package/templates/mobile/test/src/components/TheButton.spec.ts +0 -15
  163. package/templates/mobile/test/src/components/TheButton.spec.tsx +0 -15
  164. package/templates/web/src/components/TheButton.tsx +0 -9
  165. package/templates/web/src/micro-app.d.ts +0 -20
  166. package/templates/web/src/styles/index.css +0 -0
  167. package/templates/web/test/src/components/TheButton.spec.ts +0 -15
  168. package/templates/web/test/src/components/TheButton.spec.tsx +0 -15
  169. /package/templates/{web → micro}/src/micro/context.ts +0 -0
  170. /package/templates/{mobile → micro}/src/micro-app.d.ts +0 -0
  171. /package/templates/{mobile/src/styles/index.css → micro/src/styles/index.scss} +0 -0
@@ -0,0 +1,141 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
+ import { join } from 'node:path';
4
+ import { Readable } from 'node:stream';
5
+ import { pipeline } from 'node:stream/promises';
6
+ import { pathToFileURL } from 'node:url';
7
+ import { randomUUID } from 'node:crypto';
8
+ /** @farris/cli 目前适配的 msw 主版本(应用的 msw 由模板声明、随工作区 catalog 统一) */
9
+ const SUPPORTED_MAJOR = 2;
10
+ const toPosix = (p) => p.split('\\').join('/');
11
+ /** 路径比较统一按 posix + 小写(Windows 下 server 侧给的是 C:/...,本地 join 给的是 C:\...) */
12
+ const normalize = (p) => toPosix(p).toLowerCase();
13
+ // handleRequest 的 emitter 参数只用于生命周期事件通知,dev 期无需监听;
14
+ // msw 未从包根导出该类型,按参数位置断言,避免额外依赖 strict-event-emitter
15
+ const noopEmitter = { emit() { } };
16
+ const sharedOptions = { onUnhandledRequest: () => null };
17
+ const loadingRuntimes = new Map();
18
+ async function resolveAppMsw(appRoot) {
19
+ const require = createRequire(join(appRoot, 'package.json'));
20
+ let entry;
21
+ let pkgPath;
22
+ try {
23
+ // 先按包名解析:pnpm 下命中应用自己的 node_modules,npm 下命中提升后的 node_modules
24
+ pkgPath = require.resolve('msw/package.json');
25
+ entry = require.resolve('msw');
26
+ }
27
+ catch (err) {
28
+ throw new Error(`未能在应用目录解析到 msw(${appRoot}):请先在应用工程内安装依赖(msw 已由应用模板放入 devDependencies)。` +
29
+ `若工程由旧版脚手架创建,请升级 @farris/cli 或手动执行 pnpm add -D msw@^2。原因:` +
30
+ `${err instanceof Error ? err.message : String(err)}`);
31
+ }
32
+ const version = String(JSON.parse(readFileSync(pkgPath, 'utf8')).version ?? '');
33
+ const major = Number.parseInt(version.split('.')[0] ?? '', 10);
34
+ if (major !== SUPPORTED_MAJOR) {
35
+ throw new Error(`应用安装的 msw 版本为 ${version},@farris/cli 目前只适配 ${SUPPORTED_MAJOR}.x:` +
36
+ `请把应用里的 msw 对齐到 ${SUPPORTED_MAJOR}.x(工作区 catalog 已统一版本)`);
37
+ }
38
+ const mod = (await import(pathToFileURL(entry).href));
39
+ const handleRequest = mod.handleRequest ?? mod.default?.handleRequest;
40
+ if (typeof handleRequest !== 'function') {
41
+ throw new Error(`msw ${version} 的入口未导出 handleRequest(${entry}),无法执行 mock handler`);
42
+ }
43
+ return { handleRequest, version };
44
+ }
45
+ /**
46
+ * 从应用目录解析并加载 msw(应用 devDependencies 里的那一份)。
47
+ * 同一应用目录只加载一次;加载失败不缓存,装好依赖后重试即可。
48
+ */
49
+ export function loadAppMsw(appRoot) {
50
+ const cached = loadingRuntimes.get(appRoot);
51
+ if (cached) {
52
+ return cached;
53
+ }
54
+ const loading = resolveAppMsw(appRoot);
55
+ loadingRuntimes.set(appRoot, loading);
56
+ loading.catch(() => loadingRuntimes.delete(appRoot));
57
+ return loading;
58
+ }
59
+ /** 读取 handler 的 info(方法/路径),用于重复路径校验 */
60
+ export function handlerInfo(handler) {
61
+ return handler.info ?? {};
62
+ }
63
+ /** 默认导出的项是否为 MSW 的 HTTP handler */
64
+ export function isRequestHandler(value) {
65
+ return !!value && typeof handlerInfo(value).method === 'string';
66
+ }
67
+ /** 是否位于指定目录内(按 posix、大小写不敏感比较,并要求完整目录边界,避免同名前缀目录误判) */
68
+ export function isInsideDir(file, dir) {
69
+ const target = normalize(file);
70
+ const base = normalize(dir).replace(/\/+$/, '');
71
+ return target === base || target.startsWith(`${base}/`);
72
+ }
73
+ /** 非流式场景下的请求体读取(按 chunk 收集) */
74
+ function readBufferedBody(req) {
75
+ return new Promise((resolve) => {
76
+ const chunks = [];
77
+ req.on('data', (chunk) => chunks.push(String(chunk)));
78
+ req.on('end', () => resolve(chunks.length > 0 ? chunks.join('') : undefined));
79
+ req.on('error', () => resolve(undefined));
80
+ });
81
+ }
82
+ /** 把 Node 请求转成 fetch Request(handleRequest 的输入) */
83
+ export async function toWebRequest(req, origin) {
84
+ const method = (req.method ?? 'GET').toUpperCase();
85
+ const hasBody = method !== 'GET' && method !== 'HEAD';
86
+ const init = {
87
+ method,
88
+ headers: new Headers(req.headers)
89
+ };
90
+ if (hasBody) {
91
+ // 真实 dev server 下 req 是可读流,直接流式交给 fetch;测试替身等场景退化为缓冲读取
92
+ init.duplex = 'half';
93
+ init.body =
94
+ req.readable && typeof Readable.toWeb === 'function'
95
+ ? Readable.toWeb(req)
96
+ : await readBufferedBody(req);
97
+ }
98
+ return new Request(new URL(req.url ?? '/', origin), init);
99
+ }
100
+ /** 把 fetch Response 流式写回 Node 响应 */
101
+ async function writeResponse(res, response) {
102
+ res.statusCode = response.status;
103
+ if (response.statusText) {
104
+ res.statusMessage = response.statusText;
105
+ }
106
+ response.headers.forEach((value, name) => {
107
+ // appendHeader 才符合多值头(如 set-cookie)的语义,Node 18.3 起可用
108
+ if (typeof res.appendHeader === 'function') {
109
+ res.appendHeader(name, value);
110
+ }
111
+ else {
112
+ res.setHeader(name, value);
113
+ }
114
+ });
115
+ if (response.body) {
116
+ try {
117
+ await pipeline(Readable.fromWeb(response.body), res);
118
+ }
119
+ catch {
120
+ // 客户端提前断开或响应流异常:连接已不可用,回收即可,不向上抛
121
+ res.destroy();
122
+ }
123
+ return;
124
+ }
125
+ res.end();
126
+ }
127
+ /**
128
+ * 用应用侧的 msw 处理一次请求。
129
+ * 命中 mock 时写回响应并返回状态码;未命中返回 null,由调用方放行给代理或 404 守卫。
130
+ */
131
+ export async function runMockHandlers(req, res, handlers, runtime) {
132
+ const origin = `http://${req.headers.host ?? 'localhost'}`;
133
+ const request = await toWebRequest(req, origin);
134
+ const response = await runtime.handleRequest(request, randomUUID(), handlers, sharedOptions, noopEmitter, { resolutionContext: { baseUrl: origin } });
135
+ if (!response) {
136
+ return null;
137
+ }
138
+ await writeResponse(res, response);
139
+ return response.status;
140
+ }
141
+ //# sourceMappingURL=msw-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"msw-adapter.js","sourceRoot":"","sources":["../../src/plugins/msw-adapter.ts"],"names":[],"mappings":"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"}
@@ -1,18 +1,18 @@
1
- import { getPackageName } from '../common/constant.js';
2
- export function replace(path) {
3
- return {
4
- name: 'farris-replace-path',
5
- renderChunk(code, chunk) {
6
- const fileNames = chunk.fileName.split('.');
7
- const format = fileNames[fileNames.length - 2];
8
- // const regExpress = new RegExp(/@farris\/mobile-ui-vue\/([\w-]+)/g);
9
- const dynamicRegExp = new RegExp(`${getPackageName().replace(/\//g, '\\/')}\\/([\\w-]+)`, // 自动转义斜杠
10
- 'g');
11
- return code.replace(dynamicRegExp, (match, captureGroup) => {
12
- return path(format, [captureGroup]);
13
- });
14
- }
15
- };
16
- }
17
- ;
1
+ import { getPackageName } from '../common/constant.js';
2
+ export function replace(path) {
3
+ return {
4
+ name: 'farris-replace-path',
5
+ renderChunk(code, chunk) {
6
+ const fileNames = chunk.fileName.split('.');
7
+ const format = fileNames[fileNames.length - 2];
8
+ // const regExpress = new RegExp(/@farris\/mobile-ui-vue\/([\w-]+)/g);
9
+ const dynamicRegExp = new RegExp(`${getPackageName().replace(/\//g, '\\/')}\\/([\\w-]+)`, // 自动转义斜杠
10
+ 'g');
11
+ return code.replace(dynamicRegExp, (match, captureGroup) => {
12
+ return path(format, [captureGroup]);
13
+ });
14
+ }
15
+ };
16
+ }
17
+ ;
18
18
  //# sourceMappingURL=replace.js.map
@@ -1,16 +1,16 @@
1
- export function systemjsBundle() {
2
- return {
3
- name: 'systemjs-bundle',
4
- outputOptions(options) {
5
- if (options.format === 'systemjs') {
6
- return {
7
- ...options,
8
- name: undefined
9
- };
10
- }
11
- return options;
12
- }
13
- };
14
- }
15
- ;
1
+ export function systemjsBundle() {
2
+ return {
3
+ name: 'systemjs-bundle',
4
+ outputOptions(options) {
5
+ if (options.format === 'systemjs') {
6
+ return {
7
+ ...options,
8
+ name: undefined
9
+ };
10
+ }
11
+ return options;
12
+ }
13
+ };
14
+ }
15
+ ;
16
16
  //# sourceMappingURL=systemjs-bundle.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"systemjs-bundle.js","sourceRoot":"","sources":["../../src/plugins/systemjs-bundle.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,aAAa,CAAC,OAAY;YACxB,IAAG,OAAO,CAAC,MAAM,KAAK,UAAU,EAAE;gBAChC,OAAO;oBACL,GAAG,OAAO;oBACV,IAAI,EAAE,SAAS;iBAChB,CAAC;aACH;YACD,OAAO,OAAO,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC;AAAA,CAAC"}
1
+ {"version":3,"file":"systemjs-bundle.js","sourceRoot":"","sources":["../../src/plugins/systemjs-bundle.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,aAAa,CAAC,OAAY;YACxB,IAAG,OAAO,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;gBACjC,OAAO;oBACL,GAAG,OAAO;oBACV,IAAI,EAAE,SAAS;iBAChB,CAAC;YACJ,CAAC;YACD,OAAO,OAAO,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC;AAAA,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@farris/cli",
3
3
  "private": false,
4
- "version": "2.3.7",
4
+ "version": "2.3.9",
5
5
  "type": "module",
6
6
  "typings": "lib/index.d.ts",
7
7
  "exports": {
@@ -38,6 +38,7 @@
38
38
  "@vitejs/plugin-vue-jsx": "^3.0.0",
39
39
  "esbuild": "^0.23.0",
40
40
  "esbuild-sass-plugin": "^3.3.1",
41
+ "msw": "^2.15.0",
41
42
  "typescript": "^5.7.3",
42
43
  "vite": "^5.4.19",
43
44
  "vite-plugin-css-injected-by-js": "^3.5.2",
@@ -56,6 +57,9 @@
56
57
  "esbuild-sass-plugin": {
57
58
  "optional": true
58
59
  },
60
+ "msw": {
61
+ "optional": true
62
+ },
59
63
  "typescript": {
60
64
  "optional": true
61
65
  },
@@ -75,6 +79,7 @@
75
79
  "@vitejs/plugin-vue-jsx": "^3.0.0",
76
80
  "esbuild": "^0.23.0",
77
81
  "esbuild-sass-plugin": "^3.3.1",
82
+ "msw": "^2.15.0",
78
83
  "rimraf": "^5.0.7",
79
84
  "sass": "^1.90.0",
80
85
  "typescript": "^5.7.3",
@@ -1,13 +1,33 @@
1
- node_modules
2
- dist
3
- dist-es
4
- package
5
- lib
1
+ # 依赖与产物
2
+ node_modules/
3
+ dist/
4
+ dist-es/
5
+ dist-ssr/
6
+ coverage/
7
+ *.tsbuildinfo
8
+ .pnpm-store/
9
+
10
+ # 日志与本地文件
11
+ *.log
6
12
  .DS_Store
7
13
  *.local
14
+ .env
15
+ .env.*
16
+ !.env.example
17
+ package-lock.json
18
+
19
+ # 编辑器
8
20
  .vscode/*
9
21
  !.vscode/extensions.json
10
22
  !.vscode/settings.json
11
- .idea
12
- *.log
13
- .pnpm-store
23
+ .idea/
24
+ .history
25
+ *.sw?
26
+
27
+ # AI 工具
28
+ .codebuddy/
29
+ .cursor/
30
+ .claude/
31
+ .windsurf/
32
+ .trae/
33
+ .opencode/
@@ -1,6 +1,7 @@
1
1
  # <%= title %> — AI 协作契约
2
2
 
3
- 本文件是本 workspace 的**唯一真源**:所有 AI 协作约定都写在这里。根目录 `CLAUDE.md` 只是指向本文件的一行指针。
3
+ 本文件是本 workspace 的 **唯一真源**:所有 AI 协作约定都写在这里。
4
+ 根目录 `CLAUDE.md` 只是指向本文件的一行指针;**子工程内不得新增任何 AI 配置文件**(`AGENTS.md`、`CLAUDE.md`、`.cursorrules`、`.windsurfrules` 等),公共约定一律写在本文件里。
4
5
 
5
6
  ## 项目速览
6
7
 
@@ -12,76 +13,106 @@
12
13
 
13
14
  ## 2. 全局契约
14
15
 
15
- ### AI 文件落点
16
+ ### 2.1 必须遵守
16
17
 
17
- - 只在 workspace 根保留本文件(唯一真源)与 `CLAUDE.md`(一行指针);**子工程内不得新增任何 AI 配置文件**(`AGENTS.md`、`CLAUDE.md`、`.cursorrules`、`.windsurfrules` 等),公共约定一律写在本文件里。
18
+ | 规则 | 具体做法 |
19
+ |---|---|
20
+ | 改完代码先跑测试 | 在**工程目录内** `pnpm test`;提交前在根目录跑一次 `pnpm test`(递归全部工程) |
21
+ | 改结构 / 根脚本 / 容器 / 增删工程 | 先 `pnpm verify`,不通过先修复再提交 |
22
+ | 依赖版本只有一个来源 | 子工程里属于 catalog 的依赖一律写 `"catalog:"`;禁止手工 `npm install` 单个子包;禁止手改 `catalog` 版本与 `packages` glob |
23
+ | 不许为了"变绿"动测试设施 | 禁止改 `vitest.config.ts` 的 `include` / `exclude` / `environment`,禁止删改既有用例 |
24
+ | AI 配置只放 workspace 根 | 见文首:子工程内不放任何 AI 配置文件 |
25
+ | 长驻命令在工程目录内执行 | 根目录**没有** `dev` / `preview`(有意为之):`cd <工程目录>` 后再 `pnpm dev` |
18
26
 
19
- ### 目录分层
27
+ ### 2.2 目录与落点
20
28
 
21
- | 目录 | 含义 | 构建产物 |
29
+ | 目录 | 放什么 | 怎么出现 |
22
30
  |---|---|---|
23
- | `<%= appContainer %>/` | 应用,可部署 | `dist/` |
24
- | `<%= libContainer %>/` | 组件库,可发布 | `lib/` |
25
-
26
- 两类容器目录按需生成:只有存在对应类型的工程时才出现(首次 `add-app` / `add-lib` 时自动补建),不用空目录占位。
31
+ | `<%= appContainer %>/` | 应用、微应用(可部署) | `add-app` / `add-micro` 按需创建 |
32
+ | `<%= libContainer %>/` | 组件库(可发布) | `add-lib` 按需创建 |
27
33
 
28
- ### 命令契约
34
+ - 微应用与普通应用**同在 `<%= appContainer %>/` 容器**,靠工程 `package.json` 的 `"farris": { "type": "micro" }` 区分;**不存在** `micro/` 容器。
35
+ - 容器按需出现,不用空目录占位;工程目录名即包名来源。
29
36
 
30
- | 命令 | 作用 |
31
- |---|---|
32
- | `npm create farris [name]` / `farris-cli create [name]` | 新建 workspace(可同时创建一个工程) |
33
- | `farris-cli add-app <name>` | 添加应用 |
34
- | `farris-cli add-lib <name>` | 添加组件库 |
35
- | `farris-cli create-app [name]` | 在当前位置就地创建独立工程(不要用于 workspace 内) |
36
- | `farris-cli workspace create [target]` | `create` 的适配器(参数与行为一致) |
37
- | `farris-cli workspace verify` | 校验 workspace 规范 |
37
+ ### 2.3 命令
38
38
 
39
- - 改动 workspace 结构、根脚本、容器、配置或增删工程后,执行 `pnpm verify` 自检,不通过先修复再提交。
39
+ <%= commandTable %>
40
40
 
41
- ### 命令速查
41
+ ### 2.4 产物与交付
42
42
 
43
- <%= commandTable %>
43
+ | 工程类型 | 默认构建 | 产物目录 |
44
+ |---|---|---|
45
+ | 应用 | `pnpm build` → `es` + `umd` + `systemjs` | `dist/`、`dist-umd/`、`dist-systemjs/` |
46
+ | 微应用 | `pnpm build` → `iife` 单文件 | `dist/` |
47
+ | 组件库 | `pnpm build` → 一次构建出全部格式 | `dist/` |
44
48
 
45
- ### 依赖契约
49
+ - **产物目录一律是 `dist/` 系列**(组件库的发布清单 `files` 也是 `dist`);不要再写 `lib/` 之类旧目录。
50
+ - 只出某一种格式:工程目录内 `pnpm build:es`(应用另有 `pnpm build:umd` / `pnpm build:systemjs`)。
51
+ - 微应用交付 `iife` 单文件是 IBP 契约;普通应用**不默认**产出 `iife`,需要时显式执行 `farris-cli build --format iife`。
46
52
 
47
- - 依赖版本统一由根 `pnpm-workspace.yaml` 的 `catalog:` 提供;子工程里属于 catalog 的依赖一律写 `"catalog:"`。
48
- - 禁止手工 `npm install` 单个子包;禁止手改 `pnpm-workspace.yaml` 的 `packages` glob 或 `catalog` 版本。
49
- - 除 `verify` / `add-app` / `add-lib` 是 CLI 转发外,其余根脚本一律 `pnpm --recursive --if-present run <script>`。**根目录没有 `dev` / `preview` 是有意为之**:长驻服务不递归执行,避免多工程抢端口、日志交织。
53
+ ### 2.5 数据来源与 Mock
50
54
 
51
- ### 数据来源与 Mock
55
+ - 开发期接口数据默认来自工程内 `mock/` 目录,用 **MSW handler** 写法(见该目录 README);未命中请求按 `farris.config.mjs` 的 `proxy` 转发。
56
+ - 联调真实后端:在**工程目录内**执行 `pnpm dev --no-mock`(或 `MOCK=none pnpm dev`),业务代码不改。
57
+ - 请求路径必须与 mock 的 `url` 逐字一致;禁止在组件里散落假数据。
58
+ - mock 不得进入构建产物:`msw` 已在应用 `devDependencies`(开发期依赖),不要在 `mock/` 之外引用它,也不要把它加到 `dependencies`。
52
59
 
53
- - 开发期接口数据默认来自工程内 `mock/` 目录,写法与行为见该目录 README;未命中请求按 `farris.config.mjs` 的 `proxy` 转发,联调真实后端在**工程目录内**执行 `pnpm dev --no-mock`,业务代码不改动。
54
- - 请求路径必须与 mock 的 url 逐字一致;禁止在组件内散落假数据;mock 不得进入构建产物。
60
+ ### 2.6 工程内生成器
55
61
 
56
- ### 工程内生成器
62
+ | 命令 | 作用 | 关键参数 |
63
+ |---|---|---|
64
+ | `farris-cli generate view <name>` | 生成页面 | `--with-route` 自动注册路由;`--with-props` 生成 Props |
65
+ | `farris-cli generate component <name>` | 生成组件到 `<工程>/src/components/<name>/` | `--with-props`;`--style none\|css\|scss`(默认 `none`) |
66
+ | `farris-cli generate api <name> -e /api/v1/orders` | 生成 `src/api/` 接口模块 | `-m get` 指定方法 |
57
67
 
58
- - `farris-cli generate view <name> [--with-route] [--with-props]`:生成页面;`--with-route` 自动注册路由。
59
- - `farris-cli generate component <name> [--style none|css|scss]`:生成 `src/components/` 通用组件。
60
- - `farris-cli generate api <name> -e /api/v1/orders [-m get]`:生成 `src/api/` 接口模块。
61
- - 路由注册依赖 `src/router/index.ts`(或 `src/router/routes.ts`)中的 `routes = [...]` 赋值形式数组;自己重写 router 必须保留该形式,否则 `--with-route` 不会生效。
68
+ - `--with-route` 依赖 `src/router/index.ts`(或 `src/router/routes.ts`)里的 `routes = [...]` 赋值形式;自己重写 router 必须保留该写法,否则不生效。
62
69
 
63
70
  ## 3. 工程类型差异速查表
64
71
 
65
- | 关注点 | 应用 `<%= appContainer %>/<name>` | 组件库 `<%= libContainer %>/<name>` |
66
- |---|---|---|
67
- | 源码位置 | `src/` | `components/` 是**发布物唯一入口**;`src/` 仅供本地演示 |
68
- | 构建 | `farris-cli build` | `farris-cli build-lib -ep && farris-cli build-components` |
69
- | 产物 | `dist/` | `lib/` |
70
- | 发版 | 不单独发版(`private: true`) | `pnpm changeset` |
71
- | 测试 | `test/` 镜像 `src/` 路径 | `test/` 镜像 `components/` 与 `src/` 路径 |
72
+ | 关注点 | 应用 `<%= appContainer %>/<name>` | 微应用 `<%= appContainer %>/<name>`(`farris.type: micro`) | 组件库 `<%= libContainer %>/<name>` |
73
+ |---|---|---|---|
74
+ | 源码位置 | `src/` | `src/` | `components/` 是**发布物唯一入口**;`src/` 仅供本地演示 |
75
+ | 构建 | `pnpm build` | `pnpm build`(`iife` 单文件) | `pnpm build`(`farris-cli build-lib -ep` + `farris-cli build-components`) |
76
+ | 产物 | `dist/`、`dist-umd/`、`dist-systemjs/` | `dist/` | `dist/` |
77
+ | 宿主契约 | **不暴露** | 暴露 `window.mount` / `window.unmount`,并处理宿主下发的 `initialPath` 深链 | —— |
78
+ | 发版 | 不单独发版(`private: true`) | 不单独发版(`private: true`) | `pnpm changeset` |
79
+ | 测试 | 就近 `__tests__/` | 就近 `__tests__/` | 就近 `__tests__/`(贴 `components/` 或 `src/` 下被测文件) |
72
80
 
73
- **高频陷阱:** 组件写在组件库的 `src/` 下等于「写了但发不出去」——`farris-cli build-components` 只扫 `components/`。
81
+ **两个高频陷阱:**
82
+
83
+ 1. 组件写进组件库的 `src/` 等于「写了但发不出去」——`farris-cli build-components` 只扫 `components/`。
84
+ 2. 普通应用**没有**宿主契约:不要往应用里加 `window.mount` / `__MICRO_APP_ENVIRONMENT__`,也不会生成 `src/micro/`、`src/micro-app.d.ts`;需要微前端能力就用 `farris-cli add-micro <name>` 新建微应用。
74
85
 
75
86
  ## 4. 测试约定
76
87
 
77
- 测试路径 = 被测文件相对工程根的路径,前缀 `test/`,扩展名换成 `.spec.ts` / `.spec.tsx`:
88
+ ### 4.1 放哪儿(就近:与被测文件同级)
78
89
 
79
90
  ```text
80
- <%= libContainer %>/button/components/button/src/button.vue
81
- → <%= libContainer %>/button/test/components/button/src/button.spec.ts
91
+ <%= appContainer %>/shop/src/components/button/button.component.tsx
92
+ → <%= appContainer %>/shop/src/components/button/__tests__/button.spec.tsx
93
+
94
+ <%= libContainer %>/ui-kit/components/button/button.component.tsx
95
+ → <%= libContainer %>/ui-kit/components/button/__tests__/button.spec.tsx
82
96
  ```
83
97
 
84
- 工程内 `pnpm test` 跑本工程测试;根目录 `pnpm test` 递归跑全部工程。
98
+ - 文件名 = 被测文件名 + `.spec`:纯逻辑用 `*.spec.ts`,组件或含 JSX 用 `*.spec.tsx`。
99
+ - `__tests__/` 与被测文件同级;**不要**在工程根另建 `test/` 汇总目录。
100
+ - 工程里**不预置**端到端测试:需要时自行引入,别与上面的单元测试混放。
101
+
102
+ ### 4.2 每次改动必须做
103
+
104
+ 1. 改完代码先在**工程目录内**跑 `pnpm test`;提交前在根目录跑一次 `pnpm test`(递归全部工程)。
105
+ 2. 新增或修改组件、工具函数、mock 解析逻辑:**同一提交内**补上或更新对应 `.spec`。
106
+ 3. 修 bug:先在 `.spec` 里写一条能复现的失败用例,再改实现(先红后绿)。
107
+ 4. 用例必须能在 `jsdom` 下独立通过:不依赖真实浏览器、不访问外网、不依赖执行顺序。
108
+
109
+ ### 4.3 禁止
110
+
111
+ - 禁止为让测试通过而改 `vitest.config.ts` 的 `include` / `exclude` / `environment`,或删改既有用例。
112
+ - 禁止把端到端用例放进 `__tests__/`;禁止提交 `.only` / `.skip`。
113
+ - 禁止在用例里靠固定 `sleep` 等待,或依赖上一条用例残留的状态。
114
+
115
+ 工程内 `pnpm test` 只跑本工程;根目录 `pnpm test` 递归跑全部工程。
85
116
 
86
117
  ## 5. 子工程清单
87
118
 
@@ -2,23 +2,56 @@
2
2
 
3
3
  <%= readmeBody %>
4
4
 
5
+ 本 workspace 用 pnpm 管理:根目录只放 workspace 级命令,工程内的开发 / 构建命令进工程目录执行。
6
+
7
+ ## 快速上手
8
+
9
+ ```bash
10
+ pnpm install # 安装依赖(版本由 pnpm-workspace.yaml 的 catalog 统一提供)
11
+ pnpm build # 构建全部工程(默认产出全部格式)
12
+ pnpm test # 跑全部工程的单元测试
13
+ pnpm verify # 校验 workspace 规范(改结构 / 脚本 / 容器后必跑)
14
+ ```
15
+
16
+ 开发某个工程时,进入它的目录:
17
+
18
+ ```bash
19
+ cd <%= appContainer %>/shop # 以应用为例:工程内的命令都在这里执行
20
+ pnpm dev # 启动开发服务器(根目录没有 dev,是有意为之)
21
+ ```
22
+
5
23
  ## 目录结构
6
24
 
7
25
  ```text
8
- ├── <%= appContainer %>/ # 应用(可部署)
9
- ├── <%= libContainer %>/ # 组件库(可发布)
10
- ├── AGENTS.md # AI 协作契约(唯一真源)
11
- ├── pnpm-workspace.yaml # workspace 配置与 catalog 依赖版本
12
- └── package.json # 根脚本
26
+ <%= appContainer %>/ # 应用与微应用(可部署)
27
+ <%= libContainer %>/ # 组件库(可发布)
28
+ AGENTS.md # AI 协作约定(唯一真源)
29
+ CLAUDE.md # 指向 AGENTS.md 的一行指针
30
+ pnpm-workspace.yaml # workspace 配置与 catalog 依赖版本
31
+ package.json # 根脚本
13
32
  ```
14
33
 
15
- 两类容器目录按需生成:只有存在对应类型的工程时才出现(首次 `add-app` / `add-lib` 时自动补建),不会被空目录占位。
34
+ 容器目录按需出现:只有真正存在对应类型的工程时才生成,不用空目录占位。
35
+ 微应用与普通应用同住 `<%= appContainer %>/`,靠工程 `package.json` 的 `"farris": { "type": "micro" }` 区分。
16
36
 
17
- ## 快速上手
37
+ ## 交付物在哪
38
+
39
+ 每个工程的产物都在自己的 `dist/` 系列目录里,组件库的发布清单(`files`)同样只指向 `dist`:
40
+
41
+ | 工程类型 | 产物目录 |
42
+ |---|---|
43
+ | 应用 | `dist/`、`dist-umd/`、`dist-systemjs/` |
44
+ | 微应用 | `dist/`(`iife` 单文件) |
45
+ | 组件库 | `dist/`(一次构建出全部格式) |
46
+
47
+ ## 增删工程
18
48
 
19
49
  ```bash
20
- pnpm install
21
- pnpm --filter <pkg> dev # 启动某个工程的开发服务器(根目录不提供 dev)
22
- pnpm build
23
- pnpm verify
50
+ pnpm add-app shop # 新增应用 → <%= appContainer %>/shop
51
+ pnpm add-lib ui-kit # 新增组件库 → <%= libContainer %>/ui-kit
52
+ pnpm add-micro portal # 新增微应用 → <%= appContainer %>/portal
24
53
  ```
54
+
55
+ 生成页面 / 组件 / 接口模块,在**工程目录内**执行 `farris-cli generate view|component|api <name>`。
56
+
57
+ 完整的命令表、测试约定、Mock 规则与工程类型差异,见 `AGENTS.md`。
@@ -17,6 +17,7 @@
17
17
  "format": "pnpm --recursive --if-present run format",
18
18
  "verify": "farris-cli workspace verify",
19
19
  "add-app": "farris-cli add-app",
20
- "add-lib": "farris-cli add-lib"
20
+ "add-lib": "farris-cli add-lib",
21
+ "add-micro": "farris-cli add-micro"
21
22
  }
22
23
  }
@@ -1,3 +1,33 @@
1
+ # 依赖与产物
1
2
  node_modules/
2
- lib/
3
+ dist/
4
+ dist-es/
5
+ dist-ssr/
6
+ coverage/
7
+ *.tsbuildinfo
8
+ .pnpm-store/
9
+
10
+ # 日志与本地文件
11
+ *.log
12
+ .DS_Store
13
+ *.local
14
+ .env
15
+ .env.*
16
+ !.env.example
3
17
  package-lock.json
18
+
19
+ # 编辑器
20
+ .vscode/*
21
+ !.vscode/extensions.json
22
+ !.vscode/settings.json
23
+ .idea/
24
+ .history
25
+ *.sw?
26
+
27
+ # AI 工具
28
+ .codebuddy/
29
+ .cursor/
30
+ .claude/
31
+ .windsurf/
32
+ .trae/
33
+ .opencode/
@@ -33,7 +33,7 @@ build-job:
33
33
  expire_in: '5days'
34
34
  name: 'dist'
35
35
  paths:
36
- - $CI_PROJECT_DIR/lib
36
+ - $CI_PROJECT_DIR/dist
37
37
 
38
38
  publish-one:
39
39
  stage: publish
@@ -59,4 +59,4 @@ publish-one:
59
59
  - npm config fix
60
60
  script:
61
61
  - npm config set //repos.iec.io/repository/npm-igix-release/:_auth=$(echo -n ${ARTIFACTS_REPO_USERNAME}:${ARTIFACTS_REPO_PASSWORD} | base64)
62
- - cd lib && npm publish
62
+ - cd dist && npm publish
@@ -1,3 +1,26 @@
1
1
  # <%= name %>
2
2
 
3
- `src/` 是本地演示应用,执行 `npm run dev` 启动。演示入口会自动加载 `components/**/*.scss`,新增组件样式无需再改 `src/main.ts`。发布到 npm 的组件源码在 `components/`,执行 `npm run build` 打包。
3
+ Farris 组件库:`components/` 是**发布物唯一入口**,`src/` 只用于本地演示。
4
+
5
+ ## 常用命令
6
+
7
+ ```bash
8
+ pnpm dev # 启动本地演示(自动加载 components/**/*.scss,无需改 src/main.ts)
9
+ pnpm test # 跑单元测试(用例就近放在被测文件同级的 __tests__/)
10
+ pnpm build # 构建交付物 → dist/
11
+ pnpm changeset # 记一条变更;发版执行 pnpm version
12
+ ```
13
+
14
+ ## 目录职责
15
+
16
+ | 目录 | 作用 |
17
+ |---|---|
18
+ | `components/` | 发布到 npm 的组件源码(唯一入口)——只有写在这里才会被打包 |
19
+ | `components/**/__tests__/` | 组件测试,与被测文件同级 |
20
+ | `src/` | 本地演示应用(`pnpm dev` 的入口),不参与发布 |
21
+ | `dist/` | 构建产物;`package.json` 的 `files` 只发布它 |
22
+
23
+ ## 高频陷阱
24
+
25
+ - 组件写在 `src/` 下等于「写了但发不出去」:`farris-cli build-components` 只扫 `components/`。
26
+ - 改完组件记得在 `__tests__/` 补用例,并在提交前跑 `pnpm test`。
@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest';
2
2
 
3
3
  describe('component library entry', () => {
4
4
  it('provides an empty publish entry', async () => {
5
- const entry = await import('../components/index');
5
+ const entry = await import('../index');
6
6
 
7
7
  expect(entry).toBeDefined();
8
8
  });
@@ -1,8 +1,8 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
 
3
3
  describe('component library entry (tsx collection)', () => {
4
- it('is collected by the unified vitest include', async () => {
5
- const entry = await import('../components/index');
4
+ it('is collected by the default vitest include', async () => {
5
+ const entry = await import('../index');
6
6
 
7
7
  expect(entry).toBeDefined();
8
8
  });