chore: remove legacy Windows launcher and PORTABLE verification records
Storybook is served on the web (main deployment), so the Windows BAT launcher and its Node helper are no longer used. The root PORTABLE r4-r6 verification records are historical ZIP-era notes that nothing references. - Delete start-storybook.bat and scripts/start-storybook.mjs - Delete PORTABLE-R4/R5-CANDIDATE/R5/R6-VERIFICATION.md - README, publisher distribution guide, LAN preview note: point to the web Storybook; keep npm run storybook for local development - v2 baseline report: unlink the removed files, keep the record text
This commit is contained in:
1 parent
10a1dcd28f
commit
f8cb5f8318
10 files changed
+10
-280
No files matched your search
@@ -1,84 +0,0 @@
|
||||
// Git source launcher. Uses the existing npm scripts; no portable runtime.
|
||||
import { spawn } from 'node:child_process';
|
||||
import { readFileSync, existsSync } from 'node:fs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import net from 'node:net';
|
||||
|
||||
process.chdir(fileURLToPath(new URL('../', import.meta.url)));
|
||||
const pkg = JSON.parse(readFileSync('package.json', 'utf8'));
|
||||
const portMatch = pkg.scripts?.storybook?.match(/(?:-p|--port)\s+(\d+)/);
|
||||
if (!portMatch) throw new Error('Cannot determine the port from package.json scripts.storybook.');
|
||||
const port = Number(portMatch[1]);
|
||||
const url = `http://localhost:${port}/`;
|
||||
const [major, minor] = process.versions.node.split('.').map(Number);
|
||||
if (!((major === 20 && minor >= 19) || (major === 22 && minor >= 12) || major > 22)) {
|
||||
throw new Error('Node.js 20.19+ (20.x) or 22.12+ is required by the lockfile.');
|
||||
}
|
||||
|
||||
function run(args, options = {}) {
|
||||
return spawn(process.env.ComSpec || 'cmd.exe', ['/d', '/s', '/c', args], {
|
||||
stdio: 'inherit', windowsHide: true, ...options,
|
||||
});
|
||||
}
|
||||
function completed(child) {
|
||||
return new Promise((resolve, reject) => {
|
||||
child.once('error', reject);
|
||||
child.once('exit', (code) => code === 0 ? resolve() : reject(new Error(`Command failed with exit code ${code}. See output above.`)));
|
||||
});
|
||||
}
|
||||
async function ready() {
|
||||
try {
|
||||
const response = await fetch(`${url}index.json`, { signal: AbortSignal.timeout(1500) });
|
||||
if (!response.ok) return false;
|
||||
const index = await response.json();
|
||||
if (!index.entries?.['components-form-button--all'] || !index.entries?.['theme-designer-playground--editor']) return false;
|
||||
return (await fetch(`${url}iframe.html`, { signal: AbortSignal.timeout(1500) })).ok;
|
||||
} catch { return false; }
|
||||
}
|
||||
function occupied() {
|
||||
return new Promise(resolve => {
|
||||
const socket = net.connect({ host: '127.0.0.1', port });
|
||||
socket.setTimeout(1500);
|
||||
socket.once('connect', () => { socket.destroy(); resolve(true); });
|
||||
socket.once('error', () => { socket.destroy(); resolve(false); });
|
||||
socket.once('timeout', () => { socket.destroy(); resolve(true); });
|
||||
});
|
||||
}
|
||||
async function openBrowser() {
|
||||
await completed(spawn('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', `Start-Process '${url}'`], {
|
||||
stdio: 'inherit', windowsHide: true,
|
||||
}));
|
||||
}
|
||||
if (await ready()) {
|
||||
await openBrowser();
|
||||
} else {
|
||||
if (await occupied()) throw new Error(`Port ${port} is occupied by a server that is not a ready HMDesign Storybook. Stop it and retry.`);
|
||||
await completed(run('npm.cmd --version', { stdio: 'ignore' }));
|
||||
if (!existsSync('node_modules/.bin/storybook.cmd')) await completed(run('npm.cmd ci'));
|
||||
const missingDist = ['packages/ui', 'packages/center-graphic'].some(dir => {
|
||||
const workspace = JSON.parse(readFileSync(`${dir}/package.json`, 'utf8'));
|
||||
return Object.values(workspace.exports).some(value => {
|
||||
const entry = typeof value === 'string' ? value : value.import;
|
||||
return entry && !existsSync(`${dir}/${entry}`);
|
||||
});
|
||||
});
|
||||
if (missingDist) await completed(run('npm.cmd run build:packages'));
|
||||
// Exact port prevents interactive port selection, including a startup race.
|
||||
const server = run('npm.cmd run storybook -- --exact-port --ci');
|
||||
let stopped = false;
|
||||
const exit = completed(server).finally(() => { stopped = true; });
|
||||
// Attach a handler immediately while readiness polling is in progress.
|
||||
exit.catch(() => {});
|
||||
const stop = () => completed(run(`taskkill /pid ${server.pid} /t /f`, { stdio: 'ignore' })).catch(() => {});
|
||||
process.once('SIGINT', async () => { await stop(); process.exit(0); });
|
||||
process.once('SIGTERM', async () => { await stop(); process.exit(0); });
|
||||
try {
|
||||
const deadline = Date.now() + 180000;
|
||||
while (!stopped && Date.now() < deadline) {
|
||||
if (await ready()) { await openBrowser(); await exit; break; }
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
}
|
||||
if (stopped) await exit;
|
||||
else throw new Error('Storybook readiness timed out after 3 minutes.');
|
||||
} catch (error) { await stop(); throw error; }
|
||||
}
|
||||
Reference in new issue
Block a user