@sys-designer/create-vue 1.0.3 → 1.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sys-designer/create-vue",
3
- "version": "1.0.3",
3
+ "version": "1.1.0",
4
4
  "description": "Scaffold a sys-designer Vue3 + Vite + TS project from the command line.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,34 +1,125 @@
1
1
  #!/usr/bin/env node
2
2
  // merge-lib-config.mjs
3
- // 读取项目 package.json 中所有 "xxx": "link:../xxx" 依赖,逐个解析其 lib.config.ts,
3
+ // 读取项目 package.json 中所有依赖,逐个解析其 lib.config.ts,
4
4
  // 把其中的 libResolves / libModules 合并后输出到 <项目根>/common/lib.config.ts。
5
5
  //
6
+ // 支持两种依赖形式:
7
+ // 1) "new-app": "link:../new-app" -> 直接解析相对路径下的 lib.config.ts
8
+ // 2) "new-app": "^0.2.1" -> 视为已安装,按候选目录依次查找其 lib.config.ts:
9
+ // a) Node 模块解析(require.resolve) —— 最权威,能穿透 pnpm 软链 / .pnpm store
10
+ // b) <项目>/node_modules/<name> (项目内安装)
11
+ // c) 全局安装目录(由 `pnpm/npm ls -g --parseable` 解析,兼容 pnpm 11 哈希布局)
12
+ // —— 即 new-app 通过 `pnpm add -g .` 装成全局包的情况
13
+ // (workspace:/file:/npm: 前缀同样按上述位置处理)
14
+ // 找不到时脚本会打印所有尝试过的目录,便于定位(未安装 / 或包的 files 未含 lib.config.ts)。
15
+ //
6
16
  // 用法: node scripts/merge-lib-config.mjs
7
17
  // - 在 build.sh 中于 install 之后、build 之前被调用。
8
- // - 即使没有任何 link: 依赖 / 没有可合并的 lib.config.ts,也会输出一个空的
18
+ // - 即使没有任何可合并的依赖 / 没有可合并的 lib.config.ts,也会输出一个空的
9
19
  // common/lib.config.ts(不跳过),保证下游构建始终有该文件可用。
10
20
  // - resolve 参数保留原样(如 resolve(process.cwd(), '.', './node_modules/...'))。
11
21
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
12
- import { resolve as pathResolve, join } from 'node:path';
22
+ import { resolve as pathResolve, join, sep } from 'node:path';
23
+ import { execSync } from 'node:child_process';
24
+ import { createRequire } from 'node:module';
13
25
 
14
26
  const projectRoot = process.cwd();
27
+ // 用项目根作为解析基,require.resolve 可权威定位已安装包(穿透 pnpm 软链 / .pnpm store)
28
+ const requireFromRoot = createRequire(join(projectRoot, 'package.json'));
29
+
30
+ // 解析全局已安装的包: 包名 -> 真实安装目录。
31
+ // 兼容两种布局:
32
+ // - npm 全局: <npmRoot>/<name>
33
+ // - pnpm 全局(含 11.x 哈希布局): <pnpmRoot>/<hash>/node_modules/<name>
34
+ // 例如 new-app 通过 `pnpm add -g .` 安装后位于此类路径下。
35
+ // 通过 `pnpm ls -g --parseable` / `npm ls -g --parseable` 的输出按行解析得到。
36
+ function getGlobalPkgs() {
37
+ const map = new Map(); // name -> dir
38
+ const tryCmd = (cmd) => {
39
+ try {
40
+ const out = execSync(cmd, {
41
+ encoding: 'utf-8',
42
+ stdio: ['ignore', 'pipe', 'ignore'],
43
+ });
44
+ for (const raw of out.split(/\r?\n/)) {
45
+ const p = raw.trim();
46
+ if (!p) continue;
47
+ const marker = `node_modules${sep}`;
48
+ const idx = p.indexOf(marker);
49
+ if (idx === -1) continue; // 跳过根目录等非包行
50
+ const name = p.slice(idx + marker.length); // @scope/name 或 name
51
+ if (name && !map.has(name)) map.set(name, p);
52
+ }
53
+ } catch {
54
+ // 该命令不可用则忽略
55
+ }
56
+ };
57
+ tryCmd('pnpm ls -g --parseable');
58
+ tryCmd('npm ls -g --parseable');
59
+ return map;
60
+ }
61
+ const globalPkgs = getGlobalPkgs();
62
+ if (globalPkgs.size > 0) {
63
+ console.log(`merge-lib-config: 全局已安装包 ${globalPkgs.size} 个`);
64
+ }
15
65
 
16
- // 1) 读取 package.json,找出所有 link: 依赖
66
+ // 收集某依赖名的所有候选安装目录(按优先级),用于查找其 lib.config.ts:
67
+ // 1) Node 模块解析(最权威:node_modules 顶层软链 / .pnpm store / NODE_PATH)
68
+ // 2) <项目>/node_modules/<name>
69
+ // 3) 全局安装目录(pnpm/npm ls -g)
70
+ function candidateDirsFor(name) {
71
+ const dirs = [];
72
+ const push = (d) => {
73
+ const a = pathResolve(projectRoot, d);
74
+ if (!dirs.includes(a)) dirs.push(a);
75
+ };
76
+ // 1) Node 解析(能找到 pnpm 实际落盘位置,含软链目标)
77
+ try {
78
+ const pkgJson = requireFromRoot.resolve(`${name}/package.json`);
79
+ push(join(pkgJson, '..'));
80
+ } catch {
81
+ // 项目 node_modules 中不存在该包(可能仅全局安装或根本未装)
82
+ }
83
+ // 2) 项目内 node_modules
84
+ push(join('node_modules', name));
85
+ // 3) 全局安装目录
86
+ if (globalPkgs.has(name)) push(globalPkgs.get(name));
87
+ return dirs;
88
+ }
89
+
90
+ // 读取 package.json,收集所有依赖的候选目录
17
91
  const pkgPath = join(projectRoot, 'package.json');
18
- const linkDirs = [];
92
+ const candidateDirs = []; // { name, path }
93
+ const seenPaths = new Set();
94
+ function addCandidate(name, dir) {
95
+ const abs = pathResolve(projectRoot, dir);
96
+ if (seenPaths.has(abs)) return; // 同一目录只处理一次
97
+ seenPaths.add(abs);
98
+ candidateDirs.push({ name, path: abs });
99
+ }
19
100
  if (!existsSync(pkgPath)) {
20
101
  console.log('merge-lib-config: 未找到 package.json,将输出空的 common/lib.config.ts');
21
102
  } else {
22
103
  const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
23
104
  const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
24
105
  for (const [name, spec] of Object.entries(deps)) {
25
- if (typeof spec === 'string' && spec.startsWith('link:')) {
26
- const rel = spec.slice('link:'.length);
27
- linkDirs.push({ name, path: pathResolve(projectRoot, rel) });
106
+ if (typeof spec !== 'string') continue;
107
+ if (spec.startsWith('link:')) {
108
+ // link:../new-app -> 直接解析相对路径
109
+ addCandidate(name, spec.slice('link:'.length));
110
+ } else if (
111
+ // 版本范围 / workspace: / file: / npm: -> 视为已安装,按候选目录依次查找
112
+ /^[\^~><=*\s\d]/.test(spec) ||
113
+ spec.startsWith('workspace:') ||
114
+ spec.startsWith('file:') ||
115
+ spec.startsWith('npm:')
116
+ ) {
117
+ for (const d of candidateDirsFor(name)) addCandidate(name, d);
28
118
  }
119
+ // 其它形式(如 git url)暂忽略
29
120
  }
30
- if (linkDirs.length === 0) {
31
- console.log('merge-lib-config: 未找到 link: 依赖,将输出空的 common/lib.config.ts');
121
+ if (candidateDirs.length === 0) {
122
+ console.log('merge-lib-config: 未找到可合并的依赖,将输出空的 common/lib.config.ts');
32
123
  }
33
124
  }
34
125
 
@@ -74,10 +165,20 @@ const mergedModules = [];
74
165
  const seenModules = new Set();
75
166
  let conflictWarned = false;
76
167
 
77
- for (const { name, path } of linkDirs) {
168
+ const tries = []; // 诊断用: 记录每个候选目录的查找结果
169
+ for (const { name, path } of candidateDirs) {
78
170
  const cfgPath = join(path, 'lib.config.ts');
79
- if (!existsSync(cfgPath)) {
80
- console.log(`merge-lib-config: [${name}] 未找到 lib.config.ts,跳过: ${cfgPath}`);
171
+ const dirExists = existsSync(path);
172
+ const hasLib = dirExists && existsSync(cfgPath);
173
+ tries.push({ name, dir: path, dirExists, hasLib });
174
+ if (!hasLib) {
175
+ if (dirExists) {
176
+ // 包已安装,但 lib.config.ts 不在其中 —— 多半是包的 package.json "files" 没包含它
177
+ console.log(
178
+ `merge-lib-config: [${name}] 目录存在但无 lib.config.ts: ${path} ` +
179
+ `(检查该包 package.json 的 "files" 是否包含 lib.config.ts)`
180
+ );
181
+ }
81
182
  continue;
82
183
  }
83
184
  const { resolves, modules } = parseLibConfig(readFileSync(cfgPath, 'utf-8'));
@@ -98,6 +199,22 @@ for (const { name, path } of linkDirs) {
98
199
  }
99
200
  }
100
201
 
202
+ // 诊断:若最终未合并到任何内容,打印尝试过的、确实存在的目录,便于定位问题
203
+ if (Object.keys(mergedResolves).length === 0 && mergedModules.length === 0) {
204
+ const existing = tries.filter((t) => t.dirExists);
205
+ if (existing.length > 0) {
206
+ console.warn('merge-lib-config: 未合并到任何 lib.config.ts。已安装但无 lib.config.ts 的包:');
207
+ for (const t of existing) {
208
+ console.warn(` - [${t.name}] ${t.dir}`);
209
+ }
210
+ console.warn(' => 请确认目标包的 package.json "files" 包含 lib.config.ts,或改用 link: 引用源码目录。');
211
+ } else if (tries.length > 0) {
212
+ console.warn('merge-lib-config: 未合并到任何 lib.config.ts。所有候选目录均不存在:');
213
+ for (const t of tries) console.warn(` - [${t.name}] ${t.dir}`);
214
+ console.warn(' => 该依赖似乎未安装(项目 node_modules 与全局都没有)。请先安装它再构建。');
215
+ }
216
+ }
217
+
101
218
  // 4) 渲染并写出到 common/lib.config.ts
102
219
  function render() {
103
220
  const lines = [];