@flun/node-mobile-app 3.1.4 → 4.0.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.
@@ -1,6 +1,7 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { createRequire } from 'module';
4
+ import chalk from 'chalk';
4
5
 
5
6
  const require = createRequire(import.meta.url), subpath = (...parts) => './' + path.posix.join(...parts),
6
7
  BUNDLED_DIR = 'bundled', NM_DIR = 'node_modules', PKG_JSON = 'package.json',
@@ -190,8 +191,8 @@ const require = createRequire(import.meta.url), subpath = (...parts) => './' + p
190
191
  if (excludePkgs.has(relName)) { skipped++; continue; }
191
192
  if (SKIP_PKGS.has(relName)) { skipped++; continue; }
192
193
  if (hasNativeModule(pkgDir)) { skipped++; continue; }
193
- // 删除安装期脚本字段:运行时无安装期,且 Gradle npm rebuild 会触发脚本导致失败
194
- // 原生模块包已在上一步跳过(其 scripts 是编译必需,必须保留)
194
+ // 删除安装期脚本字段:运行时无安装期,且 Gradle npm rebuild 会触发脚本导致失败
195
+ // 原生模块包已在上一步跳过(其 scripts 是编译必需,必须保留)
195
196
  if (j.scripts) { delete j.scripts; fs.writeFileSync(pj, JSON.stringify(j, null, 2)); }
196
197
  if (countJS(pkgDir) <= 1) { skipped++; continue; }
197
198
  // 已优化过的包跳过
@@ -230,7 +231,7 @@ const require = createRequire(import.meta.url), subpath = (...parts) => './' + p
230
231
  }
231
232
  if (isESM) newExports[e.key] = subpath(BUNDLED_DIR, outName);
232
233
  else {
233
- // CJS 包:若 bundle 末尾是 module.exports = require_xxx()(整体赋值),
234
+ // CJS 包:若 bundle 末尾是 module.exports = require_xxx()(整体赋值),
234
235
  // cjs-module-lexer 静态分析拿不到命名导出,此时定位主入口的 __commonJS 块,
235
236
  // 块内抓 exports.X = 形式,追加显式声明让 lexer 识别;
236
237
  try {
@@ -312,12 +313,12 @@ const require = createRequire(import.meta.url), subpath = (...parts) => './' + p
312
313
  walkDel(pkgDir), totalDeleted += deleted, merged++;
313
314
  if (resJsHits && resJsHits.size > 0 && resLog)
314
315
  for (const [k, v] of resJsHits) resLog.push(` ${relName}: ${k} (${v} 个 JS)`);
315
- if (process.env.OPTIMIZE_DEBUG) console.log(` ✓ ${relName} (${parse.entries.length} 入口)`);
316
+ if (process.env.OPTIMIZE_DEBUG) console.log(chalk.gray(` ✓ ${relName} (${parse.entries.length} 入口)`));
316
317
  }
317
318
 
318
319
  if (resLog && resLog.length > 0) {
319
- console.log(' 处理保留的资源 JS(被引用则合并,否则删除):');
320
- for (const line of resLog) console.log(line);
320
+ console.log(chalk.gray(' 处理保留的资源 JS(被引用则合并,否则删除):'));
321
+ for (const line of resLog) console.log(chalk.gray(line));
321
322
  }
322
323
  return { merged, skipped, totalDeleted };
323
324
  },
@@ -399,12 +400,12 @@ const require = createRequire(import.meta.url), subpath = (...parts) => './' + p
399
400
  if (cnt > 0) cleared += cnt, pkgItems.push(`${item}(${cnt})`);
400
401
  }
401
402
  }
402
- if (process.env.OPTIMIZE_DEBUG && pkgItems.length > 0) console.log(` ✓ ${pkgRel}: ${pkgItems.join(', ')}`);
403
+ if (process.env.OPTIMIZE_DEBUG && pkgItems.length > 0) console.log(chalk.gray(` ✓ ${pkgRel}: ${pkgItems.join(', ')}`));
403
404
  }
404
405
  return cleared;
405
406
  },
406
407
  // ==================== 清平台 ====================
407
- prunePlatform = async (nmDir, myPlat, myArch) => {
408
+ prunePlatform = async (nmDir, myPlat, myArch, targetPlatform) => {
408
409
  let removed = 0;
409
410
  const readHead = file => {
410
411
  let fd;
@@ -463,13 +464,16 @@ const require = createRequire(import.meta.url), subpath = (...parts) => './' + p
463
464
  return null;
464
465
  },
465
466
  delFile = p => {
466
- try { fs.unlinkSync(p), removed++; } catch { }
467
+ try { fs.statSync(p).isDirectory() ? fs.rmSync(p, { recursive: true, force: true }) : fs.unlinkSync(p), removed++; } catch { }
467
468
  },
468
469
  processDir = d => {
469
470
  let entries;
470
471
  try { entries = fs.readdirSync(d, { withFileTypes: true }); } catch { return; }
471
472
  for (const e of entries) {
472
473
  const full = path.join(d, e.name);
474
+ const expectedPrebuilds = targetPlatform === 'ios' ? ['darwin'] : ['android'],
475
+ prebuildMatch = full.match(/[\\/]prebuilds[\\/](linux|darwin|win32|android)-/i);
476
+ if (prebuildMatch && !expectedPrebuilds.includes(prebuildMatch[1].toLowerCase())) { delFile(full); continue; }
473
477
  if (e.isDirectory()) { processDir(full); continue; }
474
478
  if (JS_RE.test(e.name)) continue;
475
479
  let plat = suffixPlat(e.name), arch = null;
@@ -482,7 +486,7 @@ const require = createRequire(import.meta.url), subpath = (...parts) => './' + p
482
486
  if (platBad || archBad) {
483
487
  if (process.env.OPTIMIZE_DEBUG) {
484
488
  const rel = toPosix(path.relative(nmDir, full));
485
- console.log(` ✓ ${rel} (${platBad ? '平台不符: ' + plat : '架构不符: ' + arch})`);
489
+ console.log(chalk.gray(` ✓ ${rel} (${platBad ? '平台不符: ' + plat : '架构不符: ' + arch})`));
486
490
  }
487
491
  delFile(full);
488
492
  }
@@ -492,21 +496,19 @@ const require = createRequire(import.meta.url), subpath = (...parts) => './' + p
492
496
  return removed;
493
497
  },
494
498
  // ==================== 清开发文件 ====================
495
- pruneDevFiles = async (nmDir, nativePkgs) => {
499
+ pruneDevFiles = async (nmDir) => {
496
500
  let deleted = 0;
497
501
  const PATTERNS = [
498
502
  /(^|\/)tsconfig\.json$/,
499
503
  /(^|\/)\.nycrc(\.(json|yml))?$/,
500
504
  /(^|\/)\.editorconfig$/, /(^|\/)\.prettierignore$/, /(^|\/)\.eslintignore$/,
501
505
  /(^|\/)\.dockerignore$/, /(^|\/)\.gitignore$/, /(^|\/)\.gitattributes$/, /(^|\/)\.npmignore$/,
502
- /\.(md|markdown)$/i, /\.(gyp|gypi)$/i, /\.(yml|yaml)$/i, /\.(h|c)$/,
503
- /\.d\.ts$/, /\.map$/, /metafile-.*\.json$/,
506
+ /\.(md|markdown)$/i, /\.(yml|yaml)$/i, /\.(gyp|gypi|h|hh|hpp|c|cc|cpp|cxx|m|mm)$/i,
507
+ /\.map$/, /metafile-.*\.json$/,
504
508
  /(^|\/)\.eslintrc(\.(json|yml|js|cjs))?$/, /(^|\/)\.babelrc(\.(json|js))?$/,
505
509
  /(^|\/)package-lock\.json$/, /(^|\/)\.package-lock\.json$/, /(^|\/)yarn\.lock$/,
506
510
  /(^|\/)package-support\.json$/,
507
511
  ], DIR_SKIP = new Set([BUNDLED_DIR]),
508
- COMPILE_EXTS = /\.(gyp|gypi|h|hh|hpp|c|cc|cpp|cxx|m|mm)$/i,
509
- inNativePkg = p => nativePkgs.some(nd => p.startsWith(nd + path.sep)),
510
512
  walk = d => {
511
513
  for (const f of fs.readdirSync(d, { withFileTypes: true })) {
512
514
  const full = path.join(d, f.name);
@@ -519,7 +521,7 @@ const require = createRequire(import.meta.url), subpath = (...parts) => './' + p
519
521
  walk(full);
520
522
  } else {
521
523
  const rel = toPosix(path.relative(nmDir, full));
522
- if (PATTERNS.some(re => re.test(rel)) && !(COMPILE_EXTS.test(f.name) && inNativePkg(full)))
524
+ if (PATTERNS.some(re => re.test(rel)))
523
525
  try { fs.unlinkSync(full), deleted++; } catch { }
524
526
  }
525
527
  }
@@ -529,19 +531,20 @@ const require = createRequire(import.meta.url), subpath = (...parts) => './' + p
529
531
  },
530
532
  pruneIntermediates = async nmDir => {
531
533
  let deleted = 0;
532
- const walk = d => {
533
- for (const f of fs.readdirSync(d, { withFileTypes: true })) {
534
- const full = path.join(d, f.name);
535
- if (f.isDirectory()) walk(full);
536
- else if (f.name.endsWith('.orig')) try { fs.unlinkSync(full), deleted++; } catch { }
537
- }
538
- };
534
+ const MID_RE = /\.(o|d|mk|stamp|Makefile|iobj|ipdb|pdb|exp|lib|obj|vcxproj|tlog|recipe|lastbuildstate|nativecodeanalysis\.xml)$/i,
535
+ walk = d => {
536
+ for (const f of fs.readdirSync(d, { withFileTypes: true })) {
537
+ const full = path.join(d, f.name);
538
+ if (f.isDirectory()) walk(full);
539
+ else if (full.includes(path.sep + 'obj.target' + path.sep) || f.name === 'Makefile' || f.name.endsWith('.orig') || MID_RE.test(f.name)) try { fs.unlinkSync(full), deleted++; } catch { }
540
+ }
541
+ };
539
542
  walk(nmDir);
540
543
  return deleted;
541
544
  },
542
545
  applyFilesRules = async nmDir => {
543
546
  let deleted = 0;
544
- // 1) 删顶层 node 假包(npm 上名为 node 的包,仅提供 node.exe,运行时不需要)
547
+ // 1) 删顶层 node 假包(npm 上名为 node 的包,仅提供 node.exe,运行时不需要)
545
548
  const LICENSE_RE = /^licen[sc]e/i, TS_RE = /\.(ts|cts|mts)$/, nodePkg = path.join(nmDir, 'node');
546
549
  if (fs.existsSync(nodePkg)) try { fs.rmSync(nodePkg, { recursive: true, force: true }), deleted++; } catch { }
547
550
 
@@ -591,7 +594,7 @@ const require = createRequire(import.meta.url), subpath = (...parts) => './' + p
591
594
 
592
595
  // ==================== 导出函数 ====================
593
596
  /**
594
- * 清除快照中的 verified 标记(优化开始或构建失败时调用)
597
+ * 清除快照中的 verified 标记(优化开始或构建失败时调用)
595
598
  * >查看定义:@see {@link clearVerified}
596
599
  * @param {string} snapshotDir 快照目录
597
600
  * @returns {Promise<void>}
@@ -605,7 +608,7 @@ const clearVerified = async snapshotDir => {
605
608
  } catch { }
606
609
  };
607
610
  /**
608
- * 标记快照 verified=true(构建全流程成功后由 build.js / test.js 调用)
611
+ * 标记快照 verified=true(构建全流程成功后由 build.js / test.js 调用)
609
612
  * >查看定义:@see {@link markVerified}
610
613
  * @param {string} snapshotDir 快照目录
611
614
  * @returns {Promise<void>}
@@ -621,14 +624,14 @@ const markVerified = async snapshotDir => {
621
624
  /**
622
625
  * 执行 node_modules 六阶段优化
623
626
  * >查看定义:@see {@link optimizeNodeModules}
624
- * @param {string} tempDir node_modules 所在目录(nodejs-assets/nodejs-project)
627
+ * @param {string} tempDir node_modules 所在目录(nodejs-assets/nodejs-project)
625
628
  * @param {object} [config] 优化配置
626
- * @param {string} [config.snapshotDir] 快照目录(默认同 tempDir)
627
- * @param {string} [config.targetPlatform] 目标平台:'android'(默认)或 'ios'
628
- * @param {string[]} [config.abiFilters] Android 目标架构(默认 ['arm64-v8a']);iOS 固定保留 arm64 + x64
629
- * @param {string} config.runtimeMajor 运行时 Node 主版本号(必填,从 libnode/node_version.h 读取)
629
+ * @param {string} [config.snapshotDir] 快照目录(默认同 tempDir)
630
+ * @param {string} [config.targetPlatform] 目标平台:'android'(默认)或 'ios'
631
+ * @param {string[]} [config.abiFilters] Android 目标架构(默认 ['arm64-v8a']);iOS 固定保留 arm64 + x64
632
+ * @param {string} config.runtimeMajor 运行时 Node 主版本号(必填,从 libnode/node_version.h 读取)
630
633
  * @param {string[]} [config.exclude] 排除的包名列表
631
- * @returns {Promise<object>} 各阶段统计(merged / cleared / platform / devFiles / intermediates / filesRules)
634
+ * @returns {Promise<object>} 各阶段统计(merged / cleared / platform / devFiles / intermediates / filesRules)
632
635
  */
633
636
  const optimizeNodeModules = async (tempDir, config = {}) => {
634
637
  const targetPlatform = config.targetPlatform || 'android', abiFilters = config.abiFilters || ['arm64-v8a'],
@@ -637,49 +640,49 @@ const optimizeNodeModules = async (tempDir, config = {}) => {
637
640
  snapPath = path.join(snapshotDir, SNAPSHOT_FILE), myPlat = TARGET_PLAT_MAP[targetPlatform] || [],
638
641
  myArch = targetPlatform === 'ios' ? IOS_ARCHES : (abiFilters || []).map(a => ABI_ARCH_MAP[a]).filter(Boolean);
639
642
 
640
- if (!runtimeMajor) throw new Error('optimizeNodeModules 缺少 config.runtimeMajor(应从 libnode/node_version.h 读取)');
643
+ if (!runtimeMajor) throw new Error('optimizeNodeModules 缺少 config.runtimeMajor(应从 libnode/node_version.h 读取)');
641
644
  if (!fs.existsSync(nmDir)) {
642
- console.log('[优化] node_modules 不存在,跳过');
645
+ console.log(chalk.gray('[优化] node_modules 不存在,跳过'));
643
646
  return { skipped: true };
644
647
  }
645
648
 
646
649
  await clearVerified(snapshotDir); // 执行优化前清 verified,构建成功后再由 build.js / test.js 写回 true
647
- const t0 = Date.now(), nativePkgs = findPackages(nmDir).filter(p => fs.existsSync(path.join(p, 'binding.gyp')));
650
+ const t0 = Date.now();
648
651
  try {
649
- // 阶段1: 清空资源(跳过 js,留待合并阶段处理)
650
- console.log(' [1/6] 清空复制到项目根的资源...');
652
+ // 阶段1: 清空资源(跳过 js,留待合并阶段处理)
653
+ console.log(chalk.cyan(' [1/6] 清空复制到项目根的资源...'));
651
654
  const c = await clearResources(nmDir, excludePkgs);
652
- console.log(` 清空 ${c} 个文件(js 文件保留,留待合并阶段处理)`);
655
+ console.log(chalk.green(` 清空 ${c} 个文件(js 文件保留,留待合并阶段处理)`));
653
656
 
654
657
  // 阶段2: 合并
655
- console.log(' [2/6] 合并 JS...');
658
+ console.log(chalk.cyan(' [2/6] 合并 JS...'));
656
659
  const m = await mergeAll(nmDir, excludePkgs, runtimeMajor);
657
- console.log(` 合并 ${m.merged} 包,跳过 ${m.skipped},删 ${m.totalDeleted} 个 JS`);
660
+ console.log(chalk.green(` 合并 ${m.merged} 包,跳过 ${m.skipped},删 ${m.totalDeleted} 个 JS`));
658
661
 
659
662
  // 阶段3: 清平台二进制
660
- console.log(' [3/6] 清理非当前平台二进制...');
661
- const p = await prunePlatform(nmDir, myPlat, myArch);
662
- console.log(` 清理 ${p} 项`);
663
+ console.log(chalk.cyan(' [3/6] 清理非当前平台二进制...'));
664
+ const p = await prunePlatform(nmDir, myPlat, myArch, targetPlatform);
665
+ console.log(chalk.green(` 清理 ${p} 项`));
663
666
 
664
667
  // 阶段4: 清开发文件
665
- console.log(' [4/6] 清理开发文件...');
666
- const d = await pruneDevFiles(nmDir, nativePkgs);
667
- console.log(` 清理 ${d} 个文件`);
668
+ console.log(chalk.cyan(' [4/6] 清理开发文件...'));
669
+ const d = await pruneDevFiles(nmDir);
670
+ console.log(chalk.green(` 清理 ${d} 个文件`));
668
671
 
669
672
  // 阶段5: 清中间产物
670
- console.log(' [5/6] 清理中间产物...');
673
+ console.log(chalk.cyan(' [5/6] 清理中间产物...'));
671
674
  const i = await pruneIntermediates(nmDir);
672
- console.log(` 清理 ${i} 个文件`);
675
+ console.log(chalk.green(` 清理 ${i} 个文件`));
673
676
 
674
- // 阶段6: 清除不参与运行的文件(与 build.js 的 files 数组对齐)
675
- console.log(' [6/6] 清除不参与运行的文件和空目录...');
677
+ // 阶段6: 清除不参与运行的文件(与 build.js 的 files 数组对齐)
678
+ console.log(chalk.cyan(' [6/6] 清除不参与运行的文件和空目录...'));
676
679
  const fr = await applyFilesRules(nmDir);
677
- console.log(` 清理 ${fr} 项`);
680
+ console.log(chalk.green(` 清理 ${fr} 项`));
678
681
 
679
682
  // 写 platform/abiFilters/runtimeMajor,同时 verified=false
680
683
  await writeSnapshotFlags(snapshotDir, targetPlatform, abiFilters, runtimeMajor);
681
684
  const elapsed = ((Date.now() - t0) / 1000).toFixed(1);
682
- console.log(`[信息] 优化完成,耗时 ${elapsed}s`);
685
+ console.log(chalk.green(` [信息] 优化完成,耗时 ${elapsed}s`));
683
686
 
684
687
  return { merged: m.merged, cleared: c, platform: p, devFiles: d, intermediates: i, filesRules: fr };
685
688
  } catch (err) {
@@ -689,7 +692,7 @@ const optimizeNodeModules = async (tempDir, config = {}) => {
689
692
  }
690
693
  };
691
694
  /**
692
- * 当前优化文件的 SHA256 前 16 位(缓存指纹:优化代码一改,缓存自动失效)
695
+ * 当前优化文件的 SHA256 前 16 位(缓存指纹:优化代码一改,缓存自动失效)
693
696
  * >查看定义:@see {@link SELF_HASH}
694
697
  */
695
698
  const SELF_HASH = (() => {
@@ -699,4 +702,4 @@ const SELF_HASH = (() => {
699
702
  } catch { return 'unknown'; }
700
703
  })();
701
704
 
702
- export { clearVerified, markVerified, optimizeNodeModules, SELF_HASH };
705
+ export { clearVerified, markVerified, optimizeNodeModules, SELF_HASH };