-
Notifications
You must be signed in to change notification settings - Fork 36
Expand file tree
/
Copy pathbuild.ts
More file actions
179 lines (158 loc) · 5.09 KB
/
build.ts
File metadata and controls
179 lines (158 loc) · 5.09 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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#!/usr/bin/env bun
/**
* Self-contained build script for ElizaOS projects
*
* - Starts Vite build in the background (to web-dist/)
* - Runs tsc --noEmit and Bun.build in parallel
* - If anything fails, Vite is terminated and the script exits non-zero
*/
import { existsSync } from 'node:fs';
import { rm } from 'node:fs/promises';
import { $ } from 'bun';
function fmt(ns: bigint) {
const ms = Number(ns) / 1e6;
return ms < 1000 ? `${ms.toFixed(2)}ms` : `${(ms / 1000).toFixed(2)}s`;
}
const VITE_OUTDIR = 'dist'; // web-dist?
const NODE_OUTDIR = 'dist';
async function cleanBuild(...dirs: string[]) {
for (const dir of dirs) {
if (existsSync(dir)) {
await rm(dir, { recursive: true, force: true });
console.log(`✓ Cleaned ${dir} directory`);
}
}
}
// 👉 run TypeScript type-checker first (no emit)
// We still *start* Vite immediately (background), but if typecheck fails we kill Vite and exit.
async function typecheck(viteProc?: Bun.Subprocess) {
const t0 = Bun.nanoseconds();
console.log('▶︎ Type-checking with tsc…');
try {
await $`tsc --noEmit -p tsconfig.typecheck.json`;
const dt = Bun.nanoseconds() - t0;
console.log(`⏱️ Type-check done in ${fmt(dt)}`);
} catch (err) {
const dt = Bun.nanoseconds() - t0;
console.error(`✖ Type-check failed after ${fmt(dt)}`);
// kill vite if it's running
try { viteProc?.kill('SIGTERM'); } catch { }
process.exit(1);
}
}
function startViteBuild(): { proc: Bun.Subprocess; exited: Promise<number> } {
console.log('🎛️ Starting Vite build (background)…');
// Use bunx to ensure local vite is used; send stdio to terminal.
const proc = Bun.spawn({
cmd: ['bunx', '-y', 'vite', 'build', '--outDir', VITE_OUTDIR, '--emptyOutDir'],
stdout: 'inherit',
stderr: 'inherit',
env: {
...process.env,
// Put any env flags you want Vite to see here
// e.g. VITE_BUILD_MODE: 'production'
},
});
const exited = proc.exited; // Promise<number>
exited.then((code) => {
if (code === 0) {
console.log(`✅ Vite build finished successfully → ${VITE_OUTDIR}/`);
} else {
console.error(`✖ Vite build failed with exit code ${code}`);
}
});
return { proc, exited };
}
async function buildNodeBundle() {
console.log('📦 Bundling with Bun…');
const result = await Bun.build({
entrypoints: ['./src/index.ts'],
outdir: `./${NODE_OUTDIR}`,
target: 'node',
format: 'esm',
sourcemap: true,
minify: false,
external: [
'dotenv',
'fs',
'path',
'https',
'node:*',
'@elizaos/core',
'@elizaos/plugin-bootstrap',
'@elizaos/plugin-sql',
'@elizaos/cli',
'zod',
],
naming: {
entry: '[dir]/[name].[ext]',
},
});
if (!result.success) {
console.error('✗ Bun build failed:', result.logs);
return { success: false, outputs: [] as typeof result.outputs };
}
const totalSize = result.outputs.reduce((sum, o) => sum + o.size, 0);
const sizeMB = (totalSize / 1024 / 1024).toFixed(2);
console.log(`✓ Built ${result.outputs.length} file(s) - ${sizeMB}MB`);
return result;
}
async function build() {
const start = performance.now();
console.log('🚀 Building project...');
// Clean both outputs up front to avoid races
await cleanBuild(NODE_OUTDIR, VITE_OUTDIR);
// Kick off Vite immediately (background)
const { proc: viteProc, exited: viteExited } = startViteBuild();
// Run typecheck + (Bun bundle + d.ts) in parallel
console.log('Starting build tasks…');
const typecheckPromise = typecheck(viteProc);
const bunBundlePromise = (async () => {
const buildResult = await buildNodeBundle();
return buildResult;
})();
const dtsPromise = (async () => {
console.log('📝 Generating TypeScript declarations…');
try {
await $`tsc --emitDeclarationOnly --incremental --project ./tsconfig.build.json`.quiet();
console.log('✓ TypeScript declarations generated');
return { success: true };
} catch {
console.warn('⚠ Failed to generate TypeScript declarations');
console.warn(' This is usually due to test files or type errors.');
return { success: false };
}
})();
// Wait for typecheck + Bun bundle + d.ts
const [_, bunResult, dtsResult] = await Promise.all([
typecheckPromise,
bunBundlePromise,
dtsPromise,
]);
// If Bun bundle failed, stop Vite and bail out
if (!bunResult.success) {
try { viteProc.kill('SIGTERM'); } catch { }
// Ensure vite exits (don’t hang)
await Promise.race([viteExited, new Promise((r) => setTimeout(r, 2000))]);
return false;
}
// Now wait for Vite to finish; if it fails, treat as overall failure
const viteCode = await viteExited;
if (viteCode !== 0) {
return false;
}
const elapsed = ((performance.now() - start) / 1000).toFixed(2);
console.log(`✅ Build complete! (${elapsed}s)`);
return true;
}
// Execute the build
build()
.then((success) => {
if (!success) {
process.exit(1);
}
})
.catch((error) => {
console.error('Build script error:', error);
process.exit(1);
});