@lark-apaas/fullstack-cli 1.1.63-alpha.20260826101001 → 1.1.63-alpha.20260826101330
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/dist/index.js +105 -14
- package/package.json +1 -1
- package/templates/scripts/build.sh +5 -12
- package/templates/scripts/dev-server.js +139 -0
- package/templates/vite-react/build.sh +61 -0
package/dist/index.js
CHANGED
|
@@ -2514,6 +2514,17 @@ function buildDefaultRules(opts) {
|
|
|
2514
2514
|
command: "node scripts/hooks/run-precommit.js",
|
|
2515
2515
|
overwrite: false
|
|
2516
2516
|
},
|
|
2517
|
+
// 1d. Nest 开发态由平台 launcher 选择 SWC;已有声明保持用户版本/依赖分区。
|
|
2518
|
+
{
|
|
2519
|
+
type: "ensure-dev-dependency",
|
|
2520
|
+
name: "@swc/cli",
|
|
2521
|
+
version: "^0.5.2"
|
|
2522
|
+
},
|
|
2523
|
+
{
|
|
2524
|
+
type: "ensure-dev-dependency",
|
|
2525
|
+
name: "@swc/core",
|
|
2526
|
+
version: "^1.16.1"
|
|
2527
|
+
},
|
|
2517
2528
|
// 2. 智能合并 nest-cli.json 配置(保留用户自定义的 assets、plugins 等)
|
|
2518
2529
|
{
|
|
2519
2530
|
from: "templates/nest-cli.json",
|
|
@@ -2588,6 +2599,19 @@ function buildDefaultRules(opts) {
|
|
|
2588
2599
|
name: "lint",
|
|
2589
2600
|
to: "node ./scripts/lint.js",
|
|
2590
2601
|
ifStartsWith: "concurrently "
|
|
2602
|
+
},
|
|
2603
|
+
// 9a. 只迁移模板生成的精确默认值;用户追加参数或自定义命令保持不动。
|
|
2604
|
+
{
|
|
2605
|
+
type: "patch-script",
|
|
2606
|
+
name: "dev:server",
|
|
2607
|
+
to: "NODE_ENV=development node ./scripts/dev-server.js",
|
|
2608
|
+
ifEquals: "NODE_ENV=development nest start --watch"
|
|
2609
|
+
},
|
|
2610
|
+
{
|
|
2611
|
+
type: "patch-script",
|
|
2612
|
+
name: "dev:server",
|
|
2613
|
+
to: "NODE_ENV=development node ./scripts/dev-server.js",
|
|
2614
|
+
ifEquals: "nest start --watch"
|
|
2591
2615
|
}
|
|
2592
2616
|
];
|
|
2593
2617
|
if (!opts.disableGenOpenapi) {
|
|
@@ -2617,7 +2641,15 @@ function emptyProfile() {
|
|
|
2617
2641
|
}
|
|
2618
2642
|
function viteReactProfile() {
|
|
2619
2643
|
return {
|
|
2620
|
-
sync: [
|
|
2644
|
+
sync: [
|
|
2645
|
+
// 覆盖 scripts/build.sh(回溯 public/* → dist/output/ 的修复)
|
|
2646
|
+
{
|
|
2647
|
+
from: "templates/vite-react/build.sh",
|
|
2648
|
+
to: "scripts/build.sh",
|
|
2649
|
+
type: "file",
|
|
2650
|
+
overwrite: true
|
|
2651
|
+
}
|
|
2652
|
+
],
|
|
2621
2653
|
permissions: {},
|
|
2622
2654
|
activateGitHooks: true
|
|
2623
2655
|
};
|
|
@@ -2759,7 +2791,9 @@ async function run2(options) {
|
|
|
2759
2791
|
}
|
|
2760
2792
|
const stack = resolveStack(userProjectRoot);
|
|
2761
2793
|
try {
|
|
2762
|
-
console.log(
|
|
2794
|
+
console.log(
|
|
2795
|
+
`[fullstack-cli] Starting sync${stack ? ` (stack: ${stack})` : ""}...`
|
|
2796
|
+
);
|
|
2763
2797
|
const config = genSyncConfig(stack, {
|
|
2764
2798
|
disableGenOpenapi: options.disableGenOpenapi ?? false
|
|
2765
2799
|
});
|
|
@@ -2778,7 +2812,9 @@ async function run2(options) {
|
|
|
2778
2812
|
activateGitHooks(userProjectRoot);
|
|
2779
2813
|
} catch (error) {
|
|
2780
2814
|
const message = error instanceof Error ? error.message : String(error);
|
|
2781
|
-
console.warn(
|
|
2815
|
+
console.warn(
|
|
2816
|
+
`[fullstack-cli] \u26A0 Failed to activate git hooks: ${message}`
|
|
2817
|
+
);
|
|
2782
2818
|
}
|
|
2783
2819
|
}
|
|
2784
2820
|
console.log("[fullstack-cli] Sync completed successfully \u2705");
|
|
@@ -2798,7 +2834,9 @@ function resolveStack(userProjectRoot) {
|
|
|
2798
2834
|
return typeof meta.stack === "string" ? meta.stack : void 0;
|
|
2799
2835
|
} catch (error) {
|
|
2800
2836
|
const message = error instanceof Error ? error.message : String(error);
|
|
2801
|
-
console.warn(
|
|
2837
|
+
console.warn(
|
|
2838
|
+
`[fullstack-cli] \u26A0 Failed to read .spark/meta.json, fallback to default sync: ${message}`
|
|
2839
|
+
);
|
|
2802
2840
|
return void 0;
|
|
2803
2841
|
}
|
|
2804
2842
|
}
|
|
@@ -2819,12 +2857,22 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
|
|
|
2819
2857
|
}
|
|
2820
2858
|
if (rule.type === "add-script") {
|
|
2821
2859
|
const packageJsonPath = path5.join(userProjectRoot, "package.json");
|
|
2822
|
-
addScript(
|
|
2860
|
+
addScript(
|
|
2861
|
+
packageJsonPath,
|
|
2862
|
+
rule.name,
|
|
2863
|
+
rule.command,
|
|
2864
|
+
rule.overwrite ?? false
|
|
2865
|
+
);
|
|
2866
|
+
return;
|
|
2867
|
+
}
|
|
2868
|
+
if (rule.type === "ensure-dev-dependency") {
|
|
2869
|
+
const packageJsonPath = path5.join(userProjectRoot, "package.json");
|
|
2870
|
+
ensureDevDependency(packageJsonPath, rule.name, rule.version);
|
|
2823
2871
|
return;
|
|
2824
2872
|
}
|
|
2825
2873
|
if (rule.type === "patch-script") {
|
|
2826
2874
|
const packageJsonPath = path5.join(userProjectRoot, "package.json");
|
|
2827
|
-
patchScript(packageJsonPath, rule
|
|
2875
|
+
patchScript(packageJsonPath, rule);
|
|
2828
2876
|
return;
|
|
2829
2877
|
}
|
|
2830
2878
|
if (rule.type === "add-line") {
|
|
@@ -2852,7 +2900,12 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
|
|
|
2852
2900
|
syncDirectory(srcPath, destPath, rule.overwrite ?? true);
|
|
2853
2901
|
break;
|
|
2854
2902
|
case "file":
|
|
2855
|
-
syncFile(
|
|
2903
|
+
syncFile(
|
|
2904
|
+
srcPath,
|
|
2905
|
+
destPath,
|
|
2906
|
+
rule.overwrite ?? true,
|
|
2907
|
+
rule.onlyIfExists ?? false
|
|
2908
|
+
);
|
|
2856
2909
|
break;
|
|
2857
2910
|
case "append":
|
|
2858
2911
|
appendToFile(srcPath, destPath);
|
|
@@ -2861,7 +2914,9 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
|
|
|
2861
2914
|
}
|
|
2862
2915
|
function syncFile(src, dest, overwrite = true, onlyIfExists = false) {
|
|
2863
2916
|
if (onlyIfExists && !fs7.existsSync(dest)) {
|
|
2864
|
-
console.log(
|
|
2917
|
+
console.log(
|
|
2918
|
+
`[fullstack-cli] \u25CB ${path5.basename(dest)} (skipped, target not exists)`
|
|
2919
|
+
);
|
|
2865
2920
|
return;
|
|
2866
2921
|
}
|
|
2867
2922
|
const destDir = path5.dirname(dest);
|
|
@@ -2869,7 +2924,9 @@ function syncFile(src, dest, overwrite = true, onlyIfExists = false) {
|
|
|
2869
2924
|
fs7.mkdirSync(destDir, { recursive: true });
|
|
2870
2925
|
}
|
|
2871
2926
|
if (fs7.existsSync(dest) && !overwrite) {
|
|
2872
|
-
console.log(
|
|
2927
|
+
console.log(
|
|
2928
|
+
`[fullstack-cli] \u25CB ${path5.basename(dest)} (skipped, already exists)`
|
|
2929
|
+
);
|
|
2873
2930
|
return;
|
|
2874
2931
|
}
|
|
2875
2932
|
fs7.copyFileSync(src, dest);
|
|
@@ -2896,7 +2953,9 @@ function syncDirectory(src, dest, overwrite = true) {
|
|
|
2896
2953
|
}
|
|
2897
2954
|
});
|
|
2898
2955
|
if (count > 0) {
|
|
2899
|
-
console.log(
|
|
2956
|
+
console.log(
|
|
2957
|
+
`[fullstack-cli] Synced ${count} files to ${path5.basename(dest)}/`
|
|
2958
|
+
);
|
|
2900
2959
|
}
|
|
2901
2960
|
}
|
|
2902
2961
|
function appendToFile(src, dest) {
|
|
@@ -2906,7 +2965,9 @@ function appendToFile(src, dest) {
|
|
|
2906
2965
|
existingContent = fs7.readFileSync(dest, "utf-8");
|
|
2907
2966
|
}
|
|
2908
2967
|
if (existingContent.includes(content.trim())) {
|
|
2909
|
-
console.log(
|
|
2968
|
+
console.log(
|
|
2969
|
+
`[fullstack-cli] \u25CB ${path5.basename(dest)} (already contains content)`
|
|
2970
|
+
);
|
|
2910
2971
|
return;
|
|
2911
2972
|
}
|
|
2912
2973
|
fs7.appendFileSync(dest, content);
|
|
@@ -2964,7 +3025,34 @@ function addScript(packageJsonPath, name, command, overwrite) {
|
|
|
2964
3025
|
fs7.writeFileSync(packageJsonPath, JSON.stringify(pkg2, null, 2) + "\n");
|
|
2965
3026
|
console.log(`[fullstack-cli] \u2713 scripts.${name}`);
|
|
2966
3027
|
}
|
|
2967
|
-
function
|
|
3028
|
+
function ensureDevDependency(packageJsonPath, name, version) {
|
|
3029
|
+
if (!fs7.existsSync(packageJsonPath)) {
|
|
3030
|
+
console.log("[fullstack-cli] \u25CB package.json (not found)");
|
|
3031
|
+
return;
|
|
3032
|
+
}
|
|
3033
|
+
try {
|
|
3034
|
+
const content = fs7.readFileSync(packageJsonPath, "utf-8");
|
|
3035
|
+
const pkg2 = JSON.parse(content);
|
|
3036
|
+
const existingVersion = pkg2.dependencies?.[name] ?? pkg2.devDependencies?.[name];
|
|
3037
|
+
if (existingVersion !== void 0) {
|
|
3038
|
+
console.log(
|
|
3039
|
+
`[fullstack-cli] \u25CB ${name} (already declared as ${existingVersion})`
|
|
3040
|
+
);
|
|
3041
|
+
return;
|
|
3042
|
+
}
|
|
3043
|
+
pkg2.devDependencies ?? (pkg2.devDependencies = {});
|
|
3044
|
+
pkg2.devDependencies[name] = version;
|
|
3045
|
+
fs7.writeFileSync(packageJsonPath, JSON.stringify(pkg2, null, 2) + "\n");
|
|
3046
|
+
console.log(`[fullstack-cli] \u2713 devDependencies.${name} = ${version}`);
|
|
3047
|
+
} catch (error) {
|
|
3048
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3049
|
+
console.warn(
|
|
3050
|
+
`[fullstack-cli] \u26A0 Could not ensure dependency ${name}: ${message}`
|
|
3051
|
+
);
|
|
3052
|
+
}
|
|
3053
|
+
}
|
|
3054
|
+
function patchScript(packageJsonPath, rule) {
|
|
3055
|
+
const { name, to } = rule;
|
|
2968
3056
|
if (!fs7.existsSync(packageJsonPath)) {
|
|
2969
3057
|
console.log(`[fullstack-cli] \u25CB package.json (not found)`);
|
|
2970
3058
|
return;
|
|
@@ -2981,7 +3069,8 @@ function patchScript(packageJsonPath, name, to, ifStartsWith) {
|
|
|
2981
3069
|
console.log(`[fullstack-cli] \u25CB scripts.${name} (already patched)`);
|
|
2982
3070
|
return;
|
|
2983
3071
|
}
|
|
2984
|
-
|
|
3072
|
+
const matches = rule.ifEquals !== void 0 ? current === rule.ifEquals : current.startsWith(rule.ifStartsWith);
|
|
3073
|
+
if (!matches) {
|
|
2985
3074
|
console.warn(
|
|
2986
3075
|
`[fullstack-cli] \u26A0 Skipped patching scripts.${name} because it has been customized`
|
|
2987
3076
|
);
|
|
@@ -2992,7 +3081,9 @@ function patchScript(packageJsonPath, name, to, ifStartsWith) {
|
|
|
2992
3081
|
console.log(`[fullstack-cli] \u2713 Patched scripts.${name}`);
|
|
2993
3082
|
} catch (error) {
|
|
2994
3083
|
const message = error instanceof Error ? error.message : String(error);
|
|
2995
|
-
console.warn(
|
|
3084
|
+
console.warn(
|
|
3085
|
+
`[fullstack-cli] \u26A0 Could not patch scripts.${name}: ${message}`
|
|
3086
|
+
);
|
|
2996
3087
|
}
|
|
2997
3088
|
}
|
|
2998
3089
|
function addLineToFile(filePath, line) {
|
package/package.json
CHANGED
|
@@ -146,21 +146,14 @@ STEP_START=$(node -e "console.log(Date.now())")
|
|
|
146
146
|
# 使用 mv 而非 cp:HTML 不能上传到公网 CDN,移走后 dist/client 中不再包含 HTML
|
|
147
147
|
if [ -d "$DIST_DIR/client" ]; then
|
|
148
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 静默覆盖)
|
|
149
154
|
find "$DIST_DIR/client" -maxdepth 1 -name "*.html" -exec mv {} "$DIST_DIR/dist/client/" \;
|
|
150
155
|
fi
|
|
151
156
|
|
|
152
|
-
# 拷贝 shared/static → dist/shared/static
|
|
153
|
-
# Nest server 生产从 process.cwd() + shared/static 读 (nestjs-core static.controller.ts:100),
|
|
154
|
-
# 生产 cwd = dist/, 所以目标是 dist/shared/static。coding-preset 的 static-assets plugin
|
|
155
|
-
# 之前 closeBundle 拷贝, 现在删除后交给 build.sh 显式做 (跟 jsPage 的 output_static rsync 对齐)。
|
|
156
|
-
# 排除 .ts/.tsx/.js/.jsx: 避免 shared/static/ 里若有开发脚本被误传到生产。
|
|
157
|
-
if [ -d "$ROOT_DIR/shared/static" ]; then
|
|
158
|
-
mkdir -p "$DIST_DIR/shared/static"
|
|
159
|
-
rsync -a --exclude='*.ts' --exclude='*.tsx' --exclude='*.js' --exclude='*.jsx' \
|
|
160
|
-
"$ROOT_DIR/shared/static/" "$DIST_DIR/shared/static/"
|
|
161
|
-
echo " Static → dist/shared/static/"
|
|
162
|
-
fi
|
|
163
|
-
|
|
164
157
|
# server 相关产物准备(only_frontend_change=true 时跳过)
|
|
165
158
|
if [[ "${only_frontend_change:-false}" == "true" ]]; then
|
|
166
159
|
echo " [skip] 跳过 run.sh/.env 复制 (only_frontend_change=true)"
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const { spawn } = require('node:child_process');
|
|
6
|
+
|
|
7
|
+
const FORWARDED_SIGNALS = ['SIGINT', 'SIGTERM'];
|
|
8
|
+
|
|
9
|
+
function resolveBuilder(projectRoot) {
|
|
10
|
+
const configPath = path.join(projectRoot, 'nest-cli.json');
|
|
11
|
+
if (!fs.existsSync(configPath)) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
16
|
+
const builder = config?.compilerOptions?.builder;
|
|
17
|
+
if (typeof builder === 'string') {
|
|
18
|
+
return builder;
|
|
19
|
+
}
|
|
20
|
+
if (
|
|
21
|
+
builder &&
|
|
22
|
+
typeof builder === 'object' &&
|
|
23
|
+
typeof builder.type === 'string'
|
|
24
|
+
) {
|
|
25
|
+
return builder.type;
|
|
26
|
+
}
|
|
27
|
+
return builder === undefined ? undefined : 'custom';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function findMissingSwcDependency(projectRoot) {
|
|
31
|
+
for (const dependency of ['@swc/cli', '@swc/core']) {
|
|
32
|
+
try {
|
|
33
|
+
require.resolve(`${dependency}/package.json`, { paths: [projectRoot] });
|
|
34
|
+
} catch {
|
|
35
|
+
return dependency;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function resolveNestEntrypoint(projectRoot) {
|
|
42
|
+
return require.resolve('@nestjs/cli/bin/nest.js', { paths: [projectRoot] });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function startNest(projectRoot, nestArgs) {
|
|
46
|
+
const child = spawn(
|
|
47
|
+
process.execPath,
|
|
48
|
+
[resolveNestEntrypoint(projectRoot), ...nestArgs],
|
|
49
|
+
{
|
|
50
|
+
cwd: projectRoot,
|
|
51
|
+
env: process.env,
|
|
52
|
+
stdio: 'inherit',
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const signalHandlers = new Map();
|
|
57
|
+
for (const signal of FORWARDED_SIGNALS) {
|
|
58
|
+
const handler = () => child.kill(signal);
|
|
59
|
+
signalHandlers.set(signal, handler);
|
|
60
|
+
process.once(signal, handler);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function removeSignalHandlers() {
|
|
64
|
+
for (const [signal, handler] of signalHandlers) {
|
|
65
|
+
process.removeListener(signal, handler);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
child.once('error', error => {
|
|
70
|
+
removeSignalHandlers();
|
|
71
|
+
console.error(
|
|
72
|
+
`[miaoda:nest-compiler] failed to start Nest CLI: ${error.message}`
|
|
73
|
+
);
|
|
74
|
+
process.exitCode = 1;
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
child.once('exit', (code, signal) => {
|
|
78
|
+
removeSignalHandlers();
|
|
79
|
+
if (signal) {
|
|
80
|
+
process.kill(process.pid, signal);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
process.exitCode = code ?? 1;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function main() {
|
|
88
|
+
const projectRoot = process.cwd();
|
|
89
|
+
const forwardedArgs = process.argv.slice(2);
|
|
90
|
+
let explicitBuilder;
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
explicitBuilder = resolveBuilder(projectRoot);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
console.error(
|
|
96
|
+
`[miaoda:nest-compiler] MIAODA_NEST_SWC_FALLBACK reason=invalid_nest_cli_config message=${JSON.stringify(error.message)}`
|
|
97
|
+
);
|
|
98
|
+
console.log('[miaoda:nest-compiler] MIAODA_NEST_COMPILER=tsc');
|
|
99
|
+
startNest(projectRoot, ['start', '--watch', ...forwardedArgs]);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (explicitBuilder && explicitBuilder !== 'swc') {
|
|
104
|
+
console.log(
|
|
105
|
+
`[miaoda:nest-compiler] MIAODA_NEST_COMPILER=${explicitBuilder}`
|
|
106
|
+
);
|
|
107
|
+
startNest(projectRoot, ['start', '--watch', ...forwardedArgs]);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const missingDependency = findMissingSwcDependency(projectRoot);
|
|
112
|
+
if (missingDependency) {
|
|
113
|
+
console.error(
|
|
114
|
+
`[miaoda:nest-compiler] MIAODA_NEST_SWC_FALLBACK reason=missing_dependency dependency=${missingDependency}`
|
|
115
|
+
);
|
|
116
|
+
console.log('[miaoda:nest-compiler] MIAODA_NEST_COMPILER=tsc');
|
|
117
|
+
startNest(projectRoot, ['start', '--watch', ...forwardedArgs]);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
console.log('[miaoda:nest-compiler] MIAODA_NEST_COMPILER=swc');
|
|
122
|
+
startNest(projectRoot, [
|
|
123
|
+
'start',
|
|
124
|
+
'--watch',
|
|
125
|
+
'--builder',
|
|
126
|
+
'swc',
|
|
127
|
+
'--type-check',
|
|
128
|
+
...forwardedArgs,
|
|
129
|
+
]);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (require.main === module) {
|
|
133
|
+
main();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
module.exports = {
|
|
137
|
+
findMissingSwcDependency,
|
|
138
|
+
resolveBuilder,
|
|
139
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
5
|
+
OUTPUT="$ROOT/dist/output"
|
|
6
|
+
OUTPUT_RESOURCE="$ROOT/dist/output_resource"
|
|
7
|
+
OUTPUT_STATIC="$ROOT/dist/output_static"
|
|
8
|
+
|
|
9
|
+
# 映射平台环境变量到 preset 期望的变量名
|
|
10
|
+
# MIAODA_APP_ID → /app/<appId> 作为客户端 base path
|
|
11
|
+
# MIAODA_RESOURCE_CDN_PREFIX → assets (JS/CSS) 的 CDN 前缀
|
|
12
|
+
# CLI 注入约定见 miaoda-cli src/services/deploy/modern/atoms/build.ts
|
|
13
|
+
export CLIENT_BASE_PATH="${MIAODA_APP_ID:+/app/$MIAODA_APP_ID}"
|
|
14
|
+
export ASSETS_CDN_PATH="${MIAODA_RESOURCE_CDN_PREFIX:-/}"
|
|
15
|
+
export STATIC_ASSETS_BASE_URL="${MIAODA_STATIC_CDN_PREFIX}"
|
|
16
|
+
export NODE_ENV="${NODE_ENV:-production}"
|
|
17
|
+
|
|
18
|
+
# 清理
|
|
19
|
+
rm -rf "$ROOT/dist"
|
|
20
|
+
|
|
21
|
+
# 1. Vite 构建 → dist/client/(相对于项目根目录输出)
|
|
22
|
+
npx vite build --outDir "$ROOT/dist/client" --emptyOutDir
|
|
23
|
+
|
|
24
|
+
# 2. public/ 静态资源 + HTML → dist/output/(模型 B:public = 应用根目录,同源 /app/<appId>/*)
|
|
25
|
+
mkdir -p "$OUTPUT"
|
|
26
|
+
# 2a. public/*:vite copyPublicDir 已把 public/* 平铺进 dist/client,但下面白名单只取
|
|
27
|
+
# *.html/routes.json,其余(favicon / 图片 / 运行时 fetch 的数据文件)会随 dist/client 被删。
|
|
28
|
+
# 从源 public/ 补拷到 output/(同源根),让 fetch('/x') / resolveAppUrl('/x') 线上可用。
|
|
29
|
+
# 先拷 public、再拷 HTML,保证构建产出的 index.html/routes.json 覆盖 public 里的同名文件(若有)。
|
|
30
|
+
if [ -d "$ROOT/public" ]; then
|
|
31
|
+
cp -R "$ROOT/public/." "$OUTPUT/"
|
|
32
|
+
fi
|
|
33
|
+
# 2b. HTML + routes.json(构建产物)
|
|
34
|
+
find "$ROOT/dist/client" -maxdepth 1 \( -name '*.html' -o -name 'routes.json' \) -exec cp {} "$OUTPUT/" \;
|
|
35
|
+
|
|
36
|
+
# 3. assets/ → dist/output_resource/(JS/CSS/字体,上传到 CDN)
|
|
37
|
+
if [ -d "$ROOT/dist/client/assets" ]; then
|
|
38
|
+
mkdir -p "$OUTPUT_RESOURCE"
|
|
39
|
+
cp -r "$ROOT/dist/client/assets" "$OUTPUT_RESOURCE/"
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# 4. 私有静态资源 → dist/output_static/(排除代码文件)
|
|
43
|
+
if [ -d "$ROOT/shared/static" ]; then
|
|
44
|
+
mkdir -p "$OUTPUT_STATIC"
|
|
45
|
+
rsync -a --exclude='*.ts' --exclude='*.tsx' --exclude='*.js' --exclude='*.jsx' "$ROOT/shared/static/" "$OUTPUT_STATIC/"
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# 5. capability 配置 → dist/output_capabilities/
|
|
49
|
+
if [ -d "$ROOT/shared/capabilities" ]; then
|
|
50
|
+
mkdir -p "$ROOT/dist/output_capabilities"
|
|
51
|
+
cp -r "$ROOT/shared/capabilities/." "$ROOT/dist/output_capabilities/"
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
# 清理中间产物
|
|
55
|
+
rm -rf "$ROOT/dist/client"
|
|
56
|
+
|
|
57
|
+
echo "Build complete"
|
|
58
|
+
echo " HTML → dist/output/"
|
|
59
|
+
[ -d "$OUTPUT_RESOURCE" ] && echo " Resource → dist/output_resource/" || true
|
|
60
|
+
[ -d "$OUTPUT_STATIC" ] && echo " Static → dist/output_static/" || true
|
|
61
|
+
[ -d "$ROOT/dist/output_capabilities" ] && echo " Capabilities → dist/output_capabilities/" || true
|