@lark-apaas/fullstack-cli 1.1.16-beta.7 → 1.1.16-beta.9
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 +124 -20
- package/package.json +1 -1
- package/templates/scripts/build.sh +15 -14
- package/templates/scripts/prune-smart.js +4 -6
- package/templates/scripts/run.sh +4 -1
package/dist/index.js
CHANGED
|
@@ -1414,14 +1414,15 @@ async function fetchSyncedTables(appId, workspace) {
|
|
|
1414
1414
|
DEFAULT_TIMEOUT_MS2
|
|
1415
1415
|
);
|
|
1416
1416
|
});
|
|
1417
|
+
const dbBranch = process.env.FORCE_DB_BRANCH || "main";
|
|
1417
1418
|
const start = Date.now();
|
|
1418
1419
|
console.log(
|
|
1419
|
-
`[fetchSyncedTables] \u2192 GET listTableView (dbBranch
|
|
1420
|
+
`[fetchSyncedTables] \u2192 GET listTableView (dbBranch=${dbBranch}) appId=${appId ? "set" : "unset"} workspace=${workspace ? "set" : "unset"}`
|
|
1420
1421
|
);
|
|
1421
1422
|
const response = await Promise.race([
|
|
1422
1423
|
client.get(
|
|
1423
1424
|
`/api/v1/dataloom/inner/app/${appId}/workspaces/${workspace}/listTableView`,
|
|
1424
|
-
{ params: { dbBranch
|
|
1425
|
+
{ params: { dbBranch }, headers: { "x-supaas-bizsource": "miaoda" } }
|
|
1425
1426
|
),
|
|
1426
1427
|
timeoutPromise
|
|
1427
1428
|
]);
|
|
@@ -2377,12 +2378,15 @@ var syncConfig = {
|
|
|
2377
2378
|
type: "directory",
|
|
2378
2379
|
overwrite: true
|
|
2379
2380
|
},
|
|
2380
|
-
// 2.
|
|
2381
|
+
// 2. 智能合并 nest-cli.json 配置(保留用户自定义的 assets、plugins 等)
|
|
2381
2382
|
{
|
|
2382
2383
|
from: "templates/nest-cli.json",
|
|
2383
2384
|
to: "nest-cli.json",
|
|
2384
|
-
type: "
|
|
2385
|
-
|
|
2385
|
+
type: "merge-json",
|
|
2386
|
+
arrayMerge: {
|
|
2387
|
+
"compilerOptions.assets": { key: "include" },
|
|
2388
|
+
"compilerOptions.plugins": { key: "name" }
|
|
2389
|
+
}
|
|
2386
2390
|
},
|
|
2387
2391
|
// // 2. 追加内容到 .gitignore
|
|
2388
2392
|
// {
|
|
@@ -2475,6 +2479,52 @@ function removeLineFromFile(filePath, pattern) {
|
|
|
2475
2479
|
return true;
|
|
2476
2480
|
}
|
|
2477
2481
|
|
|
2482
|
+
// src/utils/merge-json.ts
|
|
2483
|
+
function isPlainObject(value) {
|
|
2484
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2485
|
+
}
|
|
2486
|
+
function mergeArrayByKey(userArr, templateArr, key) {
|
|
2487
|
+
const result = [...userArr];
|
|
2488
|
+
for (const templateItem of templateArr) {
|
|
2489
|
+
if (!isPlainObject(templateItem)) continue;
|
|
2490
|
+
const templateKey = templateItem[key];
|
|
2491
|
+
const existingIndex = result.findIndex(
|
|
2492
|
+
(item) => isPlainObject(item) && item[key] === templateKey
|
|
2493
|
+
);
|
|
2494
|
+
if (existingIndex >= 0) {
|
|
2495
|
+
result[existingIndex] = templateItem;
|
|
2496
|
+
} else {
|
|
2497
|
+
result.push(templateItem);
|
|
2498
|
+
}
|
|
2499
|
+
}
|
|
2500
|
+
return result;
|
|
2501
|
+
}
|
|
2502
|
+
function deepMergeJson(user, template, arrayMerge = {}, currentPath = "") {
|
|
2503
|
+
const result = { ...user };
|
|
2504
|
+
for (const key of Object.keys(template)) {
|
|
2505
|
+
const fullPath = currentPath ? `${currentPath}.${key}` : key;
|
|
2506
|
+
const templateValue = template[key];
|
|
2507
|
+
const userValue = user[key];
|
|
2508
|
+
if (Array.isArray(templateValue)) {
|
|
2509
|
+
const mergeConfig = arrayMerge[fullPath];
|
|
2510
|
+
if (mergeConfig && Array.isArray(userValue)) {
|
|
2511
|
+
result[key] = mergeArrayByKey(userValue, templateValue, mergeConfig.key);
|
|
2512
|
+
} else {
|
|
2513
|
+
result[key] = templateValue;
|
|
2514
|
+
}
|
|
2515
|
+
} else if (isPlainObject(templateValue)) {
|
|
2516
|
+
if (isPlainObject(userValue)) {
|
|
2517
|
+
result[key] = deepMergeJson(userValue, templateValue, arrayMerge, fullPath);
|
|
2518
|
+
} else {
|
|
2519
|
+
result[key] = templateValue;
|
|
2520
|
+
}
|
|
2521
|
+
} else {
|
|
2522
|
+
result[key] = templateValue;
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
return result;
|
|
2526
|
+
}
|
|
2527
|
+
|
|
2478
2528
|
// src/commands/sync/run.handler.ts
|
|
2479
2529
|
async function run2(options) {
|
|
2480
2530
|
const userProjectRoot = process.env.INIT_CWD || process.cwd();
|
|
@@ -2537,6 +2587,12 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
|
|
|
2537
2587
|
addLineToFile(destPath2, rule.line);
|
|
2538
2588
|
return;
|
|
2539
2589
|
}
|
|
2590
|
+
if (rule.type === "merge-json") {
|
|
2591
|
+
const srcPath2 = path4.join(pluginRoot, rule.from);
|
|
2592
|
+
const destPath2 = path4.join(userProjectRoot, rule.to);
|
|
2593
|
+
mergeJsonFile(srcPath2, destPath2, rule.arrayMerge);
|
|
2594
|
+
return;
|
|
2595
|
+
}
|
|
2540
2596
|
if (!("from" in rule)) {
|
|
2541
2597
|
return;
|
|
2542
2598
|
}
|
|
@@ -2679,6 +2735,33 @@ function addLineToFile(filePath, line) {
|
|
|
2679
2735
|
fs6.appendFileSync(filePath, appendContent);
|
|
2680
2736
|
console.log(`[fullstack-cli] \u2713 ${fileName} (added: ${line})`);
|
|
2681
2737
|
}
|
|
2738
|
+
function mergeJsonFile(src, dest, arrayMerge) {
|
|
2739
|
+
const fileName = path4.basename(dest);
|
|
2740
|
+
if (!fs6.existsSync(src)) {
|
|
2741
|
+
console.warn(`[fullstack-cli] Source not found: ${src}`);
|
|
2742
|
+
return;
|
|
2743
|
+
}
|
|
2744
|
+
const templateContent = JSON.parse(fs6.readFileSync(src, "utf-8"));
|
|
2745
|
+
if (!fs6.existsSync(dest)) {
|
|
2746
|
+
const destDir = path4.dirname(dest);
|
|
2747
|
+
if (!fs6.existsSync(destDir)) {
|
|
2748
|
+
fs6.mkdirSync(destDir, { recursive: true });
|
|
2749
|
+
}
|
|
2750
|
+
fs6.writeFileSync(dest, JSON.stringify(templateContent, null, 2) + "\n");
|
|
2751
|
+
console.log(`[fullstack-cli] \u2713 ${fileName} (created)`);
|
|
2752
|
+
return;
|
|
2753
|
+
}
|
|
2754
|
+
const userContent = JSON.parse(fs6.readFileSync(dest, "utf-8"));
|
|
2755
|
+
const merged = deepMergeJson(userContent, templateContent, arrayMerge ?? {});
|
|
2756
|
+
const userStr = JSON.stringify(userContent, null, 2);
|
|
2757
|
+
const mergedStr = JSON.stringify(merged, null, 2);
|
|
2758
|
+
if (userStr === mergedStr) {
|
|
2759
|
+
console.log(`[fullstack-cli] \u25CB ${fileName} (already up to date)`);
|
|
2760
|
+
return;
|
|
2761
|
+
}
|
|
2762
|
+
fs6.writeFileSync(dest, mergedStr + "\n");
|
|
2763
|
+
console.log(`[fullstack-cli] \u2713 ${fileName} (merged)`);
|
|
2764
|
+
}
|
|
2682
2765
|
|
|
2683
2766
|
// src/commands/sync/index.ts
|
|
2684
2767
|
var syncCommand = {
|
|
@@ -2935,7 +3018,7 @@ function getUpgradeFilesToStage(disableGenOpenapi = true) {
|
|
|
2935
3018
|
const syncConfig2 = genSyncConfig({ disableGenOpenapi });
|
|
2936
3019
|
const filesToStage = /* @__PURE__ */ new Set();
|
|
2937
3020
|
syncConfig2.sync.forEach((rule) => {
|
|
2938
|
-
if (rule.type === "file" || rule.type === "directory") {
|
|
3021
|
+
if (rule.type === "file" || rule.type === "directory" || rule.type === "merge-json") {
|
|
2939
3022
|
filesToStage.add(rule.to);
|
|
2940
3023
|
} else if (rule.type === "remove-line" || rule.type === "add-line") {
|
|
2941
3024
|
filesToStage.add(rule.to);
|
|
@@ -7173,6 +7256,12 @@ var SCENE_CONFIGS = {
|
|
|
7173
7256
|
buildRequestBody: () => ({ commitID: "" })
|
|
7174
7257
|
}
|
|
7175
7258
|
};
|
|
7259
|
+
var UPLOAD_STATIC_DEFAULTS = {
|
|
7260
|
+
staticDir: "shared/static",
|
|
7261
|
+
tosutilPath: "tosutil",
|
|
7262
|
+
endpoint: "tos-cn-beijing.volces.com",
|
|
7263
|
+
region: "cn-beijing"
|
|
7264
|
+
};
|
|
7176
7265
|
|
|
7177
7266
|
// src/commands/build/api-client.ts
|
|
7178
7267
|
async function genArtifactUploadCredential(appId, body) {
|
|
@@ -7188,17 +7277,20 @@ async function genArtifactUploadCredential(appId, body) {
|
|
|
7188
7277
|
}
|
|
7189
7278
|
async function getDefaultBucketId(appId) {
|
|
7190
7279
|
const client = getHttpClient();
|
|
7191
|
-
const url = `/
|
|
7192
|
-
const response = await client.
|
|
7280
|
+
const url = `/v1/app/${appId}/storage/inner/staticBucket`;
|
|
7281
|
+
const response = await client.post(url, {});
|
|
7193
7282
|
if (!response.ok || response.status !== 200) {
|
|
7194
7283
|
throw new Error(
|
|
7195
|
-
`
|
|
7284
|
+
`getOrCreateStaticBucket \u8BF7\u6C42\u5931\u8D25: ${response.status} ${response.statusText}`
|
|
7196
7285
|
);
|
|
7197
7286
|
}
|
|
7198
7287
|
const data = await response.json();
|
|
7199
|
-
|
|
7288
|
+
if (data.status_code !== "0") {
|
|
7289
|
+
throw new Error(`getOrCreateStaticBucket \u8FD4\u56DE\u5F02\u5E38, status_code: ${data.status_code}`);
|
|
7290
|
+
}
|
|
7291
|
+
const bucketId = data?.data?.bucketID;
|
|
7200
7292
|
if (!bucketId) {
|
|
7201
|
-
throw new Error(`\u672A\u627E\u5230\u5E94\u7528 ${appId} \u7684\
|
|
7293
|
+
throw new Error(`\u672A\u627E\u5230\u5E94\u7528 ${appId} \u7684\u9759\u6001\u8D44\u6E90\u5B58\u50A8\u6876`);
|
|
7202
7294
|
}
|
|
7203
7295
|
return bucketId;
|
|
7204
7296
|
}
|
|
@@ -7278,10 +7370,10 @@ async function uploadStatic(options) {
|
|
|
7278
7370
|
try {
|
|
7279
7371
|
const {
|
|
7280
7372
|
appId,
|
|
7281
|
-
staticDir =
|
|
7282
|
-
tosutilPath =
|
|
7283
|
-
endpoint =
|
|
7284
|
-
region =
|
|
7373
|
+
staticDir = UPLOAD_STATIC_DEFAULTS.staticDir,
|
|
7374
|
+
tosutilPath = UPLOAD_STATIC_DEFAULTS.tosutilPath,
|
|
7375
|
+
endpoint = UPLOAD_STATIC_DEFAULTS.endpoint,
|
|
7376
|
+
region = UPLOAD_STATIC_DEFAULTS.region
|
|
7285
7377
|
} = options;
|
|
7286
7378
|
const resolvedStaticDir = path21.resolve(staticDir);
|
|
7287
7379
|
if (!fs25.existsSync(resolvedStaticDir)) {
|
|
@@ -7292,9 +7384,10 @@ async function uploadStatic(options) {
|
|
|
7292
7384
|
console.error(`${LOG_PREFIX} \u76EE\u5F55\u4E3A\u7A7A: ${resolvedStaticDir}\uFF0C\u8DF3\u8FC7\u4E0A\u4F20`);
|
|
7293
7385
|
return;
|
|
7294
7386
|
}
|
|
7295
|
-
|
|
7387
|
+
const resolvedTosutil = resolveTosutilPath(tosutilPath);
|
|
7388
|
+
if (!resolvedTosutil) {
|
|
7296
7389
|
throw new Error(
|
|
7297
|
-
`tosutil \u4E0D\u5B58\u5728: ${tosutilPath}\u3002\u8BF7\u786E\u4FDD\
|
|
7390
|
+
`tosutil \u4E0D\u5B58\u5728: ${tosutilPath}\u3002\u8BF7\u786E\u4FDD tosutil \u5DF2\u5B89\u88C5\u5728\u7CFB\u7EDF PATH \u4E2D\u6216\u901A\u8FC7 --tosutil-path \u6307\u5B9A\u8DEF\u5F84\u3002`
|
|
7298
7391
|
);
|
|
7299
7392
|
}
|
|
7300
7393
|
let uploadPrefix;
|
|
@@ -7317,7 +7410,7 @@ async function uploadStatic(options) {
|
|
|
7317
7410
|
}
|
|
7318
7411
|
console.error(`${LOG_PREFIX} \u4E0A\u4F20\u76EE\u6807: ${uploadPrefix}`);
|
|
7319
7412
|
console.error(`${LOG_PREFIX} \u914D\u7F6E tosutil...`);
|
|
7320
|
-
configureTosutil(
|
|
7413
|
+
configureTosutil(resolvedTosutil, {
|
|
7321
7414
|
endpoint,
|
|
7322
7415
|
region,
|
|
7323
7416
|
accessKeyID,
|
|
@@ -7325,7 +7418,7 @@ async function uploadStatic(options) {
|
|
|
7325
7418
|
sessionToken
|
|
7326
7419
|
});
|
|
7327
7420
|
console.error(`${LOG_PREFIX} \u4E0A\u4F20 ${resolvedStaticDir} -> ${uploadPrefix}`);
|
|
7328
|
-
uploadToTos(
|
|
7421
|
+
uploadToTos(resolvedTosutil, resolvedStaticDir, uploadPrefix);
|
|
7329
7422
|
console.error(`${LOG_PREFIX} tosutil \u4E0A\u4F20\u5B8C\u6210`);
|
|
7330
7423
|
console.error(`${LOG_PREFIX} \u8C03\u7528 callbackStatic (uploadID: ${uploadID})...`);
|
|
7331
7424
|
const callbackResp = await uploadStaticAttachmentCallback(appId, bucketId, { uploadID });
|
|
@@ -7341,6 +7434,17 @@ async function uploadStatic(options) {
|
|
|
7341
7434
|
process.exit(1);
|
|
7342
7435
|
}
|
|
7343
7436
|
}
|
|
7437
|
+
function resolveTosutilPath(tosutilPath) {
|
|
7438
|
+
if (path21.isAbsolute(tosutilPath)) {
|
|
7439
|
+
return fs25.existsSync(tosutilPath) ? tosutilPath : null;
|
|
7440
|
+
}
|
|
7441
|
+
try {
|
|
7442
|
+
const resolved = execFileSync("which", [tosutilPath], { encoding: "utf-8" }).trim();
|
|
7443
|
+
return resolved || null;
|
|
7444
|
+
} catch {
|
|
7445
|
+
return null;
|
|
7446
|
+
}
|
|
7447
|
+
}
|
|
7344
7448
|
async function fetchPreUpload(appId, bucketId) {
|
|
7345
7449
|
const response = await preUploadStaticAttachment(appId, bucketId);
|
|
7346
7450
|
if (response.status_code !== "0") {
|
|
@@ -7435,7 +7539,7 @@ var uploadStaticCommand = {
|
|
|
7435
7539
|
name: "upload-static",
|
|
7436
7540
|
description: "Upload shared/static files to TOS",
|
|
7437
7541
|
register(program) {
|
|
7438
|
-
program.command(this.name).description(this.description).requiredOption("--app-id <id>", "Application ID").option("--static-dir <dir>", "Static files directory",
|
|
7542
|
+
program.command(this.name).description(this.description).requiredOption("--app-id <id>", "Application ID").option("--static-dir <dir>", "Static files directory", UPLOAD_STATIC_DEFAULTS.staticDir).option("--tosutil-path <path>", "Path to tosutil binary", UPLOAD_STATIC_DEFAULTS.tosutilPath).option("--endpoint <endpoint>", "TOS endpoint", UPLOAD_STATIC_DEFAULTS.endpoint).option("--region <region>", "TOS region", UPLOAD_STATIC_DEFAULTS.region).action(async (options) => {
|
|
7439
7543
|
await uploadStatic(options);
|
|
7440
7544
|
});
|
|
7441
7545
|
}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
set -euo pipefail
|
|
4
4
|
|
|
5
5
|
ROOT_DIR="$(pwd)"
|
|
6
|
-
|
|
6
|
+
DIST_DIR="$ROOT_DIR/dist"
|
|
7
7
|
|
|
8
8
|
# 记录总开始时间
|
|
9
9
|
TOTAL_START=$(node -e "console.log(Date.now())")
|
|
@@ -78,25 +78,26 @@ print_time $STEP_START
|
|
|
78
78
|
echo ""
|
|
79
79
|
|
|
80
80
|
# ==================== 步骤 4 ====================
|
|
81
|
-
echo "📦 [4/5]
|
|
81
|
+
echo "📦 [4/5] 准备产物"
|
|
82
82
|
STEP_START=$(node -e "console.log(Date.now())")
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
# 移动 HTML(从 dist/client 移走,避免残留)
|
|
87
|
-
mv "$ROOT_DIR/dist/client/"*.html "$OUT_DIR/dist/client/" || true
|
|
88
|
-
|
|
89
|
-
# 拷贝 run.sh 文件
|
|
90
|
-
cp "$ROOT_DIR/scripts/run.sh" "$OUT_DIR/"
|
|
84
|
+
# 拷贝 run.sh 到 dist/(prod 从 dist/ 启动,确保 cwd 一致性)
|
|
85
|
+
cp "$ROOT_DIR/scripts/run.sh" "$DIST_DIR/"
|
|
91
86
|
|
|
92
87
|
# 拷贝 .env 文件(如果存在)
|
|
93
88
|
if [ -f "$ROOT_DIR/.env" ]; then
|
|
94
|
-
cp "$ROOT_DIR/.env" "$
|
|
89
|
+
cp "$ROOT_DIR/.env" "$DIST_DIR/"
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
# 移动 client 下的 HTML 文件到 dist/dist/client,保证 views 路径在 dev/prod 下一致
|
|
93
|
+
if [ -d "$DIST_DIR/client" ]; then
|
|
94
|
+
mkdir -p "$DIST_DIR/dist/client"
|
|
95
|
+
find "$DIST_DIR/client" -maxdepth 1 -name "*.html" -exec mv {} "$DIST_DIR/dist/client/" \;
|
|
95
96
|
fi
|
|
96
97
|
|
|
97
98
|
# 清理无用文件
|
|
98
|
-
rm -rf "$
|
|
99
|
-
rm -rf "$
|
|
99
|
+
rm -rf "$DIST_DIR/scripts"
|
|
100
|
+
rm -rf "$DIST_DIR/tsconfig.node.tsbuildinfo"
|
|
100
101
|
|
|
101
102
|
print_time $STEP_START
|
|
102
103
|
echo ""
|
|
@@ -116,8 +117,8 @@ echo "构建完成"
|
|
|
116
117
|
print_time $TOTAL_START
|
|
117
118
|
|
|
118
119
|
# 输出产物信息
|
|
119
|
-
DIST_SIZE=$(du -sh "$
|
|
120
|
-
NODE_MODULES_SIZE=$(du -sh "$
|
|
120
|
+
DIST_SIZE=$(du -sh "$DIST_DIR" | cut -f1)
|
|
121
|
+
NODE_MODULES_SIZE=$(du -sh "$DIST_DIR/node_modules" | cut -f1)
|
|
121
122
|
echo ""
|
|
122
123
|
echo "📊 构建产物统计:"
|
|
123
124
|
echo " 产物大小: $DIST_SIZE"
|
|
@@ -6,11 +6,12 @@ const fs = require('fs');
|
|
|
6
6
|
const path = require('path');
|
|
7
7
|
|
|
8
8
|
const ROOT_DIR = path.resolve(__dirname, '..');
|
|
9
|
-
const
|
|
9
|
+
const DIST_DIR = path.join(ROOT_DIR, 'dist');
|
|
10
|
+
const DIST_SERVER_DIR = path.join(DIST_DIR, 'server');
|
|
10
11
|
const ROOT_PACKAGE_JSON = path.join(ROOT_DIR, 'package.json');
|
|
11
12
|
const ROOT_NODE_MODULES = path.join(ROOT_DIR, 'node_modules');
|
|
12
|
-
const OUT_NODE_MODULES = path.join(
|
|
13
|
-
const OUT_PACKAGE_JSON = path.join(
|
|
13
|
+
const OUT_NODE_MODULES = path.join(DIST_DIR, 'node_modules');
|
|
14
|
+
const OUT_PACKAGE_JSON = path.join(DIST_DIR, 'package.json');
|
|
14
15
|
|
|
15
16
|
// Server 入口文件
|
|
16
17
|
const SERVER_ENTRY = path.join(DIST_SERVER_DIR, 'main.js');
|
|
@@ -294,9 +295,6 @@ async function smartPrune() {
|
|
|
294
295
|
version: originalPackage.version,
|
|
295
296
|
private: true,
|
|
296
297
|
dependencies: prunedDependencies,
|
|
297
|
-
scripts: {
|
|
298
|
-
start: originalPackage.scripts?.start || 'node main.js'
|
|
299
|
-
},
|
|
300
298
|
engines: originalPackage.engines
|
|
301
299
|
};
|
|
302
300
|
|
package/templates/scripts/run.sh
CHANGED