@lark-apaas/coding-template-nestjs-react-fullstack 0.1.43-alpha.20260918074821 → 0.1.43
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 +0 -18
- package/package.json +1 -1
- package/template/package-lock.json +33 -33
- package/template/package.json +4 -4
- package/template/scripts/build.sh +52 -139
- package/template/scripts/prune-smart.js +11 -100
- package/template/scripts/run.sh +1 -4
- package/template/tsconfig.node.json +1 -2
package/README.md
CHANGED
|
@@ -27,16 +27,6 @@ MIAODA_APP_TYPE=3 npx @lark-apaas/miaoda-cli@<latest> app init \
|
|
|
27
27
|
- `SANDBOX_PUBLIC_URL` —— 沙箱公网域
|
|
28
28
|
- `CLIENT_BASE_PATH=/app/<app_id>/` —— React Router basename + Vite base
|
|
29
29
|
|
|
30
|
-
## MCP UI 的类型与代码检查
|
|
31
|
-
|
|
32
|
-
创建 MCP UI 时,Agent 在 `server/mcp/ui` 中同时生成 `tsconfig.json` 和 `eslint.config.cjs`,修改 UI 或其 shared 依赖后主动运行独立检查。模板和 CLI 不生成 UI 配置,也不将 UI 检查接入主工程 lint/type:check。
|
|
33
|
-
|
|
34
|
-
主工程保留原 client/server 检查。Agent 从工程根执行 `npx --no-install tsc --noEmit --project server/mcp/ui/tsconfig.json`,再执行 `npx --no-install eslint --config server/mcp/ui/eslint.config.cjs "server/mcp/ui/**/*.{ts,tsx,js,jsx}" --max-warnings 0`;必须检查退出码并修复错误。无需辅助脚本或新增 npm 命令。
|
|
35
|
-
|
|
36
|
-
CLI 不注入 MCP UI 检查命令;主工程保留原有 client/server 检查,UI 由 Agent 按独立配置执行标准 tsc/eslint。
|
|
37
|
-
|
|
38
|
-
存量 sync 不改写 ESLint 源码;UI 全局排除项由平台 ESLint 预设提供。TS 仅向已有显式 `exclude` 数组追加目录,保留注释和原项;依赖继承且未显式声明 `exclude` 的自定义配置保持不变并提示人工调整。自定义检查命令保留。UI ESLint 配置可显式引用 `fullstack-presets/lib/mcp/eslint-ui`。
|
|
39
|
-
|
|
40
30
|
## 包结构
|
|
41
31
|
|
|
42
32
|
```
|
|
@@ -49,11 +39,3 @@ CLI 不注入 MCP UI 检查命令;主工程保留原有 client/server 检查
|
|
|
49
39
|
`template/` 内以下划线开头的占位文件(`_gitignore` / `_npmrc` / `_env.local`)在 `miaoda app init`
|
|
50
40
|
渲染时会按 RENAME 映射改回正常名(npm pack 会特殊处理 `.gitignore`、且 `.npmrc` 直接放
|
|
51
41
|
在包里会污染用户 `npm install` 行为,所以都要 underscore 前缀)。
|
|
52
|
-
|
|
53
|
-
## MCP 版本与 UI 检查
|
|
54
|
-
|
|
55
|
-
模板不生成 `mcp-build-id`,构建脚本沿用原流程。SDK 发布态使用 veFaaS 函数 ID 与发布 revision;开发态使用后端编译产物指纹,UI/Skill 内容继续独立计入修订。首次升级切换版本来源后,Host 应重新发现。
|
|
56
|
-
|
|
57
|
-
MCP UI 的 `tsconfig.json` 和 `eslint.config.cjs` 由 Agent 随 UI 在 `server/mcp/ui` 中创建,执行命令与完整示例见 coding-steering 的 `mcp-ui-guide`。主工程的 TS/ESLint 排除该浏览器目录,不自动运行 UI 检查;不为无 UI 的应用创建配置或检查命令。
|
|
58
|
-
|
|
59
|
-
`server/mcp/ui` 与 `server/mcp/skills` 变更应由平台判为后端发布;纯前端发布不替换已部署 MCP 产物,也不承诺热更 MCP UI。发布版本号仅在实际后端发布时更新。
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"name": "fullstack-nestjs-template",
|
|
9
9
|
"version": "2.3.0",
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@lark-apaas/fullstack-nestjs-core": "1.1.63
|
|
11
|
+
"@lark-apaas/fullstack-nestjs-core": "^1.1.63",
|
|
12
12
|
"@nestjs/axios": "^4.0.1",
|
|
13
13
|
"@nestjs/cache-manager": "^3.1.3",
|
|
14
14
|
"@nestjs/common": "^10.4.20",
|
|
@@ -32,9 +32,9 @@
|
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@hookform/resolvers": "^5.2.2",
|
|
35
|
-
"@lark-apaas/client-toolkit": "^1.2.
|
|
36
|
-
"@lark-apaas/coding-preset-vite-react": "1.0.24
|
|
37
|
-
"@lark-apaas/fullstack-presets": "1.1.24
|
|
35
|
+
"@lark-apaas/client-toolkit": "^1.2.72",
|
|
36
|
+
"@lark-apaas/coding-preset-vite-react": "^1.0.24",
|
|
37
|
+
"@lark-apaas/fullstack-presets": "^1.1.24",
|
|
38
38
|
"@nestjs/cli": "^10.4.9",
|
|
39
39
|
"@radix-ui/react-accordion": "^1.2.12",
|
|
40
40
|
"@radix-ui/react-alert-dialog": "^1.1.15",
|
|
@@ -1546,9 +1546,9 @@
|
|
|
1546
1546
|
}
|
|
1547
1547
|
},
|
|
1548
1548
|
"node_modules/@lark-apaas/cache-service": {
|
|
1549
|
-
"version": "0.1.2
|
|
1550
|
-
"resolved": "https://registry.npmmirror.com/@lark-apaas/cache-service/-/cache-service-0.1.2
|
|
1551
|
-
"integrity": "sha512-
|
|
1549
|
+
"version": "0.1.2",
|
|
1550
|
+
"resolved": "https://registry.npmmirror.com/@lark-apaas/cache-service/-/cache-service-0.1.2.tgz",
|
|
1551
|
+
"integrity": "sha512-0n24sTo1QyH/8lHs8GUcM/E+zeDau2d5Wqga8QY0A/VbjxctCtmDc8SwN1Zl8mioLNalF3QotnBsNWnOHuOw/A==",
|
|
1552
1552
|
"license": "MIT",
|
|
1553
1553
|
"dependencies": {
|
|
1554
1554
|
"@keyv/redis": "^5.1.6",
|
|
@@ -1562,7 +1562,7 @@
|
|
|
1562
1562
|
},
|
|
1563
1563
|
"peerDependencies": {
|
|
1564
1564
|
"@lark-apaas/nestjs-common": "^0.1.9",
|
|
1565
|
-
"@lark-apaas/nestjs-logger": "1.0.18
|
|
1565
|
+
"@lark-apaas/nestjs-logger": "^1.0.18",
|
|
1566
1566
|
"@lark-apaas/nestjs-observable": "^0.0.12",
|
|
1567
1567
|
"@nestjs/common": "^10.0.0",
|
|
1568
1568
|
"@nestjs/core": "^10.0.0"
|
|
@@ -1579,9 +1579,9 @@
|
|
|
1579
1579
|
}
|
|
1580
1580
|
},
|
|
1581
1581
|
"node_modules/@lark-apaas/client-toolkit": {
|
|
1582
|
-
"version": "1.2.
|
|
1583
|
-
"resolved": "https://registry.npmmirror.com/@lark-apaas/client-toolkit/-/client-toolkit-1.2.
|
|
1584
|
-
"integrity": "sha512
|
|
1582
|
+
"version": "1.2.72",
|
|
1583
|
+
"resolved": "https://registry.npmmirror.com/@lark-apaas/client-toolkit/-/client-toolkit-1.2.72.tgz",
|
|
1584
|
+
"integrity": "sha512-+oBqT1fGLESakZjQJ1MUULxsYkTEH8rBBenu0wG+r+aGm62Upd3RcstAKCkOPOTpohrV4jgiHOifyyU8mk2NFg==",
|
|
1585
1585
|
"dev": true,
|
|
1586
1586
|
"dependencies": {
|
|
1587
1587
|
"@ant-design/colors": "^7.2.1",
|
|
@@ -1589,7 +1589,7 @@
|
|
|
1589
1589
|
"@lark-apaas/aily-web-sdk": "^0.0.12",
|
|
1590
1590
|
"@lark-apaas/auth-sdk": "^0.1.5",
|
|
1591
1591
|
"@lark-apaas/client-capability": "^0.1.7",
|
|
1592
|
-
"@lark-apaas/dataloom": "^0.1.
|
|
1592
|
+
"@lark-apaas/dataloom": "^0.1.5",
|
|
1593
1593
|
"@lark-apaas/internal-slardar": "^0.0.3",
|
|
1594
1594
|
"@lark-apaas/miaoda-inspector": "^1.0.24",
|
|
1595
1595
|
"@lark-apaas/observable-web": "^1.0.6",
|
|
@@ -1634,9 +1634,9 @@
|
|
|
1634
1634
|
"license": "MIT"
|
|
1635
1635
|
},
|
|
1636
1636
|
"node_modules/@lark-apaas/coding-preset-vite-react": {
|
|
1637
|
-
"version": "1.0.24
|
|
1638
|
-
"resolved": "https://registry.npmmirror.com/@lark-apaas/coding-preset-vite-react/-/coding-preset-vite-react-1.0.24
|
|
1639
|
-
"integrity": "sha512-
|
|
1637
|
+
"version": "1.0.24",
|
|
1638
|
+
"resolved": "https://registry.npmmirror.com/@lark-apaas/coding-preset-vite-react/-/coding-preset-vite-react-1.0.24.tgz",
|
|
1639
|
+
"integrity": "sha512-GLha4NQ4yHYY6oRUYA0j4PryGrBjMGS5pN44+VVXSJgwbq7x9T4pFWyBQYIf+FmeYQBNbTIqg19oT7hr/CJ8OA==",
|
|
1640
1640
|
"dev": true,
|
|
1641
1641
|
"license": "MIT",
|
|
1642
1642
|
"dependencies": {
|
|
@@ -1679,9 +1679,9 @@
|
|
|
1679
1679
|
}
|
|
1680
1680
|
},
|
|
1681
1681
|
"node_modules/@lark-apaas/dataloom": {
|
|
1682
|
-
"version": "0.1.
|
|
1683
|
-
"resolved": "https://registry.npmmirror.com/@lark-apaas/dataloom/-/dataloom-0.1.
|
|
1684
|
-
"integrity": "sha512-
|
|
1682
|
+
"version": "0.1.5",
|
|
1683
|
+
"resolved": "https://registry.npmmirror.com/@lark-apaas/dataloom/-/dataloom-0.1.5.tgz",
|
|
1684
|
+
"integrity": "sha512-pcVZeO7QtxjzcV1SXQtUSPHO88/f1rhc3Dp/ubXVHV92W+T65Z9Adlyh3f+OdGGMhhn2+hIUnYLsLyS9gS1vhA==",
|
|
1685
1685
|
"dev": true,
|
|
1686
1686
|
"dependencies": {
|
|
1687
1687
|
"@lark-apaas/internal-slardar": "^0.0.3"
|
|
@@ -1697,12 +1697,12 @@
|
|
|
1697
1697
|
}
|
|
1698
1698
|
},
|
|
1699
1699
|
"node_modules/@lark-apaas/fullstack-nestjs-core": {
|
|
1700
|
-
"version": "1.1.63
|
|
1701
|
-
"resolved": "https://registry.npmmirror.com/@lark-apaas/fullstack-nestjs-core/-/fullstack-nestjs-core-1.1.63
|
|
1702
|
-
"integrity": "sha512-
|
|
1700
|
+
"version": "1.1.63",
|
|
1701
|
+
"resolved": "https://registry.npmmirror.com/@lark-apaas/fullstack-nestjs-core/-/fullstack-nestjs-core-1.1.63.tgz",
|
|
1702
|
+
"integrity": "sha512-ymtOIAkqGzmGv2mcllHdthgCggJSKpY9slKYA4TMtpB/im9QJTnOeTZ1cgtKw0SJTL9Pqb3GJEGjlSqQk3/s9A==",
|
|
1703
1703
|
"license": "MIT",
|
|
1704
1704
|
"dependencies": {
|
|
1705
|
-
"@lark-apaas/cache-service": "0.1.2
|
|
1705
|
+
"@lark-apaas/cache-service": "^0.1.2",
|
|
1706
1706
|
"@lark-apaas/file-service": "^0.1.2",
|
|
1707
1707
|
"@lark-apaas/http-client": "^0.1.7",
|
|
1708
1708
|
"@lark-apaas/nestjs-authnpaas": "^1.0.6",
|
|
@@ -1711,8 +1711,8 @@
|
|
|
1711
1711
|
"@lark-apaas/nestjs-common": "^0.1.9",
|
|
1712
1712
|
"@lark-apaas/nestjs-datapaas": "^1.0.21",
|
|
1713
1713
|
"@lark-apaas/nestjs-http-forwarder": "^0.1.3",
|
|
1714
|
-
"@lark-apaas/nestjs-logger": "1.0.18
|
|
1715
|
-
"@lark-apaas/nestjs-mcp": "0.1.1
|
|
1714
|
+
"@lark-apaas/nestjs-logger": "^1.0.18",
|
|
1715
|
+
"@lark-apaas/nestjs-mcp": "^0.1.1",
|
|
1716
1716
|
"@lark-apaas/nestjs-observable": "^0.0.12",
|
|
1717
1717
|
"@lark-apaas/nestjs-openapi-devtools": "^1.0.10",
|
|
1718
1718
|
"@lark-apaas/nestjs-trigger": "^0.0.3",
|
|
@@ -1735,9 +1735,9 @@
|
|
|
1735
1735
|
}
|
|
1736
1736
|
},
|
|
1737
1737
|
"node_modules/@lark-apaas/fullstack-presets": {
|
|
1738
|
-
"version": "1.1.24
|
|
1739
|
-
"resolved": "https://registry.npmmirror.com/@lark-apaas/fullstack-presets/-/fullstack-presets-1.1.24
|
|
1740
|
-
"integrity": "sha512-
|
|
1738
|
+
"version": "1.1.24",
|
|
1739
|
+
"resolved": "https://registry.npmmirror.com/@lark-apaas/fullstack-presets/-/fullstack-presets-1.1.24.tgz",
|
|
1740
|
+
"integrity": "sha512-Iq1Xsv65qAI555d7eJ+0PcuVUgmNnAjjBDNuHOmocFpqeXfpbNqgVN7cE6mZchjsSRtML762QFQLKxw9NyMsxw==",
|
|
1741
1741
|
"dev": true,
|
|
1742
1742
|
"license": "MIT",
|
|
1743
1743
|
"dependencies": {
|
|
@@ -1926,9 +1926,9 @@
|
|
|
1926
1926
|
}
|
|
1927
1927
|
},
|
|
1928
1928
|
"node_modules/@lark-apaas/nestjs-logger": {
|
|
1929
|
-
"version": "1.0.18
|
|
1930
|
-
"resolved": "https://registry.npmmirror.com/@lark-apaas/nestjs-logger/-/nestjs-logger-1.0.18
|
|
1931
|
-
"integrity": "sha512-
|
|
1929
|
+
"version": "1.0.18",
|
|
1930
|
+
"resolved": "https://registry.npmmirror.com/@lark-apaas/nestjs-logger/-/nestjs-logger-1.0.18.tgz",
|
|
1931
|
+
"integrity": "sha512-RjucJd+TmACoNfTFw20/ppAT3gaztm3qZagPDHEZabiZxg8UpF1twbmN/VLXTF/fgpyoRFS09CMxa7nfFnrT2A==",
|
|
1932
1932
|
"license": "MIT",
|
|
1933
1933
|
"dependencies": {
|
|
1934
1934
|
"@lark-apaas/nestjs-common": "^0.1.9",
|
|
@@ -1945,9 +1945,9 @@
|
|
|
1945
1945
|
}
|
|
1946
1946
|
},
|
|
1947
1947
|
"node_modules/@lark-apaas/nestjs-mcp": {
|
|
1948
|
-
"version": "0.1.1
|
|
1949
|
-
"resolved": "https://registry.npmmirror.com/@lark-apaas/nestjs-mcp/-/nestjs-mcp-0.1.1
|
|
1950
|
-
"integrity": "sha512-
|
|
1948
|
+
"version": "0.1.1",
|
|
1949
|
+
"resolved": "https://registry.npmmirror.com/@lark-apaas/nestjs-mcp/-/nestjs-mcp-0.1.1.tgz",
|
|
1950
|
+
"integrity": "sha512-l6b3Yn6yqSxf/mpTG4bF/FFZAZyXiK7G0vVF0V8GAXtaaToRu6tQ2KlWm6JF8M7S0RB+LAeUYjNd//Zs3WeIVw==",
|
|
1951
1951
|
"license": "MIT",
|
|
1952
1952
|
"dependencies": {
|
|
1953
1953
|
"@modelcontextprotocol/ext-apps": "^1.7.5",
|
package/template/package.json
CHANGED
|
@@ -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.63
|
|
31
|
+
"@lark-apaas/fullstack-nestjs-core": "^1.1.63",
|
|
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.
|
|
56
|
-
"@lark-apaas/coding-preset-vite-react": "1.0.24
|
|
57
|
-
"@lark-apaas/fullstack-presets": "1.1.24
|
|
55
|
+
"@lark-apaas/client-toolkit": "^1.2.72",
|
|
56
|
+
"@lark-apaas/coding-preset-vite-react": "^1.0.24",
|
|
57
|
+
"@lark-apaas/fullstack-presets": "^1.1.24",
|
|
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
|
-
|
|
6
|
+
OUT_DIR="$ROOT_DIR/dist/server"
|
|
7
7
|
|
|
8
8
|
# 记录总开始时间
|
|
9
9
|
TOTAL_START=$(node -e "console.log(Date.now())")
|
|
@@ -19,174 +19,94 @@ print_time() {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
# ==================== 步骤 0 ====================
|
|
22
|
-
echo "🗑️ [0/
|
|
22
|
+
echo "🗑️ [0/5] 安装插件"
|
|
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/
|
|
29
|
+
echo "📝 [1/5] 更新 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/
|
|
36
|
+
echo "🗑️ [2/5] 清理 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 "
|
|
43
|
+
echo "🔨 [3/5] 并行构建 server 和 client"
|
|
44
44
|
STEP_START=$(node -e "console.log(Date.now())")
|
|
45
45
|
|
|
46
|
-
#
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
API_ROUTES_PID=$!
|
|
46
|
+
# 并行构建
|
|
47
|
+
echo " ├─ 启动 server 构建..."
|
|
48
|
+
npm run build:server > /tmp/build-server.log 2>&1 &
|
|
49
|
+
SERVER_PID=$!
|
|
51
50
|
|
|
52
|
-
echo " ├─
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
echo " ├─ 启动 client 构建..."
|
|
52
|
+
npm run build:client > /tmp/build-client.log 2>&1 &
|
|
53
|
+
CLIENT_PID=$!
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
# 等待两个构建完成
|
|
56
|
+
SERVER_EXIT=0
|
|
57
|
+
CLIENT_EXIT=0
|
|
58
58
|
|
|
59
|
-
wait $
|
|
60
|
-
wait $
|
|
59
|
+
wait $SERVER_PID || SERVER_EXIT=$?
|
|
60
|
+
wait $CLIENT_PID || CLIENT_EXIT=$?
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
# 检查构建结果
|
|
63
|
+
if [ $SERVER_EXIT -ne 0 ]; then
|
|
64
|
+
echo " ❌ Server 构建失败"
|
|
65
|
+
cat /tmp/build-server.log
|
|
66
|
+
exit 1
|
|
67
67
|
fi
|
|
68
68
|
|
|
69
|
-
if [ $
|
|
70
|
-
echo "
|
|
71
|
-
cat /tmp/
|
|
72
|
-
|
|
73
|
-
echo " ✅ 页面路由生成完成"
|
|
69
|
+
if [ $CLIENT_EXIT -ne 0 ]; then
|
|
70
|
+
echo " ❌ Client 构建失败"
|
|
71
|
+
cat /tmp/build-client.log
|
|
72
|
+
exit 1
|
|
74
73
|
fi
|
|
74
|
+
|
|
75
|
+
echo " ✅ Server 构建完成"
|
|
76
|
+
echo " ✅ Client 构建完成"
|
|
75
77
|
print_time $STEP_START
|
|
76
78
|
echo ""
|
|
77
79
|
|
|
78
80
|
# ==================== 步骤 4 ====================
|
|
79
|
-
echo "
|
|
81
|
+
echo "📦 [4/5] 准备 server 依赖产物"
|
|
80
82
|
STEP_START=$(node -e "console.log(Date.now())")
|
|
81
83
|
|
|
82
|
-
|
|
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 构建完成"
|
|
136
|
-
fi
|
|
137
|
-
|
|
138
|
-
print_time $STEP_START
|
|
139
|
-
echo ""
|
|
140
|
-
|
|
141
|
-
# ==================== 步骤 5 ====================
|
|
142
|
-
echo "📦 [5/6] 准备产物"
|
|
143
|
-
STEP_START=$(node -e "console.log(Date.now())")
|
|
84
|
+
mkdir -p "$OUT_DIR/dist/client"
|
|
144
85
|
|
|
145
|
-
#
|
|
146
|
-
|
|
147
|
-
|
|
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/" \;
|
|
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/"
|
|
155
89
|
fi
|
|
156
90
|
|
|
157
|
-
#
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
|
91
|
+
# 构建产物 HTML 随后拷,覆盖 public 里的同名文件(保证入口页是构建版,不被 public 静默覆盖)
|
|
92
|
+
cp "$ROOT_DIR/dist/client/"*.html "$OUT_DIR/dist/client/" || true
|
|
93
|
+
|
|
94
|
+
# 拷贝 run.sh 文件
|
|
95
|
+
cp "$ROOT_DIR/scripts/run.sh" "$OUT_DIR/"
|
|
169
96
|
|
|
170
97
|
# 清理无用文件
|
|
171
|
-
rm -rf "$
|
|
172
|
-
rm -rf "$
|
|
98
|
+
rm -rf "$ROOT_DIR/dist/scripts"
|
|
99
|
+
rm -rf "$ROOT_DIR/dist/tsconfig.node.tsbuildinfo"
|
|
173
100
|
|
|
174
101
|
print_time $STEP_START
|
|
175
102
|
echo ""
|
|
176
103
|
|
|
177
|
-
# ==================== 步骤
|
|
178
|
-
echo "✂️ [
|
|
104
|
+
# ==================== 步骤 5 ====================
|
|
105
|
+
echo "✂️ [5/5] 智能依赖裁剪"
|
|
179
106
|
STEP_START=$(node -e "console.log(Date.now())")
|
|
180
107
|
|
|
181
|
-
#
|
|
182
|
-
|
|
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
|
|
108
|
+
# 分析实际依赖、复制并裁剪 node_modules、生成精简的 package.json
|
|
109
|
+
node "$ROOT_DIR/scripts/prune-smart.js"
|
|
190
110
|
|
|
191
111
|
print_time $STEP_START
|
|
192
112
|
echo ""
|
|
@@ -196,17 +116,10 @@ echo "构建完成"
|
|
|
196
116
|
print_time $TOTAL_START
|
|
197
117
|
|
|
198
118
|
# 输出产物信息
|
|
199
|
-
DIST_SIZE=$(du -sh "$
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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
|
|
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 ""
|
|
@@ -6,53 +6,15 @@ const fs = require('fs');
|
|
|
6
6
|
const path = require('path');
|
|
7
7
|
|
|
8
8
|
const ROOT_DIR = path.resolve(__dirname, '..');
|
|
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');
|
|
9
|
+
const DIST_SERVER_DIR = path.join(ROOT_DIR, 'dist/server');
|
|
18
10
|
const ROOT_PACKAGE_JSON = path.join(ROOT_DIR, 'package.json');
|
|
19
11
|
const ROOT_NODE_MODULES = path.join(ROOT_DIR, 'node_modules');
|
|
20
|
-
const OUT_NODE_MODULES = path.join(
|
|
21
|
-
const OUT_PACKAGE_JSON = path.join(
|
|
12
|
+
const OUT_NODE_MODULES = path.join(DIST_SERVER_DIR, 'node_modules');
|
|
13
|
+
const OUT_PACKAGE_JSON = path.join(DIST_SERVER_DIR, 'package.json');
|
|
22
14
|
|
|
23
15
|
// Server 入口文件
|
|
24
16
|
const SERVER_ENTRY = path.join(DIST_SERVER_DIR, 'main.js');
|
|
25
17
|
|
|
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
|
-
|
|
56
18
|
// Node.js 内置模块列表
|
|
57
19
|
const BUILTIN_MODULES = new Set([
|
|
58
20
|
'assert', 'buffer', 'child_process', 'cluster', 'crypto', 'dgram', 'dns',
|
|
@@ -182,15 +144,12 @@ async function smartPrune() {
|
|
|
182
144
|
}
|
|
183
145
|
|
|
184
146
|
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
|
-
}
|
|
188
147
|
|
|
189
148
|
// 2. 使用 @vercel/nft 追踪依赖
|
|
190
149
|
console.log('🔎 追踪实际依赖...');
|
|
191
150
|
const analyzeStart = Date.now();
|
|
192
151
|
|
|
193
|
-
const { fileList } = await nodeFileTrace([SERVER_ENTRY
|
|
152
|
+
const { fileList } = await nodeFileTrace([SERVER_ENTRY], {
|
|
194
153
|
base: ROOT_DIR,
|
|
195
154
|
processCwd: ROOT_DIR,
|
|
196
155
|
ts: false, // 禁用 TS 解析
|
|
@@ -221,59 +180,8 @@ async function smartPrune() {
|
|
|
221
180
|
|
|
222
181
|
console.log(`📦 静态分析需要 ${requiredPackages.size} 个 npm 包`);
|
|
223
182
|
|
|
224
|
-
// 4.
|
|
225
|
-
// 某些包(如 pdf-parse)使用 try-catch 动态加载依赖(如 @napi-rs/canvas),
|
|
226
|
-
// @vercel/nft 无法追踪这类依赖,需要基于 package.json 声明补充
|
|
227
|
-
// 策略:只对 nft 已追踪到的包递归,避免收集无关依赖
|
|
183
|
+
// 4. 处理 actionPlugins(动态加载的插件,无法被静态分析追踪)
|
|
228
184
|
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(动态加载的插件,无法被静态分析追踪)
|
|
277
185
|
const actionPlugins = originalPackage.actionPlugins || {};
|
|
278
186
|
const actionPluginNames = Object.keys(actionPlugins);
|
|
279
187
|
|
|
@@ -304,7 +212,7 @@ async function smartPrune() {
|
|
|
304
212
|
|
|
305
213
|
console.log(`📦 总共需要 ${requiredPackages.size} 个 npm 包\n`);
|
|
306
214
|
|
|
307
|
-
//
|
|
215
|
+
// 5. 选择性复制包(只复制需要的)
|
|
308
216
|
console.log('📋 选择性复制 node_modules(仅复制需要的包)...');
|
|
309
217
|
const copyStart = Date.now();
|
|
310
218
|
|
|
@@ -316,7 +224,7 @@ async function smartPrune() {
|
|
|
316
224
|
console.log(` 成功: ${copiedCount.success} 个包,失败: ${copiedCount.failed} 个`);
|
|
317
225
|
console.log(` 硬链接: ${fileStats.hardLinks} 个文件,复制: ${fileStats.copies} 个文件\n`);
|
|
318
226
|
|
|
319
|
-
//
|
|
227
|
+
// 6. 生成精简版 package.json
|
|
320
228
|
// 优化:直接构建 dependencies,避免多次对象展开
|
|
321
229
|
const prunedDependencies = {};
|
|
322
230
|
const allDeps = originalPackage.dependencies || {};
|
|
@@ -335,6 +243,9 @@ async function smartPrune() {
|
|
|
335
243
|
version: originalPackage.version,
|
|
336
244
|
private: true,
|
|
337
245
|
dependencies: prunedDependencies,
|
|
246
|
+
scripts: {
|
|
247
|
+
start: originalPackage.scripts?.start || 'node main.js'
|
|
248
|
+
},
|
|
338
249
|
engines: originalPackage.engines
|
|
339
250
|
};
|
|
340
251
|
|
|
@@ -342,7 +253,7 @@ async function smartPrune() {
|
|
|
342
253
|
|
|
343
254
|
const totalElapsed = Date.now() - totalStartTime;
|
|
344
255
|
|
|
345
|
-
//
|
|
256
|
+
// 7. 输出统计信息
|
|
346
257
|
console.log('='.repeat(60));
|
|
347
258
|
console.log('📊 智能裁剪统计:');
|
|
348
259
|
console.log('='.repeat(60));
|
package/template/scripts/run.sh
CHANGED
|
@@ -13,6 +13,5 @@
|
|
|
13
13
|
"excludeDirectories": ["node_modules/**"]
|
|
14
14
|
},
|
|
15
15
|
"include": ["server/**/*", "shared/**/*.ts"],
|
|
16
|
-
|
|
17
|
-
"exclude": ["server/mcp/ui", "node_modules", "dist", "client", "source_package", "**/*.spec.ts", "**/*.e2e-spec.ts"],
|
|
16
|
+
"exclude": ["node_modules", "dist", "client", "source_package", "**/*.spec.ts", "**/*.e2e-spec.ts"],
|
|
18
17
|
}
|