@infly/libs 2.0.36 → 2.0.37

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/bin/cli.js CHANGED
@@ -1,31 +1,38 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { init: buildInit, scriptInit: buildScriptInit, beforeBuild } = require("../build/build-dist");
4
- const { init: previewInit, scriptInit: previewScriptInit } = require("../tools/project-preview");
3
+ function loadBuildDist() {
4
+ return require("../build/build-dist");
5
+ }
6
+
7
+ function loadPreview() {
8
+ return require("../tools/project-preview");
9
+ }
5
10
 
6
11
  const command = process.argv[2];
7
12
  const commandMap = {
8
- afterBuild: buildInit,
9
- initZip: buildInit,
10
- preview: previewInit,
11
- "--preview": previewInit,
12
- beforeBuild: beforeBuild,
13
+ afterBuild: () => loadBuildDist().init(),
14
+ initZip: () => loadBuildDist().init(),
15
+ preview: () => loadPreview().init(),
16
+ "--preview": () => loadPreview().init(),
17
+ beforeBuild: () => loadBuildDist().beforeBuild(),
13
18
  scriptOverride: () => {
14
- previewScriptInit();
15
- buildScriptInit();
19
+ const preview = loadPreview();
20
+ const buildDist = loadBuildDist();
21
+
22
+ preview.scriptInit();
23
+ buildDist.scriptInit();
16
24
  }
17
25
  };
18
26
 
19
- // 执行命令
20
- if (command && commandMap[command]) {
21
- commandMap[command]();
22
- } else {
23
- console.error(`未知命令: ${command || "未提供命令"}`);
24
- console.log(
25
- "可用命令: " +
26
- Object.keys(commandMap)
27
- .filter((cmd) => typeof commandMap[cmd] === "function")
28
- .join(", ")
29
- );
30
- process.exit(1); // 使用非零退出码表示错误
31
- }
27
+ (async () => {
28
+ if (command && commandMap[command]) {
29
+ await commandMap[command]();
30
+ } else {
31
+ console.error(`未知命令: ${command || "未提供命令"}`);
32
+ console.log(`可用命令: ${Object.keys(commandMap).join(", ")}`);
33
+ process.exit(1);
34
+ }
35
+ })().catch((error) => {
36
+ console.error("执行失败:", error);
37
+ process.exit(1);
38
+ });
@@ -1,4 +1,4 @@
1
- /**
1
+ /**
2
2
  * 构建工具
3
3
  * @description
4
4
  * 工具实现根据配置自动切换分支,构建到配置的对应文件夹路径,并且执行自动提交推送,也可执行自动压缩提交到当前项目
@@ -29,7 +29,9 @@ const {
29
29
  getCurrentBranch,
30
30
  getLatestCommitInfo,
31
31
  getLastCommitByFile,
32
- checkAndUpdatePackages
32
+ checkAndUpdatePackages,
33
+ checkSingleDirGitStatus,
34
+ pullSingleDirFromBranch
33
35
  } = require("../../script/git-automation");
34
36
 
35
37
  const scriptEvent = process.env.npm_lifecycle_event;
@@ -60,16 +62,23 @@ const { title: projectTitle } = fs.existsSync(targetProjectSettingsJS) ? require
60
62
 
61
63
  const isExistTargetProjectVersionConfig = fs.existsSync(targetProjectVersionConfigPath); // 安装依赖项目下是否存在旧版本控制文件
62
64
  const isExistVueConfigFile = fs.existsSync(targetProjectVueConfigPath); // 安装依赖项目下是否存在vue.config.js文件
65
+ const hasNextConfig = !isExistVueConfigFile && ( // Next.js 项目检测
66
+ fs.existsSync(targetProjectFileResolve("next.config.js")) ||
67
+ fs.existsSync(targetProjectFileResolve("next.config.mjs")) ||
68
+ fs.existsSync(targetProjectFileResolve("next.config.ts"))
69
+ );
63
70
  const isMaster = currentBranch === "master"; // 是否在master分支
64
71
  const isPkg = versionFileName === "package.json";
65
72
 
66
73
  const targetProjectVueConfig = isExistVueConfigFile ? require(targetProjectVueConfigPath) : {};
67
- const { outputDir: targetProjectOutputDir, configureWebpack } = targetProjectVueConfig || {};
74
+ const { outputDir: vueOutputDir, configureWebpack } = targetProjectVueConfig || {};
75
+ let targetProjectOutputDir = vueOutputDir;
68
76
 
69
77
  const { updateDevText = "测试环境" } = { master: { updateDevText: "正式环境" } }[currentBranch] || {}; // 更新环境和处理分支
70
78
 
71
79
  const configPath = path.resolve(projectRoot, versionFileName);
72
80
  let buildConfig = JSON.parse(fs.readFileSync(configPath, "utf-8")) || {};
81
+ let tempPlatformName = "";
73
82
 
74
83
  buildConfig = normalizeBuildConfig(buildConfig, npmPackageConfigKey, currentBranch, projectTitle);
75
84
 
@@ -89,12 +98,112 @@ const {
89
98
  enableClipboard, // 启用粘贴板
90
99
  disableUpdateVersionEnv // 禁止更新版本信息环境
91
100
  } = buildConfigs || {};
101
+ // Next.js 项目:优先使用 infly.buildConfigs.outputPath
102
+ if (!targetProjectOutputDir && outputPath) {
103
+ targetProjectOutputDir = outputPath;
104
+ }
105
+ if (targetProjectOutputDir && !path.isAbsolute(targetProjectOutputDir)) {
106
+ targetProjectOutputDir = path.resolve(projectRoot, targetProjectOutputDir);
107
+ }
92
108
  const buildFoldName = zipBuildFoldName || targetProjectOutputDir || "dist";
93
- const { mainVersion: verMainVersion, platformName, baseName, versionList = [], links } = versionConfig || {};
109
+ const { mainVersion: verMainVersion, baseName, versionList = [], links } = versionConfig || {};
94
110
  const mainVersion = verMainVersion || major; // 主版本号
95
111
  const [lastestVersionItem] = versionList || [];
96
112
  const { lastVersion = projectVersion || "1.0.0" } = lastestVersionItem || {};
97
113
 
114
+ function getBuildContext() {
115
+ try {
116
+ return JSON.parse(process.env.INFLY_BUILD_CONTEXT || "{}");
117
+ } catch {
118
+ return {};
119
+ }
120
+ }
121
+
122
+ const buildContext = getBuildContext();
123
+
124
+ function hasArg(name) {
125
+ return process.argv.includes(name);
126
+ }
127
+
128
+ function appendBatchWebhookRecord(publishText, extraParams = {}) {
129
+ const batchWebhookFile = buildContext.batchWebhookFile || process.env.INFLY_BATCH_WEBHOOK_FILE;
130
+
131
+ if (!batchWebhookFile) {
132
+ return false;
133
+ }
134
+
135
+ fs.appendFileSync(batchWebhookFile, `${JSON.stringify({ publishText, extraParams })}\n`);
136
+ return true;
137
+ }
138
+
139
+ function getArgValue(name) {
140
+ const index = process.argv.indexOf(name);
141
+ return index >= 0 ? process.argv[index + 1] : "";
142
+ }
143
+
144
+ function getNextStandaloneServerPath(distPath) {
145
+ const rootServerPath = path.join(distPath, "server.js");
146
+ const workspaceServerPath = path.join(distPath, "apps", projectName, "server.js");
147
+
148
+ if (fs.existsSync(rootServerPath)) {
149
+ return rootServerPath;
150
+ }
151
+
152
+ return workspaceServerPath;
153
+ }
154
+
155
+ function getBuildMode() {
156
+ const modeArg = getArgValue("--mode");
157
+ const lifecycleText = [process.env.npm_lifecycle_event, process.env.npm_lifecycle_script, ...process.argv]
158
+ .filter(Boolean)
159
+ .join(" ");
160
+
161
+ if (modeArg === "staging" || lifecycleText.includes("build:stage") || lifecycleText.includes("--mode staging")) {
162
+ return "stage";
163
+ }
164
+
165
+ if (
166
+ modeArg === "production" ||
167
+ modeArg === "prod" ||
168
+ lifecycleText.includes("build:prod") ||
169
+ lifecycleText.includes("build:pro")
170
+ ) {
171
+ return "prod";
172
+ }
173
+
174
+ return "";
175
+ }
176
+
177
+ function getStageBranch(branchMap = {}, branch = currentBranch) {
178
+ if (branch !== "master" && branchMap[branch] && branchMap[branch] !== "master") {
179
+ return branch;
180
+ }
181
+
182
+ if (branchMap.develop && branchMap.develop !== "master") {
183
+ return "develop";
184
+ }
185
+
186
+ if (branchMap.release && branchMap.release !== "master") {
187
+ return "release";
188
+ }
189
+
190
+ return Object.keys(branchMap).find((key) => branchMap[key] && branchMap[key] !== "master") || branch;
191
+ }
192
+
193
+ function getBuildTargetBranch(branchMap = {}) {
194
+ const buildMode = getBuildMode();
195
+
196
+ if (buildMode === "prod") {
197
+ return "master";
198
+ }
199
+
200
+ if (buildMode === "stage") {
201
+ return getStageBranch(branchMap);
202
+ }
203
+
204
+ return currentBranch;
205
+ }
206
+
98
207
  async function init() {
99
208
  try {
100
209
  // validateConfig(buildConfig);
@@ -109,7 +218,7 @@ async function init() {
109
218
 
110
219
  // 处理所需版本文件信息
111
220
  const timestamp = new Date().toISOString().slice(0, 10).replace(/-/g, ".");
112
- const baseFileName = `${platformName}-${buildFoldName}-${baseName}`;
221
+ const baseFileName = `${tempPlatformName}-${buildFoldName}-${baseName}`;
113
222
  const newVersion = isMaster ? incrementVersion(lastVersion, mainVersion) : lastVersion; // 非正式环境构建不更新版本信息
114
223
  const newFileName = baseFileName.replace("{version}", newVersion).replace("{timestamp}", timestamp);
115
224
  const gitInfo = getLatestCommitInfo() || {};
@@ -118,7 +227,7 @@ async function init() {
118
227
  if (typeof tempLink === "object") {
119
228
  tempLink = tempLink[process.env.VUE_APP_PLATFORM] || tempLink["DEFAULT"] || JSON.stringify(tempLink);
120
229
  }
121
- const publishText = `${platformName}:\n更新到:${tempLink}\n更新时间:${timestamp}\n版本号:v${newVersion}\n分支:${branch}\n更新环境:${updateDevText}\n更新内容:\n${commitMsg}`;
230
+ const publishText = `${tempPlatformName}:\n更新到:${tempLink}\n更新时间:${timestamp}\n版本号:v${newVersion}\n分支:${branch}\n更新环境:${updateDevText}\n更新内容:\n${commitMsg}`;
122
231
  const newZipFileInfo = [
123
232
  {
124
233
  version: newVersion,
@@ -134,11 +243,12 @@ async function init() {
134
243
  const outputDir = path.resolve(projectRoot, "./", outputPath);
135
244
  const outputPathFull = path.join(outputDir, newFileName);
136
245
  const distPath = gitAutoPushRepos ? targetProjectOutputDir : path.resolve(projectRoot, "./" + buildFoldName);
137
- const indexHtmlPath = path.join(distPath, "index.html");
246
+ // Next.js standalone 项目检查 server.js,Vue/SPA 项目检查 index.html
247
+ const validatePath = hasNextConfig ? getNextStandaloneServerPath(distPath) : path.join(distPath, "index.html");
138
248
 
139
249
  // 校验构建文件是否存在,确保构建成功
140
250
  validateFileExists(distPath, "distPath");
141
- validateFileExists(indexHtmlPath, "indexHtmlPath");
251
+ validateFileExists(validatePath, hasNextConfig ? "serverJsPath" : "indexHtmlPath");
142
252
 
143
253
  // 非自动推送到构建仓库,进行构建文件压缩和检查是否压缩成功
144
254
  if (!gitAutoPushRepos) {
@@ -162,6 +272,8 @@ async function init() {
162
272
  gitInfo,
163
273
  gitAutoCommitText,
164
274
  gitAutoPushReposBranchMap,
275
+ gitLockDir: buildContext.gitLockDir,
276
+ gitProcessOrder: buildContext.gitProcessOrder,
165
277
  ...checkGitStatusParams
166
278
  });
167
279
  }
@@ -175,17 +287,21 @@ async function init() {
175
287
  }
176
288
 
177
289
  if (webhookUrl) {
178
- postVersionFileAndMsg(publishText, {
290
+ const webhookParams = {
179
291
  projectName,
180
292
  newFileName,
181
293
  gitInfo,
182
294
  targetProjectOutputDir,
183
295
  repos: path.relative(__dirname, targetProjectOutputDir).replace(/^(\.\.\\){4}apps\\/, ""),
184
296
  ...buildConfigs
185
- });
297
+ };
298
+
299
+ if (!appendBatchWebhookRecord(publishText, webhookParams)) {
300
+ postVersionFileAndMsg(publishText, webhookParams);
301
+ }
186
302
  }
187
303
 
188
- if (enablePreview) {
304
+ if (enablePreview && buildContext.skipPreview !== true && process.env.INFLY_SKIP_PREVIEW !== "1") {
189
305
  await previewInit(true);
190
306
  }
191
307
  } catch (error) {
@@ -216,17 +332,14 @@ function normalizeBuildConfig(config, packageKey, branch, title) {
216
332
  }
217
333
 
218
334
  // 处理平台名称配置
219
- if (typeof normalizedConfig?.versionConfig?.platformName === "object") {
220
- normalizedConfig.versionConfig.platformName =
221
- normalizedConfig.versionConfig.platformName[branch] ||
222
- normalizedConfig.versionConfig.platformName["master"] ||
223
- "构建平台";
224
- }
225
-
226
- // 使用项目标题作为默认平台名称
227
- if (title && !normalizedConfig.versionConfig?.platformName) {
228
- normalizedConfig.versionConfig = normalizedConfig.versionConfig || {};
229
- normalizedConfig.versionConfig.platformName = title;
335
+ const platformName = normalizedConfig?.versionConfig?.platformName;
336
+ if (typeof platformName === "object") {
337
+ tempPlatformName = platformName[branch] || platformName["master"] || "构建平台";
338
+ } else if (typeof platformName === "string" && platformName) {
339
+ tempPlatformName = platformName;
340
+ } else if (title) {
341
+ // 使用项目标题作为默认平台名称
342
+ tempPlatformName = title;
230
343
  }
231
344
 
232
345
  return normalizedConfig;
@@ -268,31 +381,42 @@ function askUserConfirmation(message, defaultYes = false) {
268
381
  * 校验配置文件
269
382
  * @param {Object} buildConfig
270
383
  */
271
- async function validateConfig(buildConfig) {
384
+ async function validateConfig(buildConfig, targetBranch = currentBranch) {
272
385
  if (!buildConfig) {
273
386
  console.error(global.logColor.error, `❌ ZIP压缩已禁用,版本控制文件${versionFileName}配置错误`);
274
387
  process.exit(1);
275
388
  }
276
389
 
277
390
  if (buildConfig?.buildConfigs?.enabled === false) {
278
- console.warn(global.logColor.error, `⚠️ ZIP压缩已禁用,版本控制文件${versionFileName}中的enabled属性设置为false`);
391
+ console.warn(
392
+ global.logColor.error,
393
+ `⚠️ ZIP压缩已禁用,版本控制文件${versionFileName}中的 enabled 属性设置为 false`
394
+ );
279
395
  process.exit(0);
280
396
  }
281
397
 
282
- if (!buildConfig?.buildConfigs?.gitAutoPushReposBranchMap[currentBranch]) {
398
+ if (!buildConfig?.buildConfigs?.gitAutoPushReposBranchMap[targetBranch]) {
283
399
  if (![testScript].includes(scriptEvent)) {
284
- console.error(global.logColor.error, `❌ 当前分支非gitAutoPushReposBranchMap配置可构建分支,请检查`);
400
+ console.error(
401
+ global.logColor.error,
402
+ `❌ 目标分支 ${targetBranch} 非 gitAutoPushReposBranchMap 配置可构建分支,请检查`
403
+ );
285
404
  process.exit(1);
286
405
  }
287
406
  }
288
407
 
289
- if (currentBranch === "master" && !process.env.npm_lifecycle_event.includes("prod")) {
290
- console.error(global.logColor.error, `❌ 当前分支为 master 分支,请使用正式环境构建命令进行构建`);
408
+ const buildMode = getBuildMode();
409
+ const lifecycleEvent = process.env.npm_lifecycle_event || "";
410
+ const isProdBuild = buildMode === "prod" || lifecycleEvent.includes("prod");
411
+ const isStageBuild = buildMode === "stage" || lifecycleEvent.includes("stage");
412
+
413
+ if (targetBranch === "master" && !isProdBuild) {
414
+ console.error(global.logColor.error, `❌ 目标分支为 master 分支,请使用正式环境构建命令进行构建`);
291
415
  process.exit(1);
292
416
  }
293
417
 
294
- if (currentBranch !== "master" && !process.env.npm_lifecycle_event.includes("stage")) {
295
- console.warn(global.logColor.warning, `⚠️ 当前分支为 ${currentBranch} 分支,建议使用测试环境构建命令`);
418
+ if (targetBranch !== "master" && !isStageBuild) {
419
+ console.warn(global.logColor.warning, `⚠️ 目标分支为 ${targetBranch} 分支,建议使用测试环境构建命令`);
296
420
  console.log(global.logColor.info, `推荐命令: npm run infly:build:stage`);
297
421
 
298
422
  const shouldContinue = await askUserConfirmation("确定要继续当前构建吗?", false);
@@ -303,7 +427,6 @@ async function validateConfig(buildConfig) {
303
427
  }
304
428
  }
305
429
  }
306
-
307
430
  /**
308
431
  * 校验文件是否存在
309
432
  * @param {String} checkPath - 检查路径
@@ -320,6 +443,13 @@ function validateFileExists(checkPath, logKey) {
320
443
  indexHtmlPath: {
321
444
  error: "index.html文件不存在,请检查构建配置"
322
445
  },
446
+ serverJsPath: {
447
+ error: `server.js文件不存在,请检查 Next.js standalone 构建配置。支持 server.js 或 ${path.join(
448
+ "apps",
449
+ projectName,
450
+ "server.js"
451
+ )}`
452
+ },
323
453
  outputPathFull: {
324
454
  error: "压缩文件没有成功创建,请检查构建配置",
325
455
  success: `压缩完成,已成功创建文件`,
@@ -385,11 +515,14 @@ function createVersionMap(versionList = []) {
385
515
  * @param {Boolean} disableUpdateVersionEnv - 禁用环境配置
386
516
  */
387
517
  function checkIsDisableUpdateVersionEnv(disableUpdateVersionEnv = []) {
388
- let isDisableUpdateVersionEnv = process.env.npm_lifecycle_script.includes(`--mode staging`); // 默认禁用测试环境更新版本
518
+ const lifecycleText = [process.env.npm_lifecycle_event, process.env.npm_lifecycle_script, ...process.argv]
519
+ .filter(Boolean)
520
+ .join(" ");
521
+ let isDisableUpdateVersionEnv = lifecycleText.includes(`--mode staging`); // 默认禁用测试环境更新版本
389
522
 
390
523
  if (Array.isArray(disableUpdateVersionEnv) && disableUpdateVersionEnv.length > 0) {
391
524
  disableUpdateVersionEnv.forEach((item) => {
392
- if (process.env.npm_lifecycle_script.includes(`--mode ${item}`)) {
525
+ if (lifecycleText.includes(`--mode ${item}`)) {
393
526
  isDisableUpdateVersionEnv = disableUpdateVersionEnv.includes(item);
394
527
  }
395
528
  });
@@ -405,7 +538,14 @@ function checkIsDisableUpdateVersionEnv(disableUpdateVersionEnv = []) {
405
538
  */
406
539
  function updateVersionList(zipFiles = [], extraParams) {
407
540
  const { opt = "update", buildConfig, configPath } = extraParams || {};
408
- const { versionConfig } = buildConfig || {};
541
+ let { versionConfig } = buildConfig || {};
542
+ if (buildConfig && !versionConfig) {
543
+ buildConfig.versionConfig = {};
544
+ versionConfig = buildConfig.versionConfig;
545
+ }
546
+ if (versionConfig && !Array.isArray(versionConfig.versionList)) {
547
+ versionConfig.versionList = [];
548
+ }
409
549
  const { versionList = [] } = versionConfig || {};
410
550
  const { disableUpdateVersionEnv } = versionConfig || {};
411
551
  const isDisableUpdateVersionEnv = checkIsDisableUpdateVersionEnv(disableUpdateVersionEnv);
@@ -426,7 +566,10 @@ function updateVersionList(zipFiles = [], extraParams) {
426
566
  if (!versionMap[fileName] && Array.isArray(versionList)) {
427
567
  allVersionExist = false;
428
568
  buildConfig.versionConfig.versionList.unshift(singleVersionInfo);
429
- console.log(global.logColor.success, `✅ 新版本${version}写入${versionFileName}文件更新成功`);
569
+ const updateText = isDisableUpdateVersionEnv
570
+ ? `✅ 新版本${version}已生成,当前环境跳过写入${versionFileName}`
571
+ : `✅ 新版本${version}写入${versionFileName}文件更新成功`;
572
+ console.log(global.logColor.success, updateText);
430
573
  }
431
574
  // 如果是更新,压缩脚本进行打包则删除全部旧文件
432
575
  if (isBuilZipScript && opt === "update") {
@@ -561,7 +704,7 @@ function copyToClipboard(text) {
561
704
  */
562
705
  function scriptInit() {
563
706
  let tempInflyConfig = {};
564
- if (!isExistVueConfigFile || !fs.existsSync(targetProjectPackageJSON)) {
707
+ if ((!isExistVueConfigFile && !hasNextConfig) || !fs.existsSync(targetProjectPackageJSON)) {
565
708
  return;
566
709
  }
567
710
  scriptWrite(targetProjectPackageJSON, buildList);
@@ -596,7 +739,7 @@ function scriptInit() {
596
739
  * @returns
597
740
  */
598
741
  function copyVersionConfigFile() {
599
- if (!isExistVueConfigFile) {
742
+ if (!isExistVueConfigFile && !hasNextConfig) {
600
743
  return;
601
744
  }
602
745
  const { name: projectTitle } = configureWebpack || {};
@@ -625,7 +768,7 @@ function copyVersionConfigFile() {
625
768
  tempVersionConfig.buildConfigs.buildFoldName = targetProjectOutputDir;
626
769
  }
627
770
 
628
- if (projectTitle) {
771
+ if (projectTitle && !tempVersionConfig.versionConfig?.platformName) {
629
772
  tempVersionConfig.versionConfig.platformName = projectTitle;
630
773
  }
631
774
 
@@ -652,22 +795,44 @@ function copyVersionConfigFile() {
652
795
  * 构建前分支处理
653
796
  */
654
797
  async function beforeBuild() {
655
- // 1. 先进行配置校验,如果用户取消则阻塞后续流程
656
- await validateConfig(buildConfig);
798
+ const targetBranch = getBuildTargetBranch(gitAutoPushReposBranchMap);
799
+
800
+ await validateConfig(buildConfig, targetBranch);
801
+
802
+ if (
803
+ hasArg("--check-only") ||
804
+ buildContext.checkOnly === true ||
805
+ (process.env.INFLY_SKIP_BRANCH_UPDATE === "1" && process.env.INFLY_SKIP_PACKAGES_UPDATE === "1")
806
+ ) {
807
+ return;
808
+ }
809
+
810
+ const currentProjectStatus = checkSingleDirGitStatus(projectRoot, projectName);
811
+
812
+ if (currentProjectStatus.hasUncommitted) {
813
+ console.log(global.logColor.error, `\n❌ 当前项目存在未提交的更改,请先提交或暂存后再继续构建`);
814
+ process.exit(1);
815
+ }
816
+
817
+ const currentProjectUpdateResult = pullSingleDirFromBranch(projectRoot, projectName, targetBranch);
818
+
819
+ if (!currentProjectUpdateResult.success) {
820
+ console.log(global.logColor.error, `\n❌ 当前项目切换到 ${targetBranch} 分支失败,请检查`);
821
+ process.exit(1);
822
+ }
657
823
 
658
- // 2. 执行分支切换和拉取操作
659
824
  await autoBranchProcess({
660
825
  gitAutoPushRepos,
661
826
  gitAutoPushReposBranchMap,
662
- currentBranch,
827
+ currentBranch: targetBranch,
663
828
  targetProjectOutputDir,
664
- validateConfig: () => {} // 配置验证已经在上面完成
829
+ validateConfig: () => {}
665
830
  });
666
831
 
667
- // 3. 检查和更新 packages 下的模块(如果启用了此功能)
668
- await checkAndUpdatePackages();
832
+ if (process.env.INFLY_SKIP_PACKAGES_UPDATE !== "1") {
833
+ await checkAndUpdatePackages(undefined, "master");
834
+ }
669
835
  }
670
-
671
836
  module.exports = {
672
837
  init,
673
838
  scriptInit,
@@ -138,10 +138,19 @@ function configureWebpack(extraConfig = {}) {
138
138
  /**
139
139
  * chainWebpack配置
140
140
  */
141
- function chainWebpack(config) {
141
+ function chainWebpack(config, options = {}) {
142
+ const { htmlPluginOptions = {} } = options || {};
143
+
142
144
  config.plugins.delete("preload");
143
145
  config.plugins.delete("prefetch");
144
146
 
147
+ if (Object.keys(htmlPluginOptions).length) {
148
+ config.plugin("html").tap((args) => {
149
+ const originalOptions = args[0] || {};
150
+ return [{ ...originalOptions, ...htmlPluginOptions }];
151
+ });
152
+ }
153
+
145
154
  // 强制禁用 modern mode(staging 环境)
146
155
  if (ENV.IS_STAGING) {
147
156
  // 删除 @vue/cli-service 的 modern mode 相关插件
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+
3
+ const assert = require("node:assert/strict");
4
+ const test = require("node:test");
5
+ const { chainWebpack } = require("./webpack.base");
6
+
7
+ function createChainConfig() {
8
+ let htmlPluginOptions;
9
+ const chain = new Proxy(
10
+ function () {},
11
+ {
12
+ get(_target, property) {
13
+ if (property === "plugin") {
14
+ return (name) => ({
15
+ tap(callback) {
16
+ if (name === "html") {
17
+ [htmlPluginOptions] = callback([htmlPluginOptions || {}]);
18
+ }
19
+ return this;
20
+ },
21
+ use() {
22
+ return this;
23
+ }
24
+ });
25
+ }
26
+
27
+ return chain;
28
+ },
29
+ apply() {
30
+ return chain;
31
+ }
32
+ }
33
+ );
34
+
35
+ return {
36
+ config: chain,
37
+ getHtmlPluginOptions: () => htmlPluginOptions
38
+ };
39
+ }
40
+
41
+ test("chainWebpack 默认不增加 HTML 插件参数", () => {
42
+ const { config, getHtmlPluginOptions } = createChainConfig();
43
+
44
+ chainWebpack(config);
45
+
46
+ assert.equal(getHtmlPluginOptions()?.faviconPath, undefined);
47
+ });
48
+
49
+ test("chainWebpack 合并调用方传入的 HTML 插件参数", () => {
50
+ const { config, getHtmlPluginOptions } = createChainConfig();
51
+
52
+ chainWebpack(config, {
53
+ htmlPluginOptions: {
54
+ faviconPath: "favicon_xzya.ico"
55
+ }
56
+ });
57
+
58
+ assert.equal(getHtmlPluginOptions()?.faviconPath, "favicon_xzya.ico");
59
+ });