@lark-apaas/fullstack-cli 1.0.1-alpha.0 → 1.0.2-alpha.1

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": "@lark-apaas/fullstack-cli",
3
- "version": "1.0.1-alpha.0",
3
+ "version": "1.0.2-alpha.1",
4
4
  "description": "CLI tool for fullstack template management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -30,7 +30,6 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@lark-apaas/devtool-kits": "^1.0.0",
33
- "@vercel/nft": "^0.30.3",
34
33
  "cac": "^6.7.14",
35
34
  "dotenv": "^16.0.0",
36
35
  "drizzle-kit": "0.31.5"
@@ -1,89 +1,39 @@
1
1
  #!/usr/bin/env bash
2
2
  # This file is auto-generated by @lark-apaas/fullstack-cli
3
+
3
4
  set -euo pipefail
4
5
 
5
6
  ROOT_DIR="$(pwd)"
6
7
  OUT_DIR="$ROOT_DIR/dist/server"
7
8
 
8
- # 记录总开始时间
9
- TOTAL_START=$(node -e "console.log(Date.now())")
10
-
11
- # 打印耗时的辅助函数
12
- print_time() {
13
- local start=$1
14
- local end=$(node -e "console.log(Date.now())")
15
- local elapsed=$((end - start))
16
- local seconds=$((elapsed / 1000))
17
- local ms=$((elapsed % 1000))
18
- echo " ⏱️ 耗时: ${seconds}.$(printf "%03d" $ms)s"
19
- }
20
-
21
- echo "╔════════════════════════════════════════════════════════╗"
22
- echo "║ 开始构建 - 智能裁剪版本 ║"
23
- echo "╚════════════════════════════════════════════════════════╝"
24
- echo ""
25
-
26
- # ==================== 步骤 0 ====================
27
- echo "📝 [0/4] 更新 openapi 代码"
28
- STEP_START=$(node -e "console.log(Date.now())")
9
+ echo "===================="
10
+ echo "0) 更新 openapi 代码"
11
+ echo "===================="
29
12
  npm run gen:openapi
30
- print_time $STEP_START
31
- echo ""
32
13
 
33
- # ==================== 步骤 1 ====================
34
- echo "🗑️ [1/4] 清理 dist 目录"
35
- STEP_START=$(node -e "console.log(Date.now())")
14
+ echo "===================="
15
+ echo "1) 清理 dist 目录"
16
+ echo "===================="
36
17
  rm -rf "$ROOT_DIR/dist"
37
- print_time $STEP_START
38
- echo ""
39
-
40
- # ==================== 步骤 2 ====================
41
- echo "🔨 [2/4] 并行构建 server 和 client"
42
- STEP_START=$(node -e "console.log(Date.now())")
43
-
44
- # 并行构建
45
- echo " ├─ 启动 server 构建..."
46
- npm run build:server > /tmp/build-server.log 2>&1 &
47
- SERVER_PID=$!
48
-
49
- echo " ├─ 启动 client 构建..."
50
- npm run build:client > /tmp/build-client.log 2>&1 &
51
- CLIENT_PID=$!
52
-
53
- # 等待两个构建完成
54
- SERVER_EXIT=0
55
- CLIENT_EXIT=0
56
18
 
57
- wait $SERVER_PID || SERVER_EXIT=$?
58
- wait $CLIENT_PID || CLIENT_EXIT=$?
59
-
60
- # 检查构建结果
61
- if [ $SERVER_EXIT -ne 0 ]; then
62
- echo " ❌ Server 构建失败"
63
- cat /tmp/build-server.log
64
- exit 1
65
- fi
66
-
67
- if [ $CLIENT_EXIT -ne 0 ]; then
68
- echo " ❌ Client 构建失败"
69
- cat /tmp/build-client.log
70
- exit 1
71
- fi
72
-
73
- echo " ✅ Server 构建完成"
74
- echo " ✅ Client 构建完成"
75
- print_time $STEP_START
76
- echo ""
77
-
78
- # ==================== 步骤 3 ====================
79
- echo "📦 [3/4] 准备 server 依赖产物"
80
- STEP_START=$(node -e "console.log(Date.now())")
19
+ echo "===================="
20
+ echo "2) 构建项目"
21
+ echo "===================="
22
+ npm run build:prod
23
+ echo "✅ Build completed"
81
24
 
25
+ echo "===================="
26
+ echo "3) 准备 server 产物目录"
27
+ echo "===================="
82
28
  mkdir -p "$OUT_DIR/dist/client"
83
29
 
84
30
  # 拷贝 HTML
85
31
  cp "$ROOT_DIR/dist/client/"*.html "$OUT_DIR/dist/client/" || true
86
32
 
33
+ # 拷贝 package.json
34
+ cp "$ROOT_DIR/package.json" "$OUT_DIR/"
35
+ [ -f "$ROOT_DIR/pnpm-lock.yaml" ] && cp "$ROOT_DIR/pnpm-lock.yaml" "$OUT_DIR/"
36
+
87
37
  # 拷贝 run.sh 文件
88
38
  cp "$ROOT_DIR/scripts/run.sh" "$OUT_DIR/"
89
39
 
@@ -91,30 +41,11 @@ cp "$ROOT_DIR/scripts/run.sh" "$OUT_DIR/"
91
41
  rm -rf "$ROOT_DIR/dist/scripts"
92
42
  rm -rf "$ROOT_DIR/dist/tsconfig.node.tsbuildinfo"
93
43
 
94
- print_time $STEP_START
95
- echo ""
96
-
97
- # ==================== 步骤 4 ====================
98
- echo "✂️ [4/4] 智能依赖裁剪"
99
- STEP_START=$(node -e "console.log(Date.now())")
100
-
101
- # 分析实际依赖、复制并裁剪 node_modules、生成精简的 package.json
102
- node "$ROOT_DIR/scripts/prune-smart.js"
103
-
104
- print_time $STEP_START
105
- echo ""
44
+ echo "===================="
45
+ echo "4) 复制 node_modules(仅生产依赖)"
46
+ echo "===================="
106
47
 
107
- # 总耗时
108
- echo "╔════════════════════════════════════════════════════════╗"
109
- echo "║ 构建完成 ║"
110
- echo "╚════════════════════════════════════════════════════════╝"
111
- print_time $TOTAL_START
48
+ npm prune --omit=dev
49
+ cp -R "$ROOT_DIR/node_modules" "$OUT_DIR/"
112
50
 
113
- # 输出产物信息
114
- DIST_SIZE=$(du -sh "$OUT_DIR" | cut -f1)
115
- NODE_MODULES_SIZE=$(du -sh "$OUT_DIR/node_modules" | cut -f1)
116
- echo ""
117
- echo "📊 构建产物统计:"
118
- echo " 总大小: $DIST_SIZE"
119
- echo " node_modules: $NODE_MODULES_SIZE"
120
- echo ""
51
+ echo "✅ node_modules ready"
@@ -1,270 +0,0 @@
1
- #!/usr/bin/env node
2
- // This file is auto-generated by @lark-apaas/fullstack-cli, do not modify it manually.
3
-
4
- /**
5
- * 智能依赖裁剪脚本 - 高性能版本
6
- *
7
- * 策略:
8
- * 1. 分析 dist/server 下所有文件的实际依赖
9
- * 2. **选择性复制**:只复制需要的包,而不是全部复制再删除
10
- * 3. 生成精简的 package.json 到 dist/server
11
- */
12
-
13
- const { nodeFileTrace } = require('@vercel/nft');
14
- const fs = require('fs');
15
- const path = require('path');
16
-
17
- const ROOT_DIR = path.resolve(__dirname, '..');
18
- const DIST_SERVER_DIR = path.join(ROOT_DIR, 'dist/server');
19
- const ROOT_PACKAGE_JSON = path.join(ROOT_DIR, 'package.json');
20
- const ROOT_NODE_MODULES = path.join(ROOT_DIR, 'node_modules');
21
- const OUT_NODE_MODULES = path.join(DIST_SERVER_DIR, 'node_modules');
22
- const OUT_PACKAGE_JSON = path.join(DIST_SERVER_DIR, 'package.json');
23
-
24
- // Node.js 内置模块列表
25
- const BUILTIN_MODULES = new Set([
26
- 'assert', 'buffer', 'child_process', 'cluster', 'crypto', 'dgram', 'dns',
27
- 'events', 'fs', 'http', 'http2', 'https', 'net', 'os', 'path', 'stream',
28
- 'string_decoder', 'timers', 'tls', 'url', 'util', 'v8', 'vm', 'zlib',
29
- 'async_hooks', 'perf_hooks', 'worker_threads', 'inspector', 'trace_events'
30
- ]);
31
-
32
- /**
33
- * 递归获取目录下所有 .js 文件
34
- */
35
- function getJsFiles(dir) {
36
- const files = [];
37
-
38
- if (!fs.existsSync(dir)) {
39
- console.error(`❌ 目录不存在: ${dir}`);
40
- process.exit(1);
41
- }
42
-
43
- function traverse(currentDir) {
44
- const items = fs.readdirSync(currentDir);
45
- for (const item of items) {
46
- const fullPath = path.join(currentDir, item);
47
- const stat = fs.statSync(fullPath);
48
-
49
- if (stat.isDirectory() && item !== 'node_modules') {
50
- traverse(fullPath);
51
- } else if (stat.isFile() && item.endsWith('.js')) {
52
- files.push(fullPath);
53
- }
54
- }
55
- }
56
-
57
- traverse(dir);
58
- return files;
59
- }
60
-
61
- /**
62
- * 从完整路径中提取 npm 包名
63
- */
64
- function extractPackageName(filePath) {
65
- const parts = filePath.split('node_modules' + path.sep);
66
- if (parts.length < 2) return null;
67
-
68
- const afterNodeModules = parts[parts.length - 1];
69
- const segments = afterNodeModules.split(path.sep);
70
-
71
- // 处理 scoped package (@xxx/yyy)
72
- if (segments[0].startsWith('@')) {
73
- return segments[0] + '/' + segments[1];
74
- }
75
-
76
- return segments[0];
77
- }
78
-
79
- /**
80
- * 递归删除目录
81
- */
82
- function removeDir(dir) {
83
- if (fs.existsSync(dir)) {
84
- fs.rmSync(dir, { recursive: true, force: true });
85
- }
86
- }
87
-
88
- /**
89
- * 递归复制目录
90
- */
91
- function copyDir(src, dest) {
92
- if (!fs.existsSync(dest)) {
93
- fs.mkdirSync(dest, { recursive: true });
94
- }
95
-
96
- const entries = fs.readdirSync(src, { withFileTypes: true });
97
-
98
- for (const entry of entries) {
99
- const srcPath = path.join(src, entry.name);
100
- const destPath = path.join(dest, entry.name);
101
-
102
- if (entry.isDirectory()) {
103
- copyDir(srcPath, destPath);
104
- } else {
105
- fs.copyFileSync(srcPath, destPath);
106
- }
107
- }
108
- }
109
-
110
- /**
111
- * 选择性复制包
112
- */
113
- function copyPackagesSelectively(packages, rootNodeModules, outNodeModules) {
114
- const copiedCount = { success: 0, failed: 0 };
115
-
116
- // 确保输出目录存在
117
- if (fs.existsSync(outNodeModules)) {
118
- removeDir(outNodeModules);
119
- }
120
- fs.mkdirSync(outNodeModules, { recursive: true });
121
-
122
- // 注意:不复制 .bin 目录,运行时不需要
123
-
124
- // 复制每个包
125
- for (const pkg of packages) {
126
- const srcPath = path.join(rootNodeModules, pkg);
127
- const destPath = path.join(outNodeModules, pkg);
128
-
129
- if (!fs.existsSync(srcPath)) {
130
- copiedCount.failed++;
131
- continue;
132
- }
133
-
134
- try {
135
- // 确保父目录存在(处理 scoped packages)
136
- const destDir = path.dirname(destPath);
137
- if (!fs.existsSync(destDir)) {
138
- fs.mkdirSync(destDir, { recursive: true });
139
- }
140
-
141
- // 复制包目录
142
- copyDir(srcPath, destPath);
143
- copiedCount.success++;
144
- } catch (err) {
145
- console.error(` ⚠️ 复制失败: ${pkg} - ${err.message}`);
146
- copiedCount.failed++;
147
- }
148
- }
149
-
150
- return copiedCount;
151
- }
152
-
153
- /**
154
- * 主函数:智能裁剪
155
- */
156
- async function smartPrune() {
157
- console.log('🔍 开始智能依赖分析...\n');
158
-
159
- const totalStartTime = Date.now();
160
-
161
- // 1. 获取所有 server 构建产物
162
- const jsFiles = getJsFiles(DIST_SERVER_DIR);
163
- console.log(`📂 找到 ${jsFiles.length} 个 JS 文件`);
164
-
165
- if (jsFiles.length === 0) {
166
- console.error('❌ 没有找到任何 JS 文件');
167
- process.exit(1);
168
- }
169
-
170
- // 2. 使用 @vercel/nft 追踪依赖
171
- console.log('🔎 追踪实际依赖...');
172
- const analyzeStart = Date.now();
173
-
174
- const { fileList } = await nodeFileTrace(jsFiles, {
175
- base: ROOT_DIR,
176
- processCwd: ROOT_DIR,
177
- // 性能优化选项
178
- cache: {}, // 启用缓存,避免重复分析相同文件
179
- ignore: [
180
- // 忽略明显不需要的文件类型
181
- '**/*.md',
182
- '**/*.ts',
183
- '**/*.d.ts',
184
- '**/test/**',
185
- '**/tests/**',
186
- '**/__tests__/**',
187
- '**/examples/**',
188
- '**/docs/**',
189
- '**/.git/**',
190
- ],
191
- });
192
-
193
- const analyzeElapsed = Date.now() - analyzeStart;
194
- console.log(` ✅ 分析完成,耗时: ${analyzeElapsed}ms\n`);
195
-
196
- // 3. 提取 npm 包名
197
- const requiredPackages = new Set();
198
-
199
- for (const file of fileList) {
200
- if (file.includes('node_modules')) {
201
- const pkgName = extractPackageName(file);
202
- if (pkgName && !BUILTIN_MODULES.has(pkgName)) {
203
- requiredPackages.add(pkgName);
204
- }
205
- }
206
- }
207
-
208
- console.log(`📦 实际需要 ${requiredPackages.size} 个 npm 包\n`);
209
-
210
- // 4. 选择性复制包(只复制需要的)
211
- console.log('📋 选择性复制 node_modules(仅复制需要的包)...');
212
- const copyStart = Date.now();
213
-
214
- const sortedPackages = Array.from(requiredPackages).sort();
215
- const copiedCount = copyPackagesSelectively(sortedPackages, ROOT_NODE_MODULES, OUT_NODE_MODULES);
216
-
217
- const copyElapsed = Date.now() - copyStart;
218
- console.log(` ✅ 复制完成,耗时: ${copyElapsed}ms`);
219
- console.log(` 成功: ${copiedCount.success} 个,失败: ${copiedCount.failed} 个\n`);
220
-
221
- // 5. 读取原始 package.json 并生成精简版本
222
- const originalPackage = JSON.parse(fs.readFileSync(ROOT_PACKAGE_JSON, 'utf8'));
223
- const allDeps = {
224
- ...originalPackage.dependencies || {},
225
- ...originalPackage.devDependencies || {}
226
- };
227
-
228
- const prunedDependencies = {};
229
- for (const pkg of requiredPackages) {
230
- if (allDeps[pkg]) {
231
- prunedDependencies[pkg] = allDeps[pkg];
232
- }
233
- }
234
-
235
- const prunedPackage = {
236
- name: originalPackage.name,
237
- version: originalPackage.version,
238
- private: true,
239
- dependencies: prunedDependencies,
240
- scripts: {
241
- start: originalPackage.scripts?.start || 'node main.js'
242
- },
243
- engines: originalPackage.engines
244
- };
245
-
246
- fs.writeFileSync(OUT_PACKAGE_JSON, JSON.stringify(prunedPackage, null, 2));
247
-
248
- const totalElapsed = Date.now() - totalStartTime;
249
-
250
- // 6. 输出统计信息
251
- console.log('='.repeat(60));
252
- console.log('📊 智能裁剪统计:');
253
- console.log('='.repeat(60));
254
- console.log(` 需要的包数量: ${requiredPackages.size}`);
255
- console.log(` 成功复制: ${copiedCount.success} 个`);
256
- console.log(` 失败: ${copiedCount.failed} 个`);
257
- console.log(` 分析耗时: ${analyzeElapsed}ms`);
258
- console.log(` 复制耗时: ${copyElapsed}ms`);
259
- console.log(` 总耗时: ${totalElapsed}ms`);
260
- console.log('='.repeat(60) + '\n');
261
-
262
- console.log('✅ 智能裁剪完成!');
263
- console.log(`📍 精简的 package.json 已保存到: ${OUT_PACKAGE_JSON}\n`);
264
- }
265
-
266
- // 运行智能裁剪
267
- smartPrune().catch(err => {
268
- console.error('❌ 智能裁剪失败:', err);
269
- process.exit(1);
270
- });