Embed workflow UI and isolate workspace assets

This commit is contained in:
boos
2026-05-26 17:00:10 +08:00
parent 0f9fe4a81d
commit e0bd9b4194
7 changed files with 529 additions and 148 deletions
+73 -19
View File
@@ -4,10 +4,34 @@ import { spawn } from 'child_process';
const ROOT = process.cwd();
const REPO = process.env.BOOSAPI_WORKFLOW_UI_REPO || '';
const REF = process.env.BOOSAPI_WORKFLOW_UI_REF || 'v1.46.1';
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.1';
const SUBMODULE_DIR = path.join(ROOT, 'vendor', 'ComfyUI_frontend');
const CACHE_DIR = path.join(ROOT, '.cache', 'comfyui-frontend');
const DIST = path.join(ROOT, 'dist', 'workflow-ui');
const DEFAULT_DIST = path.join(ROOT, 'dist', 'workflow-ui');
// External/RunningHub often exposes older ComfyUI servers; v1.14.x matches
// ComfyUI 0.3.27 much better than the newer Cloud-oriented frontend.
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) => {
@@ -25,23 +49,53 @@ function run(command, args, options = {}) {
});
}
const hasSubmodule = await fs.access(path.join(SUBMODULE_DIR, 'package.json')).then(() => true, () => false);
const DIR = REPO ? CACHE_DIR : SUBMODULE_DIR;
if (REPO) {
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 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(CACHE_DIR, { recursive: true, force: true });
await run('git', ['clone', '--depth', '1', '--branch', REF, REPO, CACHE_DIR]);
} else if (!hasSubmodule) {
await run('git', ['submodule', 'update', '--init', '--recursive', 'vendor/ComfyUI_frontend']);
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', ['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 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 });
} else {
await run('npm', ['ci'], { cwd: dir });
await run('npm', ['run', 'build'], { cwd: dir });
}
await fs.rm(dist, { recursive: true, force: true });
await fs.cp(path.join(dir, 'dist'), dist, { recursive: true });
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}`);
}
}
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 });
} else {
await run('npm', ['ci'], { cwd: DIR });
await run('npm', ['run', 'build'], { cwd: DIR });
for (const [name, config] of selectedVariants()) {
await buildVariant(name, config);
}
await fs.rm(DIST, { recursive: true, force: true });
await fs.cp(path.join(DIR, 'dist'), DIST, { recursive: true });
console.log(`workflow-ui installed to ${DIST}`);