@seayoo-web/scripts 2.4.1 → 2.5.0

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.
@@ -124,6 +124,42 @@ function getNowTime() {
124
124
  function fillZ(a) {
125
125
  return ("0" + a).slice(-2);
126
126
  }
127
+ function deepMerge(target, ...sourceList) {
128
+ for (const source of sourceList) {
129
+ if (!source || typeof source !== "object") continue;
130
+ for (const key in source) {
131
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
132
+ const sourceValue = source[key];
133
+ const targetValue = target[key];
134
+ if (isPlainObject(targetValue) && isPlainObject(sourceValue)) {
135
+ target[key] = deepMerge({ ...targetValue }, sourceValue);
136
+ } else if (isPlainObject(sourceValue)) {
137
+ target[key] = deepMerge({}, sourceValue);
138
+ } else if (Array.isArray(sourceValue)) {
139
+ target[key] = [...sourceValue];
140
+ } else {
141
+ target[key] = sourceValue;
142
+ }
143
+ }
144
+ }
145
+ }
146
+ return target;
147
+ }
148
+ function isPlainObject(value) {
149
+ return typeof value === "object" && value !== null && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]";
150
+ }
151
+ const formatReg = /\{\{\s*([\w\.]+)\s*\}\}/g;
152
+ function format(string, source) {
153
+ return string.replace(formatReg, function(_, keys) {
154
+ let val = source;
155
+ const keyPath = keys.split(".");
156
+ for (let i = 0; i < keyPath.length; i++) {
157
+ const p = keyPath[i];
158
+ val = typeof val === "object" && !!val ? p in val ? val[p] : void 0 : void 0;
159
+ }
160
+ return val === void 0 || val === null ? "" : val + "";
161
+ });
162
+ }
127
163
  const MainBranchName = "main";
128
164
  const DeployTagPrefix = "deploy_";
129
165
  const BackupTagPrefix = "backup_";
@@ -266,6 +302,9 @@ export {
266
302
  checkGitStatusBeforeDestroy as j,
267
303
  createBackupTag as k,
268
304
  getRepos as l,
305
+ isPlainObject as m,
306
+ format as n,
307
+ deepMerge as o,
269
308
  removeProjectFromWorkspace as r,
270
309
  submitAllDeletionChanges as s
271
310
  };
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import vueDevTools from "vite-plugin-vue-devtools";
8
8
  import { existsSync, readFileSync } from "fs";
9
9
  import { loadEnv } from "vite";
10
10
  import "colors";
11
- import { g as getNowTime, a as getCommitInfo, c as createPageDeployTag } from "./git-ByQTrD0l.js";
11
+ import { g as getNowTime, a as getCommitInfo, c as createPageDeployTag } from "./git-9UtzsH83.js";
12
12
  import skipFormatting from "@vue/eslint-config-prettier/skip-formatting";
13
13
  import { vueTsConfigs, defineConfigWithVueTs } from "@vue/eslint-config-typescript";
14
14
  import { flatConfigs } from "eslint-plugin-import";
package/dist/node.js CHANGED
@@ -1,11 +1,19 @@
1
- import { readFileSync } from "fs";
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+ import { readFileSync, readdirSync, statSync, existsSync, rmSync, mkdirSync, writeFileSync } from "fs";
2
5
  import "colors";
3
- import path from "path";
6
+ import path, { resolve } from "path";
4
7
  import { Command } from "commander";
5
8
  import fs from "fs-extra";
6
9
  import inquirer from "inquirer";
7
10
  import ora from "ora";
8
- import { b as getMonorepoRoot, d as addProjectToWorkspace, e as copyTemplate, f as copyGlobalFiles, h as getProjects, i as getTemplates, j as checkGitStatusBeforeDestroy, k as createBackupTag, r as removeProjectFromWorkspace, s as submitAllDeletionChanges, l as getRepos } from "./git-ByQTrD0l.js";
11
+ import { b as getMonorepoRoot, d as addProjectToWorkspace, e as copyTemplate, f as copyGlobalFiles, h as getProjects, i as getTemplates, j as checkGitStatusBeforeDestroy, k as createBackupTag, r as removeProjectFromWorkspace, s as submitAllDeletionChanges, l as getRepos, m as isPlainObject, n as format, o as deepMerge } from "./git-9UtzsH83.js";
12
+ import { finderUpload } from "@seayoo-web/finder";
13
+ import { finderDeploy, finderUpload as finderUpload2 } from "@seayoo-web/finder";
14
+ import { createServer } from "http";
15
+ import chokidar from "chokidar";
16
+ import { minify } from "html-minifier-terser";
9
17
  const commitRE = /^(?:revert: )?(?:feat|fix|docs|style|refactor|test|build|chore|debug|tweak|improve)(?:\(.+\))?: .{1,100}/;
10
18
  function checkCommit() {
11
19
  const msgPath = process.argv[2];
@@ -277,8 +285,350 @@ async function destroyRepo() {
277
285
  spinner.succeed("页面已经销毁!".green);
278
286
  }
279
287
  program.action(startCreateJob);
288
+ const styleReg = /<style>.+?<\/style>/gi;
289
+ const scriptReg = /<script>.+?<\/script>/gi;
290
+ const scriptMetaReg = /<script meta>.+?<\/script>/gi;
291
+ const htmlReg = /<template>.+?<\/template>/gi;
292
+ class FooterBuilder {
293
+ constructor({
294
+ codeBaseDir,
295
+ distDir,
296
+ dataJsonFile,
297
+ envFilePath,
298
+ injectFunction
299
+ }) {
300
+ __publicField(this, "codeBaseDir");
301
+ __publicField(this, "envFilePath");
302
+ __publicField(this, "distDir");
303
+ __publicField(this, "dataJsonFile");
304
+ __publicField(this, "injectFunction");
305
+ __publicField(this, "$groups");
306
+ this.codeBaseDir = codeBaseDir;
307
+ this.envFilePath = envFilePath;
308
+ this.distDir = distDir;
309
+ this.dataJsonFile = dataJsonFile;
310
+ this.injectFunction = injectFunction;
311
+ this.$groups = readdirSync(codeBaseDir).filter((name) => {
312
+ return statSync(resolve(codeBaseDir, name)).isDirectory();
313
+ });
314
+ if (this.$groups.length === 0) {
315
+ console.warn("⚠️没有找到组信息,请先创建组目录。");
316
+ }
317
+ if (existsSync(distDir)) {
318
+ rmSync(distDir, { recursive: true });
319
+ }
320
+ for (const group of this.$groups) {
321
+ mkdirSync(resolve(distDir, group), { recursive: true });
322
+ }
323
+ }
324
+ get groups() {
325
+ return this.$groups;
326
+ }
327
+ getDeployUserKey() {
328
+ if (!existsSync(this.envFilePath)) {
329
+ return null;
330
+ }
331
+ const config = readFileSync(this.envFilePath, "utf8").toString();
332
+ const userMatch = config.match(/SY_DEPLOY_USER *= *([a-z\d]+)/);
333
+ const keyMatch = config.match(/SY_DEPLOY_KEY *= *([a-z\d]+)/);
334
+ return {
335
+ user: ((userMatch == null ? void 0 : userMatch[1]) || "").trim(),
336
+ key: ((keyMatch == null ? void 0 : keyMatch[1]) || "").trim()
337
+ };
338
+ }
339
+ getAllTemplates() {
340
+ return this.$groups.map((group) => {
341
+ const groupDir = resolve(this.codeBaseDir, group);
342
+ return readdirSync(groupDir).filter((file) => file.endsWith(".html")).map((file) => `${group}/${file}`);
343
+ }).flat();
344
+ }
345
+ getTemplateFile(group, template) {
346
+ return `${group}/${template}.html`;
347
+ }
348
+ loadDefaultData() {
349
+ const jsonText = readFileSync(this.dataJsonFile).toString();
350
+ function removeCommit(json) {
351
+ for (const key in json) {
352
+ if (isPlainObject(json[key])) {
353
+ removeCommit(json[key]);
354
+ } else if (key.startsWith("-") || key.startsWith("+") || key.startsWith("#")) {
355
+ delete json[key];
356
+ }
357
+ }
358
+ return json;
359
+ }
360
+ try {
361
+ return removeCommit(JSON.parse(jsonText));
362
+ } catch (e) {
363
+ console.log("配置数据加载失败", e);
364
+ return {};
365
+ }
366
+ }
367
+ formatMetaConfig(string) {
368
+ try {
369
+ const json = new Function(string.replace(/export default/, ";return "))();
370
+ if (!isPlainObject(json)) {
371
+ console.error("格式化 meta 信息错误,应该是一个简单对象");
372
+ return null;
373
+ }
374
+ const keys = Object.keys(json);
375
+ if (keys.length === 0) {
376
+ console.error("格式化 meta 信息错误,对象不能为空");
377
+ return null;
378
+ }
379
+ const result = [];
380
+ for (const key of keys) {
381
+ if (!key.includes("/public/footer/") && !key.includes("/snippets/")) {
382
+ console.error(`deployTo (${key}) 错误, 必须包含路径 "/public/footer/" 或 "/snippets/"`);
383
+ return null;
384
+ }
385
+ const config = json[key];
386
+ if (!isPlainObject(config)) {
387
+ console.error(`deployTo (${key}) 配置错误,应该是一个简单对象`);
388
+ return null;
389
+ }
390
+ if (!("enabledIn" in config) || !Array.isArray(config.enabledIn) || config.enabledIn.length === 0 || config.enabledIn.some((x) => typeof x !== "string")) {
391
+ console.error(`deployTo (${key}) 配置项 enabledIn 错误, 应该是一个包含域名的非空数组`);
392
+ return null;
393
+ }
394
+ if ("payload" in config && !isPlainObject(config.payload)) {
395
+ console.error(`deployTo (${key}) 配置项 payload 错误, 应该是一个对象`);
396
+ return null;
397
+ }
398
+ result.push({
399
+ deployTo: key,
400
+ enabledIn: config.enabledIn,
401
+ payload: isPlainObject(config.payload) ? config.payload : void 0
402
+ });
403
+ }
404
+ return result;
405
+ } catch (e) {
406
+ console.error("Format Meta Config Error", e);
407
+ return null;
408
+ }
409
+ }
410
+ async buildEntry(template, payloadData) {
411
+ if (!template.endsWith(".html")) {
412
+ console.error(`${template} 不是 html 文件!`);
413
+ return [];
414
+ }
415
+ const htmlRaw = readFileSync(resolve(this.codeBaseDir, template)).toString();
416
+ const miniHtml = await minify(htmlRaw, {
417
+ collapseWhitespace: true,
418
+ removeComments: true,
419
+ removeScriptTypeAttributes: true,
420
+ removeStyleLinkTypeAttributes: true,
421
+ sortAttributes: true,
422
+ removeEmptyElements: true,
423
+ minifyCSS: true,
424
+ minifyJS: true
425
+ });
426
+ const style = (miniHtml.match(styleReg) || []).map((code) => code.slice(7, -8)).join("");
427
+ const meta = (miniHtml.match(scriptMetaReg) || []).map((code) => code.slice(13, -9)).join(";");
428
+ const script = (miniHtml.match(scriptReg) || []).map((code) => code.slice(8, -9)).join(";");
429
+ const html = (miniHtml.match(htmlReg) || []).map((code) => code.slice(10, -11)).join("");
430
+ if (!html) {
431
+ console.log(`${template} 的 html 数据配置错误,请检查。`);
432
+ return [];
433
+ }
434
+ if (!style) {
435
+ console.log(`${template} 的 style 数据配置错误,请检查。`);
436
+ return [];
437
+ }
438
+ const metaConfig = this.formatMetaConfig(meta);
439
+ if (!metaConfig) {
440
+ console.log(`${template} 的 script meta 数据配置错误,请检查。`);
441
+ return [];
442
+ }
443
+ const buildResult = [];
444
+ for (const config of metaConfig) {
445
+ const formattedHTML = format(html, deepMerge({}, payloadData || {}, config.payload || {})).replace(/<img [^>]*?src=""[^>]+>/gi, "").replace(/<a [^>]*?href=""[^>]+>(.*?)<\/a>/gi, "$1").replace(/<p class="">/gi, "<p>").replace(/(?:<p>\s*<\/p>|<section>\s*<\/section>|<div>\s*<\/div>)/gi, "");
446
+ buildResult.push({
447
+ deployTo: config.deployTo,
448
+ group: template.replace(/\/.*$/, ""),
449
+ template,
450
+ filename: config.deployTo.replace(/^.*\//, ""),
451
+ code: await this.combineToCode(config.enabledIn, style, script, formattedHTML)
452
+ });
453
+ }
454
+ return buildResult;
455
+ }
456
+ async combineToCode(enabledIn, style, script, html) {
457
+ const func = (await minify(`<script>${this.injectFunction}<\/script>`, {
458
+ collapseWhitespace: true,
459
+ removeComments: true,
460
+ minifyJS: true
461
+ })).slice(8, -9).replace(/function injectFooter/, "function");
462
+ return `(${func})(${JSON.stringify(enabledIn)},${JSON.stringify(style)},${JSON.stringify(script)},${JSON.stringify(html)})`;
463
+ }
464
+ async upload(deployTo, code, user, key) {
465
+ return await finderUpload({
466
+ fileContent: code,
467
+ deployTo,
468
+ user,
469
+ key,
470
+ preview: true
471
+ }).then(() => null).catch((err) => err instanceof Error ? err : new Error(err));
472
+ }
473
+ /**
474
+ * 核心构建方法,根据模板文件生成结果
475
+ * @param templateFile 可选模板文件路径,若未提供则使用所有模板
476
+ * @returns 返回构建结果数组
477
+ */
478
+ async coreBuild(templateFile) {
479
+ const templateData = this.loadDefaultData();
480
+ const templates = templateFile ? [templateFile.replace(/\\/g, "/")] : this.getAllTemplates();
481
+ const result = [];
482
+ for (const html of templates) {
483
+ result.push(...await this.buildEntry(html, templateData));
484
+ }
485
+ return result;
486
+ }
487
+ /**
488
+ * 构建模板并输出结果文件
489
+ * @param templateFile - 模板文件路径
490
+ */
491
+ async buildAndOutput(templateFile) {
492
+ const result = await this.coreBuild(templateFile);
493
+ for (const { group, template, filename, code } of result) {
494
+ mkdirSync(resolve(this.distDir, group, template), { recursive: true });
495
+ writeFileSync(resolve(this.distDir, group, template, filename), code);
496
+ }
497
+ }
498
+ /**
499
+ * 监听代码目录变化并触发构建
500
+ * @description 使用chokidar监控代码目录,当非目录添加事件发生时:
501
+ * - 如果是.html文件,构建并输出相对路径
502
+ * - 其他文件变更则触发全量构建
503
+ */
504
+ startFileWatch() {
505
+ chokidar.watch(this.codeBaseDir).on("all", (event, path2) => {
506
+ if (event !== "addDir") {
507
+ if (path2.endsWith(".html")) {
508
+ this.buildAndOutput(path2.slice(4).replace(/\\/g, "/"));
509
+ } else {
510
+ this.buildAndOutput();
511
+ }
512
+ }
513
+ });
514
+ }
515
+ /**
516
+ * 启动部署服务器,监听指定端口
517
+ * @param port 服务器监听端口,默认为7759
518
+ * @description
519
+ * 1. 处理跨域请求和预检OPTIONS请求
520
+ * 2. 验证部署配置和用户权限
521
+ * 3. 支持两种部署模式:
522
+ * - 部署单个文件:匹配 /deploy/[group]/[template]/[filename] 路径
523
+ * - 部署模板下所有文件:匹配 /deploy/[group]/[template] 路径
524
+ * 4. 返回部署结果或错误信息
525
+ */
526
+ startDeployServer(port = 7759) {
527
+ const server = createServer(async (req, res) => {
528
+ const cosHeader = {
529
+ "Access-Control-Allow-Origin": req.headers.origin || "https://127.0.0.1",
530
+ "Access-Control-Allow-Methods": "GET, OPTIONS",
531
+ "Access-Control-Allow-Headers": "Content-Type, Authorization",
532
+ "Access-Control-Max-Age": "86400"
533
+ };
534
+ const url = (req.url || "").trim();
535
+ const method = (req.method || "get").toLowerCase();
536
+ if (method === "options") {
537
+ res.writeHead(200, cosHeader);
538
+ res.end();
539
+ return;
540
+ }
541
+ const fileDeployInfo = url.match(/deploy\/([^/]+)\/([^/]+)\/([^/]+)$/);
542
+ const templateDeployInfo = url.match(/deploy\/([^/]+)\/([^/]+)$/);
543
+ const user = this.getDeployUserKey();
544
+ if (fileDeployInfo || templateDeployInfo) {
545
+ if (!user) {
546
+ res.writeHead(403, cosHeader);
547
+ res.write("请先在根目录添加 .env.local 文件");
548
+ res.end();
549
+ return;
550
+ }
551
+ if (!user.user) {
552
+ res.writeHead(403, cosHeader);
553
+ res.write("请设置 .env.local 文件中 SY_DEPLOY_USER");
554
+ res.end();
555
+ return;
556
+ }
557
+ if (!user.key) {
558
+ res.writeHead(403, cosHeader);
559
+ res.write("请设置 .env.local 文件中 SY_DEPLOY_KEY");
560
+ res.end();
561
+ return;
562
+ }
563
+ const group = (fileDeployInfo == null ? void 0 : fileDeployInfo[1]) || (templateDeployInfo == null ? void 0 : templateDeployInfo[1]) || "";
564
+ const allGroups = this.groups;
565
+ if (!allGroups.includes(group)) {
566
+ res.writeHead(403, cosHeader);
567
+ res.write(`分组错误,没有 ${group}`);
568
+ res.end();
569
+ return;
570
+ }
571
+ const template = fileDeployInfo ? this.getTemplateFile(fileDeployInfo[1], fileDeployInfo[2]) : templateDeployInfo ? this.getTemplateFile(templateDeployInfo[1], templateDeployInfo[2]) : "";
572
+ const allTemplates = this.getAllTemplates();
573
+ if (!allTemplates.includes(template)) {
574
+ res.writeHead(403, cosHeader);
575
+ res.write(`模板错误,没有 ${template}`);
576
+ res.end();
577
+ return;
578
+ }
579
+ }
580
+ if (fileDeployInfo) {
581
+ const buildResult = await this.coreBuild(this.getTemplateFile(fileDeployInfo[1], fileDeployInfo[2]));
582
+ const filename = `${fileDeployInfo[3].replace(/\.js$/, "")}.js`;
583
+ const data = buildResult.find((data2) => data2.filename === filename);
584
+ if (!data) {
585
+ res.writeHead(504, cosHeader);
586
+ res.write(`没有找到文件 ${filename}`);
587
+ res.end();
588
+ return;
589
+ }
590
+ const err = await this.upload(data.deployTo, data.code, (user == null ? void 0 : user.user) || "", (user == null ? void 0 : user.key) || "");
591
+ res.writeHead(200, { "Content-Type": "text/plain", ...cosHeader });
592
+ res.write(err ? `部署失败 ${err.message}` : `部署完毕 ${data.deployTo}`);
593
+ res.end();
594
+ return;
595
+ }
596
+ if (templateDeployInfo) {
597
+ const buildResult = await this.coreBuild(this.getTemplateFile(templateDeployInfo[1], templateDeployInfo[2]));
598
+ const success = [];
599
+ const failed = [];
600
+ for (const data of buildResult) {
601
+ const err = await this.upload(data.deployTo, data.code, (user == null ? void 0 : user.user) || "", (user == null ? void 0 : user.key) || "");
602
+ if (err) {
603
+ failed.push(data.deployTo);
604
+ } else {
605
+ success.push(data.deployTo);
606
+ }
607
+ }
608
+ res.writeHead(200, { "Content-Type": "text/plain", ...cosHeader });
609
+ res.write(
610
+ [
611
+ success.length > 0 ? `部署成功
612
+ ${success.join("\n")}` : "",
613
+ failed.length > 0 ? `部署失败
614
+ ${failed.join("\n")}` : ""
615
+ ].join("\n")
616
+ );
617
+ res.end();
618
+ return;
619
+ }
620
+ res.writeHead(404, { "Content-Type": "text/plain", ...cosHeader });
621
+ res.write("Api Not Found");
622
+ res.end();
623
+ });
624
+ server.listen(port);
625
+ }
626
+ }
280
627
  export {
628
+ FooterBuilder,
281
629
  checkCommit,
630
+ finderDeploy,
631
+ finderUpload2 as finderUpload,
282
632
  runCreateScript,
283
633
  runDestroyScript
284
634
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seayoo-web/scripts",
3
- "version": "2.4.1",
3
+ "version": "2.5.0",
4
4
  "description": "scripts for seayoo web repos",
5
5
  "type": "module",
6
6
  "source": "index.ts",
@@ -38,11 +38,13 @@
38
38
  "@vitejs/plugin-vue": "^5.2.3",
39
39
  "@vue/eslint-config-prettier": "^10.2.0",
40
40
  "@vue/eslint-config-typescript": "^14.5.0",
41
+ "chokidar": "^4.0.3",
41
42
  "colors": "^1.4.0",
42
43
  "commander": "^13.1.0",
43
44
  "eslint-plugin-import": "^2.31.0",
44
45
  "eslint-plugin-vue": "^9.33.0",
45
46
  "fs-extra": "^11.3.0",
47
+ "html-minifier-terser": "^7.2.0",
46
48
  "inquirer": "^12.5.2",
47
49
  "jiti": "^2.4.2",
48
50
  "ora": "^8.2.0",
@@ -51,10 +53,11 @@
51
53
  "terser": "^5.39.0",
52
54
  "vite-plugin-stylelint": "^6.0.0",
53
55
  "vite-plugin-vue-devtools": "^7.7.5",
54
- "@seayoo-web/finder": "^2.1.0"
56
+ "@seayoo-web/finder": "^2.1.1"
55
57
  },
56
58
  "devDependencies": {
57
59
  "@types/fs-extra": "^11.0.4",
60
+ "@types/html-minifier-terser": "^7.0.2",
58
61
  "@types/node": "^22.14.1",
59
62
  "@typescript-eslint/utils": "^8.30.1",
60
63
  "eslint": "^9.25.0",
package/types/node.d.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  export * from "./src/commit";
2
2
  export * from "./src/create";
3
3
  export * from "./src/destroy";
4
+ export * from "./src/finder";
5
+ export * from "./src/footer";
@@ -0,0 +1 @@
1
+ export { finderUpload, finderDeploy } from "@seayoo-web/finder";
@@ -0,0 +1,60 @@
1
+ export declare class FooterBuilder {
2
+ private codeBaseDir;
3
+ private envFilePath;
4
+ private distDir;
5
+ private dataJsonFile;
6
+ private injectFunction;
7
+ private $groups;
8
+ constructor({ codeBaseDir, distDir, dataJsonFile, envFilePath, injectFunction, }: {
9
+ codeBaseDir: string;
10
+ distDir: string;
11
+ dataJsonFile: string;
12
+ envFilePath: string;
13
+ injectFunction: string;
14
+ });
15
+ get groups(): string[];
16
+ private getDeployUserKey;
17
+ private getAllTemplates;
18
+ private getTemplateFile;
19
+ private loadDefaultData;
20
+ private formatMetaConfig;
21
+ private buildEntry;
22
+ private combineToCode;
23
+ private upload;
24
+ /**
25
+ * 核心构建方法,根据模板文件生成结果
26
+ * @param templateFile 可选模板文件路径,若未提供则使用所有模板
27
+ * @returns 返回构建结果数组
28
+ */
29
+ coreBuild(templateFile?: string): Promise<{
30
+ deployTo: string;
31
+ group: string;
32
+ template: string;
33
+ filename: string;
34
+ code: string;
35
+ }[]>;
36
+ /**
37
+ * 构建模板并输出结果文件
38
+ * @param templateFile - 模板文件路径
39
+ */
40
+ buildAndOutput(templateFile?: string): Promise<void>;
41
+ /**
42
+ * 监听代码目录变化并触发构建
43
+ * @description 使用chokidar监控代码目录,当非目录添加事件发生时:
44
+ * - 如果是.html文件,构建并输出相对路径
45
+ * - 其他文件变更则触发全量构建
46
+ */
47
+ startFileWatch(): void;
48
+ /**
49
+ * 启动部署服务器,监听指定端口
50
+ * @param port 服务器监听端口,默认为7759
51
+ * @description
52
+ * 1. 处理跨域请求和预检OPTIONS请求
53
+ * 2. 验证部署配置和用户权限
54
+ * 3. 支持两种部署模式:
55
+ * - 部署单个文件:匹配 /deploy/[group]/[template]/[filename] 路径
56
+ * - 部署模板下所有文件:匹配 /deploy/[group]/[template] 路径
57
+ * 4. 返回部署结果或错误信息
58
+ */
59
+ startDeployServer(port?: number): void;
60
+ }
@@ -44,3 +44,11 @@ export declare function addProjectToWorkspace(project: string): Promise<void>;
44
44
  */
45
45
  export declare function removeProjectFromWorkspace(project: string): Promise<void>;
46
46
  export declare function getNowTime(): string;
47
+ export declare function deepMerge(target: Record<string, unknown>, ...sourceList: Record<string, unknown>[]): Record<string, unknown>;
48
+ export declare function isPlainObject(value: unknown): value is Record<string, unknown>;
49
+ /**
50
+ * 模板格式化
51
+ * @param string 要格式化的模板字符串
52
+ * @param source 要填充的数据源
53
+ */
54
+ export declare function format(string: string, source: Record<string, unknown>): string;