139 lines
4.9 KiB
JavaScript
139 lines
4.9 KiB
JavaScript
import fs from 'fs/promises';
|
|
import path from 'path';
|
|
import { spawn } from 'child_process';
|
|
|
|
const ROOT = process.cwd();
|
|
const REPO = process.env.BOOSAPI_WORKFLOW_UI_REPO || '';
|
|
const VARIANT = (process.env.BOOSAPI_WORKFLOW_UI_VARIANT || process.argv[2] || 'all').toLowerCase();
|
|
const DEFAULT_EXTERNAL_REF = 'v1.14.6';
|
|
const DEFAULT_CLOUD_REF = 'v1.46.2';
|
|
const SUBMODULE_DIR = path.join(ROOT, 'vendor', 'ComfyUI_frontend');
|
|
const CACHE_DIR = path.join(ROOT, '.cache', 'comfyui-frontend');
|
|
const DEFAULT_DIST = path.join(ROOT, 'dist', 'workflow-ui');
|
|
|
|
// External/RunningHub currently targets ComfyUI 0.3.27, where v1.14.x is the
|
|
// most stable match. Cloud tracks the newer ComfyUI_frontend release line.
|
|
|
|
const variants = {
|
|
external: {
|
|
ref: process.env.BOOSAPI_WORKFLOW_UI_EXTERNAL_REF
|
|
|| process.env.BOOSAPI_WORKFLOW_UI_REF
|
|
|| DEFAULT_EXTERNAL_REF,
|
|
dist: process.env.BOOSAPI_WORKFLOW_UI_EXTERNAL_DIST
|
|
|| path.join(ROOT, 'dist', 'workflow-ui-external'),
|
|
description: 'External/RunningHub compatible frontend',
|
|
},
|
|
cloud: {
|
|
ref: process.env.BOOSAPI_WORKFLOW_UI_CLOUD_REF
|
|
|| process.env.BOOSAPI_WORKFLOW_UI_REF
|
|
|| DEFAULT_CLOUD_REF,
|
|
dist: process.env.BOOSAPI_WORKFLOW_UI_CLOUD_DIST
|
|
|| path.join(ROOT, 'dist', 'workflow-ui-cloud'),
|
|
description: 'Comfy Cloud frontend',
|
|
},
|
|
};
|
|
|
|
function run(command, args, options = {}) {
|
|
return new Promise((resolve, reject) => {
|
|
const env = { ...process.env, ...(options.env || {}) };
|
|
if (options.cleanPackageEnv) {
|
|
Object.keys(env)
|
|
.filter((key) => key.startsWith('npm_package_'))
|
|
.forEach((key) => {
|
|
delete env[key];
|
|
});
|
|
Object.assign(env, options.env || {});
|
|
}
|
|
const child = spawn(command, args, {
|
|
cwd: options.cwd || ROOT,
|
|
env,
|
|
stdio: 'inherit',
|
|
shell: process.platform === 'win32',
|
|
});
|
|
child.on('error', reject);
|
|
child.on('exit', (code) => {
|
|
if (code === 0) resolve();
|
|
else reject(new Error(`${command} ${args.join(' ')} exited with ${code}`));
|
|
});
|
|
});
|
|
}
|
|
|
|
function selectedVariants() {
|
|
if (VARIANT === 'all') return Object.entries(variants);
|
|
if (variants[VARIANT]) return [[VARIANT, variants[VARIANT]]];
|
|
throw new Error(`Unknown workflow-ui variant: ${VARIANT}. Use external, cloud, or all.`);
|
|
}
|
|
|
|
async function readPackageInfo(dir) {
|
|
const raw = await fs.readFile(path.join(dir, 'package.json'), 'utf8');
|
|
return JSON.parse(raw);
|
|
}
|
|
|
|
async function buildVariant(name, config) {
|
|
const ref = config.ref;
|
|
const dist = config.dist;
|
|
const dir = path.join(CACHE_DIR, `${name}-${ref.replace(/[^a-zA-Z0-9._-]/g, '_')}`);
|
|
|
|
console.log(`\n==> Building workflow-ui:${name} (${config.description}) from ${ref}`);
|
|
await fs.mkdir(path.dirname(CACHE_DIR), { recursive: true });
|
|
await fs.rm(dir, { recursive: true, force: true });
|
|
|
|
if (REPO) {
|
|
await run('git', ['clone', '--depth', '1', '--branch', ref, REPO, dir]);
|
|
} else {
|
|
const hasSubmodule = await fs.access(path.join(SUBMODULE_DIR, 'package.json')).then(() => true, () => false);
|
|
if (!hasSubmodule) {
|
|
await run('git', ['submodule', 'update', '--init', '--recursive', 'vendor/ComfyUI_frontend']);
|
|
}
|
|
await run('git', ['fetch', '--tags', 'origin', ref], { cwd: SUBMODULE_DIR });
|
|
await run('git', ['clone', '--shared', SUBMODULE_DIR, dir]);
|
|
await run('git', ['-c', 'advice.detachedHead=false', 'checkout', '--quiet', ref], { cwd: dir });
|
|
await run('git', ['submodule', 'update', '--init', '--recursive'], { cwd: dir });
|
|
}
|
|
|
|
const packageInfo = await readPackageInfo(dir);
|
|
const packageEnv = {
|
|
npm_package_name: packageInfo.name || '',
|
|
npm_package_version: packageInfo.version || ref.replace(/^v/, ''),
|
|
};
|
|
const hasPnpmLock = await fs.access(path.join(dir, 'pnpm-lock.yaml')).then(() => true, () => false);
|
|
if (hasPnpmLock) {
|
|
await run('pnpm', ['install', '--frozen-lockfile'], { cwd: dir });
|
|
await run('pnpm', ['exec', 'vite', 'build', '--config', 'vite.config.mts'], {
|
|
cwd: dir,
|
|
cleanPackageEnv: true,
|
|
env: packageEnv,
|
|
});
|
|
} else {
|
|
await run('npm', ['ci'], { cwd: dir });
|
|
await run('npm', ['run', 'build'], {
|
|
cwd: dir,
|
|
cleanPackageEnv: true,
|
|
env: packageEnv,
|
|
});
|
|
}
|
|
|
|
await fs.rm(dist, { recursive: true, force: true });
|
|
await fs.cp(path.join(dir, 'dist'), dist, { recursive: true });
|
|
await fs.writeFile(
|
|
path.join(dist, 'boosapi-workflow-ui.json'),
|
|
`${JSON.stringify({
|
|
variant: name,
|
|
ref,
|
|
packageName: packageInfo.name || null,
|
|
packageVersion: packageInfo.version || null,
|
|
}, null, 2)}\n`,
|
|
);
|
|
console.log(`workflow-ui:${name} installed to ${dist}`);
|
|
|
|
if (name === 'cloud') {
|
|
await fs.rm(DEFAULT_DIST, { recursive: true, force: true });
|
|
await fs.cp(dist, DEFAULT_DIST, { recursive: true });
|
|
console.log(`workflow-ui default compatibility copy installed to ${DEFAULT_DIST}`);
|
|
}
|
|
}
|
|
|
|
for (const [name, config] of selectedVariants()) {
|
|
await buildVariant(name, config);
|
|
}
|