@seayoo-web/scripts 2.4.0 → 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.
- package/dist/{git-w5-27jZ7.js → git-9UtzsH83.js} +41 -2
- package/dist/index.js +1 -1
- package/dist/node.js +353 -3
- package/package.json +5 -2
- package/types/node.d.ts +2 -0
- package/types/src/finder.d.ts +1 -0
- package/types/src/footer.d.ts +60 -0
- package/types/src/utils.d.ts +8 -0
|
@@ -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_";
|
|
@@ -209,9 +245,9 @@ async function getCommitLogs(branchOrCommit, sinceCommit, codePath) {
|
|
|
209
245
|
"git log",
|
|
210
246
|
sinceCommit ? `${sinceCommit}..${branchOrCommit || "HEAD"}` : branchOrCommit || "",
|
|
211
247
|
/** spell-checker:disable-next-line */
|
|
212
|
-
`--oneline --pretty=format:"[%cd]
|
|
248
|
+
`--oneline --pretty=format:"[%cd] %s" --date=short -n 60`,
|
|
213
249
|
`-- ${codePath}`
|
|
214
|
-
].filter((f) => !!f).join(" ");
|
|
250
|
+
].filter((f) => !!f && !f.includes("Merge branch")).join(" ");
|
|
215
251
|
const result = await execCmd(cmd);
|
|
216
252
|
return result ? result.split("\n") : [];
|
|
217
253
|
}
|
|
@@ -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-
|
|
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
|
-
|
|
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-
|
|
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.
|
|
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.
|
|
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
|
@@ -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
|
+
}
|
package/types/src/utils.d.ts
CHANGED
|
@@ -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;
|