fix: bundle Linux ARM64 resvg runtime dependency

This commit is contained in:
john
2026-07-12 12:04:02 +08:00
parent 03a79322e4
commit fdc2712084
+35
View File
@@ -1,5 +1,6 @@
#!/usr/bin/env node
import fs from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { spawn } from 'node:child_process';
@@ -16,6 +17,7 @@ const skipBuild = process.argv.includes('--skip-build');
const skipNodeModules = process.argv.includes('--skip-node-modules');
const runtimeNodeTarget = process.env.PORTAL_RUNTIME_NODE_TARGET || 'node24';
const runtimeInstallMode = process.env.PORTAL_RUNTIME_INSTALL_MODE || 'bundle-node-modules';
const linuxArm64ResvgPackage = '@resvg/resvg-js-linux-arm64-gnu';
const externalPackages = [
'@img/sharp-darwin-arm64',
@@ -195,6 +197,39 @@ async function copyNodeModules() {
console.log('==> 拷贝生产运行依赖 node_modules');
await copyDir(resolvedNodeModulesDir, path.join(runtimeRoot, 'node_modules'));
await rewriteNodeModulesSymlinks(path.join(runtimeRoot, 'node_modules'), resolvedNodeModulesDir);
await installLinuxArm64ResvgBinary();
}
// The runtime artifact is assembled on macOS but runs in a Linux ARM64 Colima VM.
// pnpm therefore copies the macOS optional resvg binary only. Keep the target
// native package alongside the copied node_modules so the dynamic require in
// @resvg/resvg-js resolves in production.
async function installLinuxArm64ResvgBinary() {
const resvgPackageJson = JSON.parse(
await fs.readFile(path.join(nodeModulesDir, '@resvg', 'resvg-js', 'package.json'), 'utf8'),
);
const version = resvgPackageJson.optionalDependencies?.[linuxArm64ResvgPackage];
if (!version) {
throw new Error(`无法确定 ${linuxArm64ResvgPackage} 的版本`);
}
const stagingDir = await fs.mkdtemp(path.join(os.tmpdir(), 'memind-resvg-linux-arm64-'));
const targetDir = path.join(runtimeRoot, 'node_modules', '@resvg', 'resvg-js-linux-arm64-gnu');
try {
console.log(`==> 补齐 Linux ARM64 resvg 原生依赖 (${version})`);
await run('npm', ['pack', `${linuxArm64ResvgPackage}@${version}`, '--pack-destination', stagingDir]);
const archive = (await fs.readdir(stagingDir)).find((name) => name.endsWith('.tgz'));
if (!archive) throw new Error(`未生成 ${linuxArm64ResvgPackage} 安装包`);
await remove(targetDir);
await fs.mkdir(targetDir, { recursive: true });
await run('tar', ['-xzf', path.join(stagingDir, archive), '--strip-components=1', '-C', targetDir]);
const files = await fs.readdir(targetDir);
if (!files.some((name) => name.endsWith('.node'))) {
throw new Error(`${linuxArm64ResvgPackage} 缺少原生 .node 文件`);
}
} finally {
await remove(stagingDir);
}
}
async function rewriteNodeModulesSymlinks(runtimeNodeModulesDir, sourceNodeModulesDir) {