diff --git a/scripts/prepare-miniapp-shell.mjs b/scripts/prepare-miniapp-shell.mjs index 6320f8fd5c..e3a35e555e 100644 --- a/scripts/prepare-miniapp-shell.mjs +++ b/scripts/prepare-miniapp-shell.mjs @@ -2,12 +2,17 @@ // Build the window-only executable in its own Cargo invocation so Desktop's // feature union and debug profile cannot inflate every exported MiniApp. import { spawnSync } from 'node:child_process'; -import { chmodSync, copyFileSync, mkdirSync, statSync } from 'node:fs'; +import { chmodSync, copyFileSync, existsSync, mkdirSync, statSync } from 'node:fs'; import { dirname, join, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..'); export const SHELL_NAME = 'openbitfun-miniapp-shell'; +// Built design-system entries the native-window projections import. +const DESIGN_SYSTEM_CONSUMER_ENTRIES = [ + 'design-system/packages/design-tokens/dist/index.js', + 'design-system/packages/theme-openbitfun/dist/index.js', +]; export function prepareMiniAppShell({ root = ROOT, target, profile = 'debug', env = process.env, run = spawnSync, @@ -30,6 +35,13 @@ export function prepareMiniAppShell({ if (!host) throw new Error('rustc did not report the host target triple'); // Derive native-window visuals from the same Hi/FlowChat style owners. execute('node', ['scripts/generate-miniapp-chat-styles.mjs']); + // The chrome-theme projection reads the built design-system token packages, + // while Tauri's frontend build (whose prebuild owns that dist) runs after + // this step. Build them here so a fresh checkout, including every package + // build, can project the shell without a pre-warmed workspace. + if (DESIGN_SYSTEM_CONSUMER_ENTRIES.some((entry) => !existsSync(join(root, entry)))) { + execute('pnpm', ['--dir', 'design-system', 'run', 'prepare:consumer-dev'], { shell: true }); + } execute('node', ['scripts/generate-miniapp-chrome-theme.mjs']); const triple = target || host; const targetDir = env.CARGO_TARGET_DIR ? resolve(root, env.CARGO_TARGET_DIR) : join(root, 'target'); diff --git a/scripts/prepare-miniapp-shell.test.mjs b/scripts/prepare-miniapp-shell.test.mjs index 4079eacf28..dcf9a5e669 100644 --- a/scripts/prepare-miniapp-shell.test.mjs +++ b/scripts/prepare-miniapp-shell.test.mjs @@ -25,9 +25,51 @@ function fixture(t) { return root; } +// A workspace that already built the design-system consumers, as after any web build. +function seedDesignSystemConsumers(root) { + for (const entry of ['design-tokens', 'theme-openbitfun']) { + const file = join(root, 'design-system/packages', entry, 'dist/index.js'); + mkdirSync(dirname(file), { recursive: true }); + writeFileSync(file, 'export {};\n'); + } +} + +test('a fresh checkout builds the design-system consumers before projecting the chrome theme', (t) => { + const root = fixture(t); + const calls = []; + const run = (command, args) => { + calls.push({ command, args }); + if (command === 'rustc') return { status: 0, stdout: 'host: aarch64-apple-darwin\n' }; + if (command === 'pnpm') { + assert.deepEqual(args, ['--dir', 'design-system', 'run', 'prepare:consumer-dev']); + seedDesignSystemConsumers(root); + return { status: 0 }; + } + if (command === 'node') return { status: 0 }; + if (command === 'cargo') { + const binary = join(root, 'target/miniapp-shell', SHELL_NAME); + mkdirSync(dirname(binary), { recursive: true }); + writeFileSync(binary, 'window-only-binary'); + return { status: 0 }; + } + return assert.fail(command); + }; + prepareMiniAppShell({ root, profile: 'release', env: {}, run }); + assert.deepEqual(calls.map(({ command }) => command), ['rustc', 'node', 'pnpm', 'node', 'cargo']); + + // A workspace that already built them skips the extra build. + const warmCalls = []; + prepareMiniAppShell({ root, profile: 'release', env: {}, run: (command, args) => { + warmCalls.push({ command, args }); + return run(command, args); + } }); + assert.deepEqual(warmCalls.map(({ command }) => command), ['rustc', 'node', 'node', 'cargo']); +}); + for (const target of [undefined, 'x86_64-pc-windows-msvc', 'x86_64-unknown-linux-gnu', 'universal-apple-darwin']) { test(`prepares a separate optimized sidecar and stages the correct target: ${target || 'host'}`, (t) => { const root = fixture(t); + seedDesignSystemConsumers(root); const calls = []; const run = (command, args, options) => { calls.push({ command, args, options });