@lark-apaas/miaoda-cli 0.1.37 → 0.1.39-alpha.76f8fd5
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/cli/commands/deploy/modern.js +31 -11
- package/dist/cli/handlers/deploy/modern.js +32 -3
- package/dist/config/sync-configs/index.js +3 -1
- package/dist/config/sync-configs/vite-react.js +20 -0
- package/dist/services/deploy/modern/atoms/local-release.js +2 -0
- package/dist/services/deploy/modern/patch/actions.js +7 -1
- package/dist/services/deploy/modern/patch/index.js +2 -1
- package/dist/services/deploy/modern/pipelines/design-local.js +6 -1
- package/dist/services/deploy/modern/pipelines/local.js +6 -1
- package/dist/utils/http.js +2 -2
- package/package.json +1 -1
- package/upgrade/templates/nestjs-react-fullstack/templates/nest-cli.json +1 -10
- package/upgrade/templates/nestjs-react-fullstack/templates/scripts/build.sh +5 -0
- package/upgrade/templates/vite-react/templates/scripts/build.sh +61 -0
|
@@ -18,7 +18,14 @@ function registerDeployCommandsModern(program) {
|
|
|
18
18
|
.option('--dir <path>', '项目目录', '.')
|
|
19
19
|
.option('--skip-build', '跳过 build 步骤(已构建好时使用)', false)
|
|
20
20
|
.option('--skip-release', '不创建/更新本地发布单,发布单状态由外部托管', false)
|
|
21
|
-
.option('--conf <json>', '关联元信息 JSON,仅识别 checkPointVersion / commitID
|
|
21
|
+
.option('--conf <json>', '关联元信息 JSON,仅识别 checkPointVersion / commitID / sessionID / marker 四字段')
|
|
22
|
+
// 这三个 flag 只在父命令声明一份,deploy 与 deploy patch 共用。
|
|
23
|
+
// 不能在 patch 上再声明一遍:commander 遇到父子同名 option 会把值判给父命令,
|
|
24
|
+
// 子命令拿到空数组,`deploy patch --create x` 会静默失效(deploy-patch-wiring 测试可复现)。
|
|
25
|
+
// patch 从 deployCmd.opts() 读,与它今天读 --dir 的方式一致。
|
|
26
|
+
.option('--create <relpath>', '新增文件(可重复)', shared_1.collectRepeatedOption, [])
|
|
27
|
+
.option('--update <relpath>', '修改文件(可重复)', shared_1.collectRepeatedOption, [])
|
|
28
|
+
.option('--delete <relpath>', '删除文件(可重复)', shared_1.collectRepeatedOption, [])
|
|
22
29
|
.addHelpText('after', `
|
|
23
30
|
不要用异步模式或后台模式调用 deploy,否则调用可能提前结束,Agent 会误判发布已完成。
|
|
24
31
|
|
|
@@ -41,14 +48,24 @@ function registerDeployCommandsModern(program) {
|
|
|
41
48
|
外部据 stdout 返回的 version / preReleaseID 自行建单,并据本命令的
|
|
42
49
|
退出码决定把发布单翻成 Finished 还是 Failed —— 失败态由外部负责,CLI 不再兜底。
|
|
43
50
|
该模式下 releaseID / url 输出为 null(CLI 未建单,无从得知)。
|
|
44
|
-
注意:--conf
|
|
51
|
+
注意:--conf 的四个字段唯一消费者是 createLocalRelease,
|
|
45
52
|
本模式下不生效(静默忽略,不报错),需要关联请在外部建单时自行传递。
|
|
46
53
|
|
|
54
|
+
--create / --update / --delete(变更文件清单)
|
|
55
|
+
可重复,值为工程根相对路径(禁绝对路径与 "..")。deploy patch 消费它做增量发布;
|
|
56
|
+
在 deploy 下当前是预留口子——只校验路径并记一行日志,不改变上传行为:
|
|
57
|
+
deploy 仍然全量上传产物,latest 每次被重建为工作区的精确镜像(prune 清理远端多余对象),
|
|
58
|
+
以此保证 git 仓库与 TOS 资源不会不一致。
|
|
59
|
+
后续若实现增量上传,从这里取「要 PUT 哪些文件」即可,调用方无需改动;
|
|
60
|
+
删除仍交给 prune,因为 prune 比对的是完整本地清单,与上传了哪些文件无关。
|
|
61
|
+
|
|
47
62
|
--conf(关联元信息透传)
|
|
48
|
-
值为 JSON string
|
|
63
|
+
值为 JSON string,只识别四个字段,其余 key 忽略:
|
|
49
64
|
checkPointVersion 关联的 checkpoint 版本
|
|
50
65
|
commitID 关联的代码 commit ID
|
|
51
|
-
|
|
66
|
+
sessionID 发起本次发布的页面会话 ID,原样透传不做净化
|
|
67
|
+
marker 本次发布的变更说明,落发布单 description
|
|
68
|
+
四字段均可选;非法 JSON / 非对象 / 字段值非字符串会报错。
|
|
52
69
|
|
|
53
70
|
JSON 输出(stdout)
|
|
54
71
|
{"data": {"appId": "...", "version": <n>, "url": "...", "releaseID": "...", "preReleaseID": "..."}}
|
|
@@ -60,6 +77,8 @@ JSON 输出(stdout)
|
|
|
60
77
|
$ miaoda deploy --skip-build
|
|
61
78
|
$ miaoda deploy --skip-release
|
|
62
79
|
$ miaoda deploy --conf '{"checkPointVersion":"v3","commitID":"a1b2c3d"}'
|
|
80
|
+
$ miaoda deploy --conf '{"commitID":"a1b2c3d","sessionID":"<uuid>","marker":"编辑保存:修改 index.html"}'
|
|
81
|
+
$ miaoda deploy --update index.html --create assets/new.js --delete old.html
|
|
63
82
|
`);
|
|
64
83
|
deployCmd.action((0, shared_1.withHelp)(deployCmd, async (rawOpts) => {
|
|
65
84
|
await (0, modern_1.handleDeployModern)({
|
|
@@ -68,17 +87,18 @@ JSON 输出(stdout)
|
|
|
68
87
|
skipBuild: rawOpts.skipBuild,
|
|
69
88
|
skipRelease: rawOpts.skipRelease,
|
|
70
89
|
conf: rawOpts.conf,
|
|
90
|
+
creates: rawOpts.create,
|
|
91
|
+
updates: rawOpts.update,
|
|
92
|
+
deletes: rawOpts.delete,
|
|
71
93
|
});
|
|
72
94
|
}));
|
|
73
95
|
const patchCmd = deployCmd
|
|
74
96
|
.command('patch')
|
|
75
97
|
.description('design-html 增量发布:按文件 create/update/delete,.html 变动时同步 routes.json')
|
|
76
|
-
.option('--create <relpath>', '新增文件(可重复)', shared_1.collectRepeatedOption, [])
|
|
77
|
-
.option('--update <relpath>', '覆盖已有文件(可重复)', shared_1.collectRepeatedOption, [])
|
|
78
|
-
.option('--delete <relpath>', '删除文件(可重复)', shared_1.collectRepeatedOption, [])
|
|
79
98
|
.option('--session-id <id>', '会话 ID,发布时透传给下游(可选)')
|
|
80
99
|
.addHelpText('after', `
|
|
81
|
-
--dir
|
|
100
|
+
--dir / --create / --update / --delete 声明在父命令 deploy 上,本命令共用,用法不变。
|
|
101
|
+
--dir 为项目目录,默认当前目录。
|
|
82
102
|
仅支持 design-html(design_local_deploy)。路径为工程根相对路径(= 服务端 latest 下 key),
|
|
83
103
|
禁绝对路径与 ".."。--create/--update 的本地文件必须存在。改动里含任意 .html(增 / 改 / 删)
|
|
84
104
|
时自动重算并随包更新 routes.json;纯非 .html 改动不动 routes.json。
|
|
@@ -98,9 +118,9 @@ JSON 输出
|
|
|
98
118
|
await (0, index_1.handleDeployPatch)({
|
|
99
119
|
appId: (0, shared_1.resolveAppId)({}),
|
|
100
120
|
dir: deployCmd.opts().dir ?? '.',
|
|
101
|
-
creates:
|
|
102
|
-
updates:
|
|
103
|
-
deletes:
|
|
121
|
+
creates: deployCmd.opts().create,
|
|
122
|
+
updates: deployCmd.opts().update,
|
|
123
|
+
deletes: deployCmd.opts().delete,
|
|
104
124
|
sessionID: rawOpts.sessionId,
|
|
105
125
|
});
|
|
106
126
|
}));
|
|
@@ -4,14 +4,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.parseDeployConf = parseDeployConf;
|
|
7
|
+
exports.parseChangedFiles = parseChangedFiles;
|
|
7
8
|
exports.handleDeployModern = handleDeployModern;
|
|
8
9
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
10
|
const output_1 = require("../../../utils/output");
|
|
10
11
|
const error_1 = require("../../../utils/error");
|
|
11
12
|
const index_1 = require("../../../services/deploy/modern/index");
|
|
12
|
-
const
|
|
13
|
+
const index_2 = require("../../../services/deploy/modern/patch/index");
|
|
14
|
+
const logger_1 = require("../../../utils/logger");
|
|
15
|
+
const CONF_EXPECTED = '期望形如 {"checkPointVersion":"...","commitID":"...","sessionID":"...","marker":"..."} 的 JSON 对象';
|
|
13
16
|
/**
|
|
14
|
-
* 解析 `--conf` JSON string,只取 checkPointVersion / commitID
|
|
17
|
+
* 解析 `--conf` JSON string,只取 checkPointVersion / commitID / sessionID / marker 四个白名单字段。
|
|
15
18
|
* - 未传 → 返回 {}(行为不变)。
|
|
16
19
|
* - 非法 JSON / 非 object / 字段值非 string → 抛 DEPLOY_CONF_INVALID。
|
|
17
20
|
* - 空串字段视为未提供(不进 body,保持可选语义);未知 key 忽略。
|
|
@@ -31,7 +34,7 @@ function parseDeployConf(raw) {
|
|
|
31
34
|
}
|
|
32
35
|
const source = parsed;
|
|
33
36
|
const conf = {};
|
|
34
|
-
for (const key of ['checkPointVersion', 'commitID']) {
|
|
37
|
+
for (const key of ['checkPointVersion', 'commitID', 'sessionID', 'marker']) {
|
|
35
38
|
const value = source[key];
|
|
36
39
|
if (value === undefined)
|
|
37
40
|
continue;
|
|
@@ -43,6 +46,29 @@ function parseDeployConf(raw) {
|
|
|
43
46
|
}
|
|
44
47
|
return conf;
|
|
45
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* 解析 `--create` / `--update` / `--delete`,校验路径后组成 PatchChangeSet。
|
|
51
|
+
*
|
|
52
|
+
* 复用 deploy patch 的 normalizeRel(同一套校验:禁绝对路径、禁 ".."、统一为 posix 相对路径),
|
|
53
|
+
* 保证两条链路对「变更文件」的接受范围完全一致,调用方从 patch 迁移不会遇到收紧或放宽。
|
|
54
|
+
*
|
|
55
|
+
* 当前是预留口子:deploy 仍然全量上传,这里只校验并记一行日志,不参与上传决策。
|
|
56
|
+
* 三个参数都没传 → 返回 undefined(与不传时行为完全一致,不产生日志)。
|
|
57
|
+
*/
|
|
58
|
+
function parseChangedFiles(opts) {
|
|
59
|
+
const cs = {
|
|
60
|
+
creates: (opts.creates ?? []).map((rel) => (0, index_2.normalizeRel)(rel)),
|
|
61
|
+
updates: (opts.updates ?? []).map((rel) => (0, index_2.normalizeRel)(rel)),
|
|
62
|
+
deletes: (opts.deletes ?? []).map((rel) => (0, index_2.normalizeRel)(rel)),
|
|
63
|
+
};
|
|
64
|
+
const total = cs.creates.length + cs.updates.length + cs.deletes.length;
|
|
65
|
+
if (total === 0)
|
|
66
|
+
return undefined;
|
|
67
|
+
(0, logger_1.log)('deploy', `收到变更文件提示 ${String(total)} 个(create=${String(cs.creates.length)} ` +
|
|
68
|
+
`update=${String(cs.updates.length)} delete=${String(cs.deletes.length)}):` +
|
|
69
|
+
'当前仍为全量上传,未启用增量');
|
|
70
|
+
return cs;
|
|
71
|
+
}
|
|
46
72
|
/**
|
|
47
73
|
* miaoda deploy(modern scene 专用,CLI 表面对齐 openclaw-cli)
|
|
48
74
|
*
|
|
@@ -58,6 +84,9 @@ async function handleDeployModern(opts) {
|
|
|
58
84
|
skipRelease: opts.skipRelease ?? false,
|
|
59
85
|
checkPointVersion: conf.checkPointVersion,
|
|
60
86
|
commitID: conf.commitID,
|
|
87
|
+
sessionID: conf.sessionID,
|
|
88
|
+
marker: conf.marker,
|
|
89
|
+
changedFiles: parseChangedFiles(opts),
|
|
61
90
|
});
|
|
62
91
|
(0, output_1.emit)({
|
|
63
92
|
data: {
|
|
@@ -23,13 +23,15 @@ const node_fs_1 = __importDefault(require("node:fs"));
|
|
|
23
23
|
const node_path_1 = __importDefault(require("node:path"));
|
|
24
24
|
const nestjs_react_fullstack_1 = __importDefault(require("./nestjs-react-fullstack"));
|
|
25
25
|
const design_stack_1 = __importDefault(require("./design-stack"));
|
|
26
|
+
const vite_react_1 = __importDefault(require("./vite-react"));
|
|
26
27
|
/**
|
|
27
|
-
* 已纳入新 sync 机制的 stack 注册表。未在表里的 stack
|
|
28
|
+
* 已纳入新 sync 机制的 stack 注册表。未在表里的 stack(如 html / design-html)走旧的
|
|
28
29
|
* `upgrade/templates/<stack>/{files,patches}` 机制,由 sync handler 兜底。
|
|
29
30
|
*/
|
|
30
31
|
const STACK_REGISTRY = {
|
|
31
32
|
'nestjs-react-fullstack': nestjs_react_fullstack_1.default,
|
|
32
33
|
'design-stack': design_stack_1.default,
|
|
34
|
+
'vite-react': vite_react_1.default,
|
|
33
35
|
};
|
|
34
36
|
/** 返回该 stack 的 SyncConfig;表里没有时返回 null。 */
|
|
35
37
|
function getSyncConfig(stack) {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* vite-react sync 规则(镜像 fullstack-cli 的 viteReactProfile):只同步 build.sh 一支,
|
|
4
|
+
* 回溯 public/* → dist/output/ 修复。
|
|
5
|
+
* ⚠️ build.sh 源须与 miaoda-coding 模板、fullstack-cli `templates/vite-react/build.sh` 逐字一致。
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.SYNC_CONFIG = void 0;
|
|
9
|
+
exports.SYNC_CONFIG = {
|
|
10
|
+
sync: [
|
|
11
|
+
// 覆盖 scripts/build.sh:回溯 public/* → dist/output/(同源根 /app/<appId>/*)修复
|
|
12
|
+
{
|
|
13
|
+
type: 'file',
|
|
14
|
+
from: 'scripts/build.sh',
|
|
15
|
+
to: 'scripts/build.sh',
|
|
16
|
+
overwrite: true,
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
};
|
|
20
|
+
exports.default = exports.SYNC_CONFIG;
|
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.normalizeRel = normalizeRel;
|
|
6
7
|
exports.buildTosActions = buildTosActions;
|
|
7
8
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
9
|
const node_path_1 = __importDefault(require("node:path"));
|
|
@@ -10,7 +11,12 @@ const error_1 = require("../../../../utils/error");
|
|
|
10
11
|
const index_1 = require("../../../../api/deploy/index");
|
|
11
12
|
const content_1 = require("./content");
|
|
12
13
|
const routes_1 = require("./routes");
|
|
13
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* 校验相对路径:禁绝对路径、禁含 ".." 段;normalize 成 posix 相对。
|
|
16
|
+
*
|
|
17
|
+
* 导出供 `deploy` 的 `--create` / `--update` / `--delete` 复用同一套校验,
|
|
18
|
+
* 让两条链路对「变更文件」的接受范围一致,避免两处实现漂移。
|
|
19
|
+
*/
|
|
14
20
|
function normalizeRel(rel) {
|
|
15
21
|
if (node_path_1.default.isAbsolute(rel) || rel.startsWith('/')) {
|
|
16
22
|
throw new error_1.AppError('ARGS_INVALID', `文件路径不能是绝对路径:${rel}`);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.buildTosActions = void 0;
|
|
3
|
+
exports.normalizeRel = exports.buildTosActions = void 0;
|
|
4
4
|
exports.patchDesignDeploy = patchDesignDeploy;
|
|
5
5
|
const spark_meta_1 = require("../../../../utils/spark-meta");
|
|
6
6
|
const error_1 = require("../../../../utils/error");
|
|
@@ -10,6 +10,7 @@ const template_key_map_1 = require("../template-key-map");
|
|
|
10
10
|
const actions_1 = require("./actions");
|
|
11
11
|
var actions_2 = require("./actions");
|
|
12
12
|
Object.defineProperty(exports, "buildTosActions", { enumerable: true, get: function () { return actions_2.buildTosActions; } });
|
|
13
|
+
Object.defineProperty(exports, "normalizeRel", { enumerable: true, get: function () { return actions_2.normalizeRel; } });
|
|
13
14
|
/**
|
|
14
15
|
* design-html 增量发布:读本地文件组 TosFileAction(改动含 .html 时带重算的
|
|
15
16
|
* routes.json),调后端 applyTosDiff 应用到 latest。scope 限 design_local_deploy。
|
|
@@ -28,7 +28,12 @@ async function designLocalPublishPipeline(opts) {
|
|
|
28
28
|
skipRelease: opts.skipRelease ?? false,
|
|
29
29
|
appId: ctx.appId,
|
|
30
30
|
version: pre.version,
|
|
31
|
-
extra: {
|
|
31
|
+
extra: {
|
|
32
|
+
checkPointVersion: opts.checkPointVersion,
|
|
33
|
+
commitID: opts.commitID,
|
|
34
|
+
sessionID: opts.sessionID,
|
|
35
|
+
marker: opts.marker,
|
|
36
|
+
},
|
|
32
37
|
});
|
|
33
38
|
try {
|
|
34
39
|
await (0, index_1.uploadDesignArtifacts)({ projectDir: ctx.projectDir, data });
|
|
@@ -45,7 +45,12 @@ async function localBuildLocalPublishPipeline(opts) {
|
|
|
45
45
|
skipRelease: opts.skipRelease ?? false,
|
|
46
46
|
appId: ctx.appId,
|
|
47
47
|
version: pre.version,
|
|
48
|
-
extra: {
|
|
48
|
+
extra: {
|
|
49
|
+
checkPointVersion: opts.checkPointVersion,
|
|
50
|
+
commitID: opts.commitID,
|
|
51
|
+
sessionID: opts.sessionID,
|
|
52
|
+
marker: opts.marker,
|
|
53
|
+
},
|
|
49
54
|
});
|
|
50
55
|
try {
|
|
51
56
|
(0, logger_1.log)('deploy', 'Uploading artifacts...');
|
package/dist/utils/http.js
CHANGED
|
@@ -64,13 +64,13 @@ function createClient(opts) {
|
|
|
64
64
|
* 默认灰度泳道。当前 miaoda CLI 接入的新接口(modern deploy 等)只在该泳道生效,
|
|
65
65
|
* 缺省走这个。MIAODA_CANARY_HEADER 可显式覆盖;设为空字符串则去掉头。
|
|
66
66
|
*
|
|
67
|
-
* ⚠️ TEMP(creative-upgrade 联调用):默认泳道临时指向开发泳道
|
|
67
|
+
* ⚠️ TEMP(creative-upgrade 联调用):默认泳道临时指向开发泳道 boe_creative_history,
|
|
68
68
|
* 使 alpha 发版进沙箱镜像后,app export / code-archive 等新接口无需 wrapper 即可命中
|
|
69
69
|
* 尚未合流的 studio_server 改动。
|
|
70
70
|
* 上线前必须还原为 'boe_miaoda_ccm',或改为由 agent_tool 按请求 x-tt-env 注入
|
|
71
71
|
* MIAODA_CANARY_HEADER(详见 http.ts 的 applyCanaryHeader 与 agent_tool ExecShellCmd)。
|
|
72
72
|
*/
|
|
73
|
-
const DEFAULT_CANARY_HEADER = '
|
|
73
|
+
const DEFAULT_CANARY_HEADER = 'boe_creative_history';
|
|
74
74
|
/**
|
|
75
75
|
* 注入 x-tt-env 小流量头:env 显式设值 > DEFAULT_CANARY_HEADER。
|
|
76
76
|
*
|
package/package.json
CHANGED
|
@@ -146,6 +146,11 @@ 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
|
|
|
@@ -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
|