@lark-apaas/coding-template-nestjs-react-fullstack 0.1.42 → 0.1.43-alpha.20260918074821

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.
@@ -28,7 +28,7 @@
28
28
  "upgrade": "npx -y @lark-apaas/fullstack-cli sync --disable-gen-openapi"
29
29
  },
30
30
  "dependencies": {
31
- "@lark-apaas/fullstack-nestjs-core": "^1.1.62",
31
+ "@lark-apaas/fullstack-nestjs-core": "1.1.63-alpha.20260918073530",
32
32
  "@nestjs/axios": "^4.0.1",
33
33
  "@nestjs/cache-manager": "^3.1.3",
34
34
  "@nestjs/common": "^10.4.20",
@@ -52,9 +52,9 @@
52
52
  },
53
53
  "devDependencies": {
54
54
  "@hookform/resolvers": "^5.2.2",
55
- "@lark-apaas/client-toolkit": "^1.2.71",
56
- "@lark-apaas/coding-preset-vite-react": "^1.0.23",
57
- "@lark-apaas/fullstack-presets": "^1.1.0",
55
+ "@lark-apaas/client-toolkit": "^1.2.70",
56
+ "@lark-apaas/coding-preset-vite-react": "1.0.24-alpha.20260918073537",
57
+ "@lark-apaas/fullstack-presets": "1.1.24-alpha.20260918073533",
58
58
  "@nestjs/cli": "^10.4.9",
59
59
  "@radix-ui/react-accordion": "^1.2.12",
60
60
  "@radix-ui/react-alert-dialog": "^1.1.15",
@@ -3,7 +3,7 @@
3
3
  set -euo pipefail
4
4
 
5
5
  ROOT_DIR="$(pwd)"
6
- OUT_DIR="$ROOT_DIR/dist/server"
6
+ DIST_DIR="$ROOT_DIR/dist"
7
7
 
8
8
  # 记录总开始时间
9
9
  TOTAL_START=$(node -e "console.log(Date.now())")
@@ -19,94 +19,174 @@ print_time() {
19
19
  }
20
20
 
21
21
  # ==================== 步骤 0 ====================
22
- echo "🗑️ [0/5] 安装插件"
22
+ echo "🗑️ [0/6] 安装插件"
23
23
  STEP_START=$(node -e "console.log(Date.now())")
24
24
  npx fullstack-cli action-plugin init
25
25
  print_time $STEP_START
26
26
  echo ""
27
27
 
28
28
  # ==================== 步骤 1 ====================
29
- echo "📝 [1/5] 更新 openapi 代码"
29
+ echo "📝 [1/6] 更新 openapi 代码"
30
30
  STEP_START=$(node -e "console.log(Date.now())")
31
31
  npm run gen:openapi
32
32
  print_time $STEP_START
33
33
  echo ""
34
34
 
35
35
  # ==================== 步骤 2 ====================
36
- echo "🗑️ [2/5] 清理 dist 目录"
36
+ echo "🗑️ [2/6] 清理 dist 目录"
37
37
  STEP_START=$(node -e "console.log(Date.now())")
38
38
  rm -rf "$ROOT_DIR/dist"
39
39
  print_time $STEP_START
40
40
  echo ""
41
41
 
42
42
  # ==================== 步骤 3 ====================
43
- echo "🔨 [3/5] 并行构建 server 和 client"
43
+ echo "🗺️ [3/6] 生成路由定义"
44
44
  STEP_START=$(node -e "console.log(Date.now())")
45
45
 
46
- # 并行构建
47
- echo " ├─ 启动 server 构建..."
48
- npm run build:server > /tmp/build-server.log 2>&1 &
49
- SERVER_PID=$!
46
+ # 在 client/server 构建之前生成到 dist/,供 DefinePlugin 注入前端 bundle
47
+ # 注意:nest-cli.json 中 deleteOutDir 必须为 false(模板默认值),否则 nest build 会清掉 dist/
48
+ echo " ├─ 生成 API 路由定义..."
49
+ npx generate-api-routes --server-dir ./server --out-dir ./dist > /tmp/gen-api-routes.log 2>&1 &
50
+ API_ROUTES_PID=$!
50
51
 
51
- echo " ├─ 启动 client 构建..."
52
- npm run build:client > /tmp/build-client.log 2>&1 &
53
- CLIENT_PID=$!
52
+ echo " ├─ 生成页面路由定义..."
53
+ npx generate-page-routes --app-path ./client/src/app.tsx --out-dir ./dist > /tmp/gen-page-routes.log 2>&1 &
54
+ PAGE_ROUTES_PID=$!
54
55
 
55
- # 等待两个构建完成
56
- SERVER_EXIT=0
57
- CLIENT_EXIT=0
56
+ API_ROUTES_EXIT=0
57
+ PAGE_ROUTES_EXIT=0
58
58
 
59
- wait $SERVER_PID || SERVER_EXIT=$?
60
- wait $CLIENT_PID || CLIENT_EXIT=$?
59
+ wait $API_ROUTES_PID || API_ROUTES_EXIT=$?
60
+ wait $PAGE_ROUTES_PID || PAGE_ROUTES_EXIT=$?
61
61
 
62
- # 检查构建结果
63
- if [ $SERVER_EXIT -ne 0 ]; then
64
- echo " ❌ Server 构建失败"
65
- cat /tmp/build-server.log
66
- exit 1
62
+ if [ $API_ROUTES_EXIT -ne 0 ]; then
63
+ echo " ⚠️ API 路由生成失败(不影响构建)"
64
+ cat /tmp/gen-api-routes.log
65
+ else
66
+ echo " ✅ API 路由生成完成"
67
67
  fi
68
68
 
69
- if [ $CLIENT_EXIT -ne 0 ]; then
70
- echo " ❌ Client 构建失败"
71
- cat /tmp/build-client.log
72
- exit 1
69
+ if [ $PAGE_ROUTES_EXIT -ne 0 ]; then
70
+ echo " ⚠️ 页面路由生成失败(不影响构建)"
71
+ cat /tmp/gen-page-routes.log
72
+ else
73
+ echo " ✅ 页面路由生成完成"
73
74
  fi
74
-
75
- echo " ✅ Server 构建完成"
76
- echo " ✅ Client 构建完成"
77
75
  print_time $STEP_START
78
76
  echo ""
79
77
 
80
78
  # ==================== 步骤 4 ====================
81
- echo "📦 [4/5] 准备 server 依赖产物"
79
+ echo "🔨 [4/6] 并行构建 server 和 client"
82
80
  STEP_START=$(node -e "console.log(Date.now())")
83
81
 
84
- mkdir -p "$OUT_DIR/dist/client"
85
-
86
- # public 先进(server setBaseViewsDir + nestjs-core 中间件同源 serve)
87
- if [ -d "$ROOT_DIR/client/public" ]; then
88
- cp -R "$ROOT_DIR/client/public/." "$OUT_DIR/dist/client/"
82
+ # 给 server/client 构建子进程预留 8GB heap,缓解 vite build transform 阶段 OOM
83
+ # (典型错误:Reached heap limit Allocation failed)。
84
+ # 仅在外部未设置 NODE_OPTIONS 时注入,允许 CI / 用户通过外部环境变量完全覆盖
85
+ BUILD_NODE_OPTIONS="${NODE_OPTIONS:---max-old-space-size=8192}"
86
+
87
+ # 根据 only_frontend_change 决定是否构建 server
88
+ if [[ "${only_frontend_change:-false}" == "true" ]]; then
89
+ echo "🔨 [4/6] 仅构建 client (only_frontend_change=true)"
90
+
91
+ echo " ├─ 启动 client 构建..."
92
+ NODE_OPTIONS="$BUILD_NODE_OPTIONS" npm run build:client > /tmp/build-client.log 2>&1
93
+ CLIENT_EXIT=$?
94
+
95
+ if [ $CLIENT_EXIT -ne 0 ]; then
96
+ echo " ❌ Client 构建失败"
97
+ cat /tmp/build-client.log
98
+ exit 1
99
+ fi
100
+
101
+ echo " ✅ Client 构建完成"
102
+ else
103
+ echo "🔨 [4/6] 并行构建 server 和 client"
104
+
105
+ # 并行构建
106
+ echo " ├─ 启动 server 构建..."
107
+ NODE_OPTIONS="$BUILD_NODE_OPTIONS" npm run build:server > /tmp/build-server.log 2>&1 &
108
+ SERVER_PID=$!
109
+
110
+ echo " ├─ 启动 client 构建..."
111
+ NODE_OPTIONS="$BUILD_NODE_OPTIONS" npm run build:client > /tmp/build-client.log 2>&1 &
112
+ CLIENT_PID=$!
113
+
114
+ # 等待两个构建完成
115
+ SERVER_EXIT=0
116
+ CLIENT_EXIT=0
117
+
118
+ wait $SERVER_PID || SERVER_EXIT=$?
119
+ wait $CLIENT_PID || CLIENT_EXIT=$?
120
+
121
+ # 检查构建结果
122
+ if [ $SERVER_EXIT -ne 0 ]; then
123
+ echo " ❌ Server 构建失败"
124
+ cat /tmp/build-server.log
125
+ exit 1
126
+ fi
127
+
128
+ if [ $CLIENT_EXIT -ne 0 ]; then
129
+ echo " ❌ Client 构建失败"
130
+ cat /tmp/build-client.log
131
+ exit 1
132
+ fi
133
+
134
+ echo " ✅ Server 构建完成"
135
+ echo " ✅ Client 构建完成"
89
136
  fi
90
137
 
91
- # 构建产物 HTML 随后拷,覆盖 public 里的同名文件(保证入口页是构建版,不被 public 静默覆盖)
92
- cp "$ROOT_DIR/dist/client/"*.html "$OUT_DIR/dist/client/" || true
138
+ print_time $STEP_START
139
+ echo ""
140
+
141
+ # ==================== 步骤 5 ====================
142
+ echo "📦 [5/6] 准备产物"
143
+ STEP_START=$(node -e "console.log(Date.now())")
144
+
145
+ # 移动 client 下的 HTML 文件到 dist/dist/client,保证 views 路径在 dev/prod 下一致
146
+ # 使用 mv 而非 cp:HTML 不能上传到公网 CDN,移走后 dist/client 中不再包含 HTML
147
+ if [ -d "$DIST_DIR/client" ]; then
148
+ mkdir -p "$DIST_DIR/dist/client"
149
+ # public 先进(顶层 client 打包被排除;server setBaseViewsDir + 中间件同源 serve)
150
+ if [ -d "$ROOT_DIR/client/public" ]; then
151
+ cp -R "$ROOT_DIR/client/public/." "$DIST_DIR/dist/client/"
152
+ fi
153
+ # 构建产物 HTML 随后 move,覆盖 public 里的同名文件(保证入口页是构建版,不被 public 静默覆盖)
154
+ find "$DIST_DIR/client" -maxdepth 1 -name "*.html" -exec mv {} "$DIST_DIR/dist/client/" \;
155
+ fi
93
156
 
94
- # 拷贝 run.sh 文件
95
- cp "$ROOT_DIR/scripts/run.sh" "$OUT_DIR/"
157
+ # server 相关产物准备(only_frontend_change=true 时跳过)
158
+ if [[ "${only_frontend_change:-false}" == "true" ]]; then
159
+ echo " [skip] 跳过 run.sh/.env 复制 (only_frontend_change=true)"
160
+ else
161
+ # 拷贝 run.sh 到 dist/(prod 从 dist/ 启动,确保 cwd 一致性)
162
+ cp "$ROOT_DIR/scripts/run.sh" "$DIST_DIR/"
163
+
164
+ # 拷贝 .env 文件(如果存在)
165
+ if [ -f "$ROOT_DIR/.env" ]; then
166
+ cp "$ROOT_DIR/.env" "$DIST_DIR/"
167
+ fi
168
+ fi
96
169
 
97
170
  # 清理无用文件
98
- rm -rf "$ROOT_DIR/dist/scripts"
99
- rm -rf "$ROOT_DIR/dist/tsconfig.node.tsbuildinfo"
171
+ rm -rf "$DIST_DIR/scripts"
172
+ rm -rf "$DIST_DIR/tsconfig.node.tsbuildinfo"
100
173
 
101
174
  print_time $STEP_START
102
175
  echo ""
103
176
 
104
- # ==================== 步骤 5 ====================
105
- echo "✂️ [5/5] 智能依赖裁剪"
177
+ # ==================== 步骤 6 ====================
178
+ echo "✂️ [6/6] 智能依赖裁剪"
106
179
  STEP_START=$(node -e "console.log(Date.now())")
107
180
 
108
- # 分析实际依赖、复制并裁剪 node_modules、生成精简的 package.json
109
- node "$ROOT_DIR/scripts/prune-smart.js"
181
+ # 智能依赖裁剪(仅全量构建时执行,纯前端场景不打包 server,无需裁剪)
182
+ if [[ "${only_frontend_change:-false}" == "true" ]]; then
183
+ echo "✂️ [6/6] 跳过智能依赖裁剪 (only_frontend_change=true)"
184
+ else
185
+ echo "✂️ [6/6] 智能依赖裁剪"
186
+
187
+ # 分析实际依赖、复制并裁剪 node_modules、生成精简的 package.json
188
+ node "$ROOT_DIR/scripts/prune-smart.js"
189
+ fi
110
190
 
111
191
  print_time $STEP_START
112
192
  echo ""
@@ -116,10 +196,17 @@ echo "构建完成"
116
196
  print_time $TOTAL_START
117
197
 
118
198
  # 输出产物信息
119
- DIST_SIZE=$(du -sh "$OUT_DIR" | cut -f1)
120
- NODE_MODULES_SIZE=$(du -sh "$OUT_DIR/node_modules" | cut -f1)
121
- echo ""
122
- echo "📊 构建产物统计:"
123
- echo " 总大小: $DIST_SIZE"
124
- echo " node_modules: $NODE_MODULES_SIZE"
125
- echo ""
199
+ DIST_SIZE=$(du -sh "$DIST_DIR" | cut -f1)
200
+ if [[ "${only_frontend_change:-false}" == "true" ]]; then
201
+ echo ""
202
+ echo "📊 构建产物统计:"
203
+ echo " 产物大小: $DIST_SIZE"
204
+ echo ""
205
+ else
206
+ NODE_MODULES_SIZE=$(du -sh "$DIST_DIR/node_modules" | cut -f1)
207
+ echo ""
208
+ echo "📊 构建产物统计:"
209
+ echo " 产物大小: $DIST_SIZE"
210
+ echo " node_modules: $NODE_MODULES_SIZE"
211
+ echo ""
212
+ fi
@@ -6,15 +6,53 @@ const fs = require('fs');
6
6
  const path = require('path');
7
7
 
8
8
  const ROOT_DIR = path.resolve(__dirname, '..');
9
- const DIST_SERVER_DIR = path.join(ROOT_DIR, 'dist/server');
9
+
10
+ // 加载提交的 .env,供读取构建期配置(如 MIAODA_RUNTIME_ENTRIES)。dotenv 不一定安装 → 静默降级。
11
+ try {
12
+ require('dotenv').config({ path: path.join(ROOT_DIR, '.env') });
13
+ } catch {
14
+ // dotenv 未安装:跳过;MIAODA_RUNTIME_ENTRIES 仍可来自真实环境变量
15
+ }
16
+ const DIST_DIR = path.join(ROOT_DIR, 'dist');
17
+ const DIST_SERVER_DIR = path.join(DIST_DIR, 'server');
10
18
  const ROOT_PACKAGE_JSON = path.join(ROOT_DIR, 'package.json');
11
19
  const ROOT_NODE_MODULES = path.join(ROOT_DIR, 'node_modules');
12
- const OUT_NODE_MODULES = path.join(DIST_SERVER_DIR, 'node_modules');
13
- const OUT_PACKAGE_JSON = path.join(DIST_SERVER_DIR, 'package.json');
20
+ const OUT_NODE_MODULES = path.join(DIST_DIR, 'node_modules');
21
+ const OUT_PACKAGE_JSON = path.join(DIST_DIR, 'package.json');
14
22
 
15
23
  // Server 入口文件
16
24
  const SERVER_ENTRY = path.join(DIST_SERVER_DIR, 'main.js');
17
25
 
26
+ // nest sourceRoot(源码根,默认 server):把 .env 里声明的源码路径映射到构建产物位置
27
+ let SOURCE_ROOT = 'server';
28
+ try {
29
+ const nestCli = JSON.parse(fs.readFileSync(path.join(ROOT_DIR, 'nest-cli.json'), 'utf8'));
30
+ if (nestCli.sourceRoot) SOURCE_ROOT = nestCli.sourceRoot;
31
+ } catch {
32
+ // 读不到 nest-cli.json 则用默认 server
33
+ }
34
+ const SRC_TO_OUT_EXT = { '.mts': '.mjs', '.cts': '.cjs', '.ts': '.js' };
35
+
36
+ // 额外 trace 入口:经 new Function/动态 import 加载、nft 无法从 main.js 静态发现的 ESM runtime。
37
+ // 应用在提交的 .env 里用 MIAODA_RUNTIME_ENTRIES 声明【源码路径】(相对项目根,逗号分隔),例如:
38
+ // MIAODA_RUNTIME_ENTRIES=server/modules/ethics/runtime/review-run.mjs,server/modules/ethics/runtime/parse-core.mjs
39
+ // 脚本按 nest sourceRoot 自动映射到 dist/server 下的构建产物(并重写 .mts→.mjs / .ts→.js)。
40
+ const RUNTIME_ENTRIES = (process.env.MIAODA_RUNTIME_ENTRIES || '')
41
+ .split(',')
42
+ .map((s) => s.trim())
43
+ .filter(Boolean)
44
+ .map((srcRel) => {
45
+ const fromSrc = path.relative(SOURCE_ROOT, srcRel); // 去掉 sourceRoot 前缀
46
+ const ext = path.extname(fromSrc);
47
+ const outRel = SRC_TO_OUT_EXT[ext] ? fromSrc.slice(0, -ext.length) + SRC_TO_OUT_EXT[ext] : fromSrc;
48
+ return path.join(DIST_SERVER_DIR, outRel);
49
+ })
50
+ .filter((p) => {
51
+ if (fs.existsSync(p)) return true;
52
+ console.warn(`⚠️ MIAODA_RUNTIME_ENTRIES 入口在构建产物中不存在,已忽略: ${path.relative(ROOT_DIR, p)}`);
53
+ return false;
54
+ });
55
+
18
56
  // Node.js 内置模块列表
19
57
  const BUILTIN_MODULES = new Set([
20
58
  'assert', 'buffer', 'child_process', 'cluster', 'crypto', 'dgram', 'dns',
@@ -144,12 +182,15 @@ async function smartPrune() {
144
182
  }
145
183
 
146
184
  console.log(`📂 分析入口文件: ${path.relative(ROOT_DIR, SERVER_ENTRY)}`);
185
+ if (RUNTIME_ENTRIES.length) {
186
+ console.log(`📎 额外 trace 入口 (${RUNTIME_ENTRIES.length}): ${RUNTIME_ENTRIES.map((p) => path.relative(DIST_SERVER_DIR, p)).join(', ')}`);
187
+ }
147
188
 
148
189
  // 2. 使用 @vercel/nft 追踪依赖
149
190
  console.log('🔎 追踪实际依赖...');
150
191
  const analyzeStart = Date.now();
151
192
 
152
- const { fileList } = await nodeFileTrace([SERVER_ENTRY], {
193
+ const { fileList } = await nodeFileTrace([SERVER_ENTRY, ...RUNTIME_ENTRIES], {
153
194
  base: ROOT_DIR,
154
195
  processCwd: ROOT_DIR,
155
196
  ts: false, // 禁用 TS 解析
@@ -180,8 +221,59 @@ async function smartPrune() {
180
221
 
181
222
  console.log(`📦 静态分析需要 ${requiredPackages.size} 个 npm 包`);
182
223
 
183
- // 4. 处理 actionPlugins(动态加载的插件,无法被静态分析追踪)
224
+ // 4. 从 nft 结果递归收集子依赖(处理动态 require 无法被静态分析追踪的问题)
225
+ // 某些包(如 pdf-parse)使用 try-catch 动态加载依赖(如 @napi-rs/canvas),
226
+ // @vercel/nft 无法追踪这类依赖,需要基于 package.json 声明补充
227
+ // 策略:只对 nft 已追踪到的包递归,避免收集无关依赖
184
228
  const originalPackage = JSON.parse(fs.readFileSync(ROOT_PACKAGE_JSON, 'utf8'));
229
+
230
+ let addedSubDeps = 0;
231
+ const visited = new Set(); // 防止循环依赖导致无限循环
232
+ const queue = [...requiredPackages]; // BFS 队列,从 nft 结果开始(更精准)
233
+
234
+ while (queue.length > 0) {
235
+ const depName = queue.shift();
236
+
237
+ // 跳过已访问的包(防止循环依赖)
238
+ if (visited.has(depName)) continue;
239
+ visited.add(depName);
240
+
241
+ const depPkgPath = path.join(ROOT_NODE_MODULES, depName, 'package.json');
242
+ if (!fs.existsSync(depPkgPath)) continue;
243
+
244
+ try {
245
+ const depPkg = JSON.parse(fs.readFileSync(depPkgPath, 'utf8'));
246
+ const subDeps = {
247
+ ...depPkg.dependencies,
248
+ ...depPkg.optionalDependencies,
249
+ };
250
+
251
+ for (const subDep of Object.keys(subDeps)) {
252
+ // 检查包是否存在于 node_modules 中
253
+ const subDepPath = path.join(ROOT_NODE_MODULES, subDep);
254
+ if (!fs.existsSync(subDepPath)) continue;
255
+
256
+ // 如果是新发现的包,添加到结果集并加入队列继续遍历
257
+ if (!requiredPackages.has(subDep)) {
258
+ requiredPackages.add(subDep);
259
+ addedSubDeps++;
260
+ }
261
+
262
+ // 无论是否已在 requiredPackages 中,都需要继续遍历其子依赖
263
+ if (!visited.has(subDep)) {
264
+ queue.push(subDep);
265
+ }
266
+ }
267
+ } catch {
268
+ // 忽略解析错误
269
+ }
270
+ }
271
+
272
+ if (addedSubDeps > 0) {
273
+ console.log(`📦 递归补充动态依赖,新增 ${addedSubDeps} 个包`);
274
+ }
275
+
276
+ // 5. 处理 actionPlugins(动态加载的插件,无法被静态分析追踪)
185
277
  const actionPlugins = originalPackage.actionPlugins || {};
186
278
  const actionPluginNames = Object.keys(actionPlugins);
187
279
 
@@ -212,7 +304,7 @@ async function smartPrune() {
212
304
 
213
305
  console.log(`📦 总共需要 ${requiredPackages.size} 个 npm 包\n`);
214
306
 
215
- // 5. 选择性复制包(只复制需要的)
307
+ // 6. 选择性复制包(只复制需要的)
216
308
  console.log('📋 选择性复制 node_modules(仅复制需要的包)...');
217
309
  const copyStart = Date.now();
218
310
 
@@ -224,7 +316,7 @@ async function smartPrune() {
224
316
  console.log(` 成功: ${copiedCount.success} 个包,失败: ${copiedCount.failed} 个`);
225
317
  console.log(` 硬链接: ${fileStats.hardLinks} 个文件,复制: ${fileStats.copies} 个文件\n`);
226
318
 
227
- // 6. 生成精简版 package.json
319
+ // 7. 生成精简版 package.json
228
320
  // 优化:直接构建 dependencies,避免多次对象展开
229
321
  const prunedDependencies = {};
230
322
  const allDeps = originalPackage.dependencies || {};
@@ -243,9 +335,6 @@ async function smartPrune() {
243
335
  version: originalPackage.version,
244
336
  private: true,
245
337
  dependencies: prunedDependencies,
246
- scripts: {
247
- start: originalPackage.scripts?.start || 'node main.js'
248
- },
249
338
  engines: originalPackage.engines
250
339
  };
251
340
 
@@ -253,7 +342,7 @@ async function smartPrune() {
253
342
 
254
343
  const totalElapsed = Date.now() - totalStartTime;
255
344
 
256
- // 7. 输出统计信息
345
+ // 8. 输出统计信息
257
346
  console.log('='.repeat(60));
258
347
  console.log('📊 智能裁剪统计:');
259
348
  console.log('='.repeat(60));
@@ -2,4 +2,7 @@
2
2
  # This file is auto-generated by @lark-apaas/fullstack-cli
3
3
 
4
4
  # 生产环境下,启动服务
5
- npm run start
5
+ # 从 dist/ 根目录执行,确保 process.cwd() 与 dev 模式一致
6
+ # dev: cwd = 项目根, shared/ client/ 可达
7
+ # prod: cwd = dist/, shared/ client/ 可达
8
+ NODE_ENV=production node server/main.js
@@ -13,5 +13,6 @@
13
13
  "excludeDirectories": ["node_modules/**"]
14
14
  },
15
15
  "include": ["server/**/*", "shared/**/*.ts"],
16
- "exclude": ["node_modules", "dist", "client", "source_package", "**/*.spec.ts", "**/*.e2e-spec.ts"],
16
+ // MCP UI 是独立浏览器工程,不使用服务端的 TypeScript 配置。
17
+ "exclude": ["server/mcp/ui", "node_modules", "dist", "client", "source_package", "**/*.spec.ts", "**/*.e2e-spec.ts"],
17
18
  }