xingyun/scripts/tauri-js-plugins-build.js

142 lines
4.3 KiB
JavaScript

#!/usr/bin/env node
/**
* Build local tauri plugin JS APIs (dist-js) used by webpack bundling.
*
* Notes:
* - plugin package.json exports point to dist-js; without build webpack fails to resolve tauri-plugin-*.
* - skip builds when dist-js is newer than sources unless forced.
*/
const path = require('node:path');
const fs = require('node:fs');
const { spawn } = require('node:child_process');
const packageRoot = path.resolve(__dirname, '..');
const repoRoot = path.resolve(packageRoot, '..', '..');
const packagesDir = path.join(repoRoot, 'packages');
const isWindows = process.platform === 'win32';
/**
* Auto-discover tauri-plugin-* packages under packages/.
* Only includes directories that have a package.json with a "build" script.
*/
function discoverPlugins() {
const entries = fs.readdirSync(packagesDir, { withFileTypes: true });
return entries
.filter((entry) => entry.isDirectory() && entry.name.startsWith('tauri-plugin-'))
.filter((entry) => {
const pkgJsonPath = path.join(packagesDir, entry.name, 'package.json');
try {
const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8'));
return pkgJson.scripts && pkgJson.scripts.build;
} catch {
return false;
}
})
.map((entry) => entry.name)
.sort();
}
const plugins = discoverPlugins();
const forceBuild =
process.argv.includes('--force') ||
process.env.TAURI_JS_PLUGINS_FORCE === '1';
function statSafe(targetPath) {
try {
return fs.statSync(targetPath);
} catch {
return null;
}
}
function getLatestMtime(targetPath) {
const stat = statSafe(targetPath);
if (!stat) return 0;
if (stat.isFile()) return stat.mtimeMs;
if (!stat.isDirectory()) return 0;
let latest = 0;
const entries = fs.readdirSync(targetPath, { withFileTypes: true });
for (const entry of entries) {
if (entry.name === 'node_modules' || entry.name === 'dist-js' || entry.name === '.git') {
continue;
}
const entryPath = path.join(targetPath, entry.name);
const ts = getLatestMtime(entryPath);
if (ts > latest) latest = ts;
}
return latest;
}
function isPluginUpToDate(name) {
const pluginDir = path.join(repoRoot, 'packages', name);
const distDir = path.join(pluginDir, 'dist-js');
const distFiles = [path.join(distDir, 'index.js'), path.join(distDir, 'index.cjs')];
const distStats = distFiles.map(statSafe);
if (distStats.some((s) => !s)) return false;
const distTime = Math.min(...distStats.map((s) => s.mtimeMs));
const sourceCandidates = [
path.join(pluginDir, 'guest-js'),
path.join(pluginDir, 'rollup.config.mjs'),
path.join(pluginDir, 'rollup.config.js'),
path.join(pluginDir, 'package.json'),
path.join(pluginDir, 'tsconfig.json'),
].filter((p) => statSafe(p));
if (sourceCandidates.length === 0) return false;
let sourceTime = 0;
for (const source of sourceCandidates) {
const ts = getLatestMtime(source);
if (ts > sourceTime) sourceTime = ts;
}
return distTime >= sourceTime;
}
const buildPlugin = (name) =>
new Promise((resolve) => {
if (!forceBuild && isPluginUpToDate(name)) {
console.log(`[tauri-js-plugins] skip up-to-date: ${name}`);
resolve({ ok: true, code: 0, skipped: true });
return;
}
console.log(`[tauri-js-plugins] build: ${name}`);
// On Windows, spawn "yarn" via shell to avoid EINVAL in some environments (e.g. Git Bash).
const child = spawn('yarn', ['-s', 'workspace', name, 'run', 'build'], {
cwd: repoRoot,
stdio: 'inherit',
shell: isWindows,
});
child.on('error', (error) => {
console.error(`[tauri-js-plugins] failed: ${name}: ${error.message}`);
resolve({ ok: false, code: 1 });
});
child.on('close', (code) => {
if (code === 0) {
resolve({ ok: true, code: 0 });
return;
}
const exitCode = typeof code === 'number' ? code : 1;
console.error(`[tauri-js-plugins] failed: ${name} (exit=${exitCode})`);
resolve({ ok: false, code: exitCode });
});
});
Promise.all(plugins.map((name) => buildPlugin(name)))
.then((results) => {
const failures = results.filter((item) => !item.ok);
if (failures.length > 0) {
process.exit(failures[0].code || 1);
}
console.log('[tauri-js-plugins] done');
})
.catch((error) => {
console.error(`[tauri-js-plugins] failed: ${error.message}`);
process.exit(1);
});