-
Notifications
You must be signed in to change notification settings - Fork 30
Expand file tree
/
Copy pathembed-assets.ts
More file actions
128 lines (108 loc) · 4.05 KB
/
Copy pathembed-assets.ts
File metadata and controls
128 lines (108 loc) · 4.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#!/usr/bin/env bun
/**
* This script generates an embedded assets module from the frontend build.
* It reads all files from frontend/dist and creates a TypeScript module
* with native Bun file imports using `import ... with { type: 'file' }`.
*
* This approach:
* - Embeds files directly into the compiled binary via Bun's native bundler
* - Enables lazy loading (files read on demand, not at startup)
* - Provides zero-copy file serving when combined with Bun.file()
*/
import fs from 'fs';
import path from 'path';
const FRONTEND_DIST = path.join(import.meta.dir, '../../frontend/dist');
const OUTPUT_FILE = path.join(import.meta.dir, '../src/embedded-assets.ts');
const MIME_TYPES: Record<string, string> = {
'.html': 'text/html',
'.js': 'application/javascript',
'.css': 'text/css',
'.json': 'application/json',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.gif': 'image/gif',
'.svg': 'image/svg+xml',
'.ico': 'image/x-icon',
'.woff': 'font/woff',
'.woff2': 'font/woff2',
'.ttf': 'font/ttf',
'.eot': 'application/vnd.ms-fontobject',
};
function getMimeType(filePath: string): string {
const ext = path.extname(filePath).toLowerCase();
return MIME_TYPES[ext] || 'application/octet-stream';
}
interface AssetInfo {
relativePath: string; // Path relative to frontend/dist
urlPath: string; // URL path (e.g., /index.html)
contentType: string;
}
function collectFiles(dir: string, prefix: string = ''): AssetInfo[] {
const entries: AssetInfo[] = [];
if (!fs.existsSync(dir)) {
console.error(`Frontend dist directory not found: ${dir}`);
console.error('Run "bun run build:frontend" first.');
process.exit(1);
}
const items = fs.readdirSync(dir, { withFileTypes: true });
for (const item of items) {
const fullPath = path.join(dir, item.name);
const urlPath = prefix ? `${prefix}/${item.name}` : `/${item.name}`;
const relativePath = path.relative(FRONTEND_DIST, fullPath);
if (item.isDirectory()) {
entries.push(...collectFiles(fullPath, urlPath));
} else {
entries.push({
relativePath,
urlPath,
contentType: getMimeType(item.name),
});
}
}
return entries;
}
function generateModule(assets: AssetInfo[]): string {
const lines: string[] = [
'// AUTO-GENERATED FILE - DO NOT EDIT',
'// @ts-nocheck - Bun file imports are validated by the bundler, not tsc',
'// Generated by scripts/embed-assets.ts',
'// Run "bun run embed" to regenerate',
'//',
'// Uses Bun native file embedding for zero-copy serving',
'',
];
// Generate imports with native file embedding
const importLines: string[] = [];
const mapEntries: string[] = [];
for (let i = 0; i < assets.length; i++) {
const asset = assets[i];
const varName = `asset${i}`;
// Import path relative to src/ directory (where embedded-assets.ts lives)
const importPath = `../../frontend/dist/${asset.relativePath}`;
importLines.push(`import ${varName} from ${JSON.stringify(importPath)} with { type: "file" };`);
mapEntries.push(` ${JSON.stringify(asset.urlPath)}: { path: ${varName}, contentType: ${JSON.stringify(asset.contentType)} },`);
}
lines.push(...importLines);
lines.push('');
lines.push('export interface EmbeddedAsset {');
lines.push(' path: string; // Path to embedded file (works with Bun.file())');
lines.push(' contentType: string;');
lines.push('}');
lines.push('');
lines.push('export const EMBEDDED_ASSETS: Record<string, EmbeddedAsset> = {');
lines.push(...mapEntries);
lines.push('};');
lines.push('');
return lines.join('\n');
}
// Main
console.log('📦 Generating native asset imports...');
const assets = collectFiles(FRONTEND_DIST);
console.log(` Found ${assets.length} files`);
const moduleContent = generateModule(assets);
fs.writeFileSync(OUTPUT_FILE, moduleContent);
const stats = fs.statSync(OUTPUT_FILE);
console.log(` Generated ${OUTPUT_FILE}`);
console.log(` Size: ${(stats.size / 1024).toFixed(1)} KB`);
console.log('✅ Done (using Bun native file embedding)');