67 lines
3.9 KiB
JavaScript
67 lines
3.9 KiB
JavaScript
// Portable test launcher: built-in modules only; never invokes npm or a global Node.
|
|
const http = require('node:http');
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const { spawn } = require('node:child_process');
|
|
const root = __dirname;
|
|
const types = { '.html':'text/html; charset=utf-8', '.js':'text/javascript; charset=utf-8', '.mjs':'text/javascript; charset=utf-8', '.css':'text/css; charset=utf-8', '.json':'application/json; charset=utf-8', '.svg':'image/svg+xml', '.png':'image/png', '.jpg':'image/jpeg', '.jpeg':'image/jpeg', '.gif':'image/gif', '.webp':'image/webp', '.ico':'image/x-icon', '.ttf':'font/ttf', '.woff':'font/woff', '.woff2':'font/woff2', '.txt':'text/plain; charset=utf-8' };
|
|
const server = http.createServer((req, res) => {
|
|
if (!['GET','HEAD'].includes(req.method)) { res.writeHead(405); res.end(); return; }
|
|
let pathname;
|
|
try { pathname = decodeURIComponent(new URL(req.url, 'http://127.0.0.1').pathname); }
|
|
catch { res.writeHead(400); res.end(); return; }
|
|
// Dashboard is a production export and must be served from its own URL root.
|
|
const dashboard = pathname === '/dashboard' || pathname.startsWith('/dashboard/');
|
|
const dashboardPath = dashboard ? (pathname === '/dashboard' ? '/dashboard/' : pathname) : pathname;
|
|
// Source Reference/static example paths keep their repository-relative imports.
|
|
const reference = ['/docs/','/packages/','/src/','/public/'].some(prefix => pathname.startsWith(prefix));
|
|
const base = dashboard ? path.join(root, 'dist-dashboard') : (reference ? root : path.join(root, 'storybook-static'));
|
|
const relativePath = dashboard ? dashboardPath.slice('/dashboard'.length) || '/' : (pathname === '/favicon.ico' ? '/favicon.svg' : pathname);
|
|
let file = path.resolve(base, '.' + relativePath);
|
|
const relative = path.relative(base, file);
|
|
if (relative.startsWith('..') || path.isAbsolute(relative) || pathname.includes('\\')) { res.writeHead(403); res.end(); return; }
|
|
fs.stat(file, (error, stat) => {
|
|
if (!error && stat.isDirectory()) file = path.join(file, 'index.html');
|
|
fs.stat(file, (error, stat) => {
|
|
if (error || !stat.isFile()) { res.writeHead(404); res.end('Not found'); return; }
|
|
res.writeHead(200, { 'Content-Type': types[path.extname(file).toLowerCase()] || 'application/octet-stream', 'Content-Length':stat.size, 'Cache-Control':'no-store', 'X-Content-Type-Options':'nosniff' });
|
|
if (req.method === 'HEAD') { res.end(); return; }
|
|
const stream = fs.createReadStream(file);
|
|
stream.on('error', () => res.destroy());
|
|
stream.pipe(res);
|
|
});
|
|
});
|
|
});
|
|
let port = 6007;
|
|
let browserOpened = false;
|
|
function openDefaultBrowser(url) {
|
|
if (browserOpened) return;
|
|
browserOpened = true;
|
|
const command = process.env.ComSpec || 'cmd.exe';
|
|
const browser = spawn(command, ['/c', 'start', '', url], {
|
|
detached: true,
|
|
stdio: 'ignore',
|
|
windowsHide: true
|
|
});
|
|
browser.on('error', error => {
|
|
console.error(`Browser auto-open failed: ${error.message}`);
|
|
console.error(`Open this address manually: ${url}`);
|
|
});
|
|
browser.unref();
|
|
}
|
|
server.on('error', error => {
|
|
if (error.code === 'EADDRINUSE' || error.code === 'EACCES') {
|
|
if (port === 0) { console.error(error.message); process.exitCode = 1; return; }
|
|
port = port < 6023 ? port + 1 : 0;
|
|
server.listen(port, '127.0.0.1');
|
|
} else { console.error(error.message); process.exitCode = 1; }
|
|
});
|
|
server.on('listening', () => {
|
|
const url = `http://127.0.0.1:${server.address().port}/`;
|
|
console.log(`HM Design System Portable Test\nNode ${process.version} (${process.arch})\nStorybook: ${url}\nDashboard: ${url}dashboard/\nStatic status example: ${url}docs/patterns/dashboard-status-static.html\nPress Ctrl+C to stop this preview.\n`);
|
|
openDefaultBrowser(url);
|
|
});
|
|
process.on('SIGINT', () => server.close(() => process.exit(0)));
|
|
process.on('SIGTERM', () => server.close(() => process.exit(0)));
|
|
server.listen(port, '127.0.0.1');
|