@@ -7,10 +7,8 @@ all: build
# Build templates into tarballs
templates:
- @echo "Building template tarballs..."
@for dir in templates/*/; do \
name=$$(basename "$$dir"); \
- echo " Creating $$name.tar.gz..."; \
tar -czf "templates/$$name.tar.gz" -C "templates/$$name" --exclude='.DS_Store' .; \
done
@@ -42,8 +40,7 @@ build-linux-x86: ui templates
# Build UI
ui:
- @echo "Building UI..."
- cd ui && pnpm install --frozen-lockfile && pnpm run build
+ @cd ui && pnpm install --frozen-lockfile --silent && pnpm run --silent build
# Run Go tests
test-go: ui
@@ -5,8 +5,14 @@ import * as crypto from 'crypto';
const isWatch = process.argv.includes('--watch');
const isProd = !isWatch;
+const verbose = process.env.VERBOSE === '1' || process.env.VERBOSE === 'true';
+
+function log(...args) {
+ if (verbose) console.log(...args);
+}
async function build() {
+ const startTime = Date.now();
try {
// Ensure dist directory exists
if (!fs.existsSync('dist')) {
@@ -14,7 +20,7 @@ async function build() {
}
// Build Monaco editor worker separately (IIFE format for web worker)
- console.log('Building Monaco editor worker...');
+ log('Building Monaco editor worker...');
await esbuild.build({
entryPoints: ['node_modules/monaco-editor/esm/vs/editor/editor.worker.js'],
bundle: true,
@@ -25,7 +31,7 @@ async function build() {
});
// Build Monaco editor as a separate chunk (JS + CSS)
- console.log('Building Monaco editor bundle...');
+ log('Building Monaco editor bundle...');
await esbuild.build({
entryPoints: ['node_modules/monaco-editor/esm/vs/editor/editor.main.js'],
bundle: true,
@@ -39,7 +45,7 @@ async function build() {
});
// Build main app - exclude monaco-editor, we'll load it dynamically
- console.log('Building main application...');
+ log('Building main application...');
const result = await esbuild.build({
entryPoints: ['src/main.tsx'],
bundle: true,
@@ -73,14 +79,14 @@ async function build() {
};
fs.writeFileSync('dist/build-info.json', JSON.stringify(buildInfo, null, 2));
- console.log('Build complete!');
-
// Generate gzip versions of large files and remove originals to reduce binary size
// The server will decompress on-the-fly for the rare clients that don't support gzip
- console.log('\nGenerating gzip compressed files...');
+ log('\nGenerating gzip compressed files...');
const filesToCompress = ['monaco-editor.js', 'editor.worker.js', 'main.js', 'monaco-editor.css', 'styles.css'];
const checksums = {};
-
+ let totalOrigSize = 0;
+ let totalGzSize = 0;
+
for (const file of filesToCompress) {
const inputPath = `dist/${file}`;
const outputPath = `dist/${file}.gz`;
@@ -88,34 +94,45 @@ async function build() {
const input = fs.readFileSync(inputPath);
const compressed = zlib.gzipSync(input, { level: 9 });
fs.writeFileSync(outputPath, compressed);
-
+
// Compute SHA256 of the compressed content for ETag
const hash = crypto.createHash('sha256').update(compressed).digest('hex').slice(0, 16);
checksums[file] = hash;
-
- const origKb = (input.length / 1024).toFixed(1);
- const gzKb = (compressed.length / 1024).toFixed(1);
- const ratio = ((compressed.length / input.length) * 100).toFixed(0);
- console.log(` ${file}: ${origKb} KB -> ${gzKb} KB gzip (${ratio}%) [${hash}]`);
-
+
+ totalOrigSize += input.length;
+ totalGzSize += compressed.length;
+
+ if (verbose) {
+ const origKb = (input.length / 1024).toFixed(1);
+ const gzKb = (compressed.length / 1024).toFixed(1);
+ const ratio = ((compressed.length / input.length) * 100).toFixed(0);
+ console.log(` ${file}: ${origKb} KB -> ${gzKb} KB gzip (${ratio}%) [${hash}]`);
+ }
+
// Remove original to save space in embedded binary
fs.unlinkSync(inputPath);
}
}
-
+
// Write checksums for ETag support
fs.writeFileSync('dist/checksums.json', JSON.stringify(checksums, null, 2));
- console.log('\nChecksums written to dist/checksums.json');
-
- console.log('\nOther files:');
- const otherFiles = fs.readdirSync('dist').filter(f =>
- (f.endsWith('.ttf') || f.endsWith('.map')) && !f.endsWith('.gz')
- );
- for (const file of otherFiles.sort()) {
- const stats = fs.statSync(`dist/${file}`);
- const sizeKb = (stats.size / 1024).toFixed(1);
- console.log(` ${file}: ${sizeKb} KB`);
+ log('\nChecksums written to dist/checksums.json');
+
+ if (verbose) {
+ console.log('\nOther files:');
+ const otherFiles = fs.readdirSync('dist').filter(f =>
+ (f.endsWith('.ttf') || f.endsWith('.map')) && !f.endsWith('.gz')
+ );
+ for (const file of otherFiles.sort()) {
+ const stats = fs.statSync(`dist/${file}`);
+ const sizeKb = (stats.size / 1024).toFixed(1);
+ console.log(` ${file}: ${sizeKb} KB`);
+ }
}
+
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
+ const totalGzKb = (totalGzSize / 1024).toFixed(0);
+ console.log(`UI built in ${elapsed}s (${totalGzKb} KB gzipped)`);
} catch (error) {
console.error('Build failed:', error);
process.exit(1);