| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- #!/usr/bin/env node
- /**
- * scripts/vendor.mjs —— 把 lit 系依赖 vendor 到 lib/vendor/(方案 B:本地兜底)。
- *
- * 为什么 vendor:Repose 依赖仓(/npm/importmap/lit-v3.json)在 repose.fmode.cn /
- * kangshifu.fmode.cn / app.fmode.cn 三个域名实测都是 404,见 README「依赖走哪条路」。
- *
- * 做的事:
- * 1. npm pack 每个包(不 npm install,不留 node_modules)
- * 2. 解到 lib/vendor/<name>/v<version>/,去掉 .ts / .js.map / src / development / node 等非运行时目录
- * 3. 校验每个包的 package.json main 指向的入口文件真实存在
- *
- * 可重复执行:先删后写,结果由 VENDOR 表唯一决定。
- * 用法:node scripts/vendor.mjs [--offline <tgz目录>]
- */
- import { execFileSync } from 'node:child_process';
- import { mkdtempSync, rmSync, mkdirSync, readFileSync, existsSync, cpSync, readdirSync, statSync } from 'node:fs';
- import { tmpdir } from 'node:os';
- import { join, dirname } from 'node:path';
- import { fileURLToPath } from 'node:url';
- export const VENDOR = [
- { name: 'lit', version: '3.3.3' },
- { name: 'lit-html', version: '3.3.3' },
- { name: 'lit-element', version: '4.2.2' },
- { name: '@lit/reactive-element', version: '2.1.2' },
- { name: '@lit/context', version: '1.1.6' },
- { name: '@lit-labs/signals', version: '0.3.0' },
- { name: 'signal-polyfill', version: '0.2.2' },
- ];
- const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
- const OUT = join(ROOT, 'lib/vendor');
- /** 运行时用不到的目录/文件:源码、类型、调试版、Node 专用实现 */
- const DROP = [
- /\/development\//, /\/node\//, /\/src\//, /\/decorators\//, /\/test\//,
- /\.ts$/, /\.d\.ts$/, /\.js\.map$/, /\.tsbuildinfo$/, /\/cjs\//,
- ];
- const offlineIdx = process.argv.indexOf('--offline');
- const offlineDir = offlineIdx > -1 ? process.argv[offlineIdx + 1] : null;
- function tgzName(name, version) {
- return `${name.replace('/', '-').replace('@', '')}-${version}.tgz`;
- }
- function findTgz(name, version, dir) {
- const direct = join(dir, `${name.replace(/^@/, '').replace('/', '-')}-${version}.tgz`);
- if (existsSync(direct)) return direct;
- const fallback = join(dir, tgzName(name, version));
- if (existsSync(fallback)) return fallback;
- return null;
- }
- const work = mkdtempSync(join(tmpdir(), 'kf-vendor-'));
- let failed = 0;
- rmSync(OUT, { recursive: true, force: true });
- mkdirSync(OUT, { recursive: true });
- for (const pkg of VENDOR) {
- const id = `${pkg.name}@${pkg.version}`;
- let tgz = offlineDir ? findTgz(pkg.name, pkg.version, offlineDir) : null;
- if (!tgz) {
- // 不带路径输出,避免把文件落在 cwd
- const fetched = execFileSync('npm', ['pack', id, '--silent', '--pack-destination', work], { encoding: 'utf8' }).trim().split('\n').pop();
- tgz = join(work, fetched);
- }
- const stage = join(work, pkg.name.replace(/[/@]/g, '_') + '-' + pkg.version);
- mkdirSync(stage, { recursive: true });
- execFileSync('tar', ['xzf', tgz, '-C', stage]);
- const dest = join(OUT, pkg.name, `v${pkg.version}`);
- mkdirSync(dest, { recursive: true });
- cpSync(join(stage, 'package'), dest, {
- recursive: true,
- filter: (src) => {
- if (!src.startsWith(stage)) return true;
- const rel = '/' + src.slice(join(stage, 'package').length).replace(/^[/\\]/, '').replace(/\\/g, '/');
- return !DROP.some((re) => re.test(rel + '/'));
- },
- });
- const pj = JSON.parse(readFileSync(join(dest, 'package.json'), 'utf8'));
- if (pj.version !== pkg.version) {
- console.error(`✗ ${id}: 包内版本是 ${pj.version}`);
- failed++;
- continue;
- }
- // 入口文件必须存在(importmap 指向的就是它)
- const entries = new Set();
- const ex = pj.exports?.['.'];
- if (typeof ex === 'string') entries.add(ex);
- else if (ex?.import?.default) entries.add(ex.import.default);
- else if (ex?.default) entries.add(ex.default);
- if (pj.main) entries.add(pj.main);
- const missing = [...entries].filter((e) => !existsSync(join(dest, e)));
- if (missing.length) {
- console.error(`✗ ${id}: 入口不存在 ${missing.join(', ')}`);
- failed++;
- continue;
- }
- const size = du(dest);
- console.log(`✓ ${id} → lib/vendor/${pkg.name}/v${pkg.version}/ (${entries.values().next().value}, ${size})`);
- }
- rmSync(work, { recursive: true, force: true });
- console.log(failed ? `\nVENDOR FAILED(${failed})` : '\nVENDOR OK');
- process.exit(failed ? 1 : 0);
- function du(dir) {
- let n = 0;
- for (const e of readdirSync(dir)) {
- const p = join(dir, e);
- const s = statSync(p);
- n += s.isDirectory() ? du(p) : s.size;
- }
- return `${Math.round(n / 1024) || "<1"} KB`;
- }
|