Files
CloudSSH/scripts/build-html.js
T
TanXin bdc8d0da17 fix: 修复前端多个问题
- 修复 favicon 未加载:构建脚本未内联 public/favicon.svg
- 修复终端重连残留:断开连接后清空终端内容和状态
- 修复 sz 下载文件损坏:将 Uint8Array 转为普通数组传给 save_to_disk
- 修复 rz 上传失败:input 元素过早移除导致 onchange 无法触发
2026-06-22 16:04:02 +08:00

76 lines
2.9 KiB
JavaScript

const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const rootDir = path.resolve(__dirname, '..');
const frontendDir = path.join(rootDir, 'frontend');
const distDir = path.join(frontendDir, 'dist');
const workerDir = path.join(rootDir, 'src', 'worker');
const htmlTsFile = path.join(workerDir, 'html.ts');
console.log('Building frontend...');
try {
// 1. Install and build frontend
execSync('npm install', { cwd: frontendDir, stdio: 'inherit' });
execSync('npm run build', { cwd: frontendDir, stdio: 'inherit' });
console.log('Inlining assets...');
// 2. Read dist/index.html
let html = fs.readFileSync(path.join(distDir, 'index.html'), 'utf8');
// 3. Find assets in dist/assets
const assetsDir = path.join(distDir, 'assets');
const files = fs.readdirSync(assetsDir);
let jsContent = '';
let cssContent = '';
for (const file of files) {
const filePath = path.join(assetsDir, file);
if (file.endsWith('.js')) {
jsContent = fs.readFileSync(filePath, 'utf8');
} else if (file.endsWith('.css')) {
cssContent = fs.readFileSync(filePath, 'utf8');
}
}
// 4. Inline favicon.svg as base64 data URL
const faviconPath = path.join(frontendDir, 'public', 'favicon.svg');
if (fs.existsSync(faviconPath)) {
const faviconContent = fs.readFileSync(faviconPath, 'utf8');
const faviconBase64 = Buffer.from(faviconContent).toString('base64');
html = html.replace(
/href=["']\/favicon\.svg["']/i,
`href="data:image/svg+xml;base64,${faviconBase64}"`
);
}
// 5. Inline CSS (replace <link rel="stylesheet" ...>)
html = html.replace(/<link[^>]*rel=["']stylesheet["'][^>]*href=["']\/assets\/[^"']+["'][^>]*>/i, () => `<style>${cssContent}</style>`);
html = html.replace(/<link[^>]*rel=["']stylesheet["'][^>]*href=["']\/src\/[^"']+["'][^>]*>/i, () => `<style>${cssContent}</style>`);
// 6. Inline JS (replace <script type="module" src="/src/main.ts"></script> or similar)
html = html.replace(/<script[^>]*type=["']module["'][^>]*src=["']\/assets\/[^"']+["'][^>]*><\/script>/i, () => `<script type="module">${jsContent}</script>`);
html = html.replace(/<script[^>]*type=["']module["'][^>]*src=["']\/src\/[^"']+["'][^>]*><\/script>/i, () => `<script type="module">${jsContent}</script>`);
// 7. Write to src/worker/html.ts
const escapedHtml = html
.replace(/\\/g, '\\\\')
.replace(/`/g, '\\`')
.replace(/\${/g, '\\${');
const htmlTsContent = `// Automatically generated by scripts/build-html.js. Do not edit directly.
export const HTML = \`${escapedHtml}\`;
`;
if (!fs.existsSync(workerDir)) {
fs.mkdirSync(workerDir, { recursive: true });
}
fs.writeFileSync(htmlTsFile, htmlTsContent, 'utf8');
console.log('Frontend built and inlined successfully to src/worker/html.ts!');
} catch (error) {
console.error('Failed to build and inline frontend:', error);
process.exit(1);
}