diff --git a/Dockerfile b/Dockerfile index 57a72cb..addd6ac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,16 +16,10 @@ RUN bun prisma generate # Copy source code COPY . . -# Build frontend -# We use asset-naming to ensure the CSS file is named index.css so we can overwrite it with Tailwind -RUN bun build ./src/ui/index.html --outdir ./dist --asset-naming="[name].[ext]" - -# Build Tailwind CSS -# We overwrite the CSS generated by bun build with the one processed by Tailwind -RUN bunx tailwindcss -i ./src/ui/index.css -o ./dist/index.css --minify +RUN bun run build.ts # Stage 2: Runner -FROM oven/bun:1-alpine AS runner +FROM oven/bun:1 AS runner WORKDIR /app diff --git a/build.ts b/build.ts new file mode 100644 index 0000000..e028420 --- /dev/null +++ b/build.ts @@ -0,0 +1,126 @@ +#!/usr/bin/env bun +import plugin from 'bun-plugin-tailwind' +import { existsSync } from 'fs' +import { rm } from 'fs/promises' +import path from 'path' + +if (process.argv.includes('--help') || process.argv.includes('-h')) { + console.log(` +šŸ—ļø Bun Build Script + +Usage: bun run build.ts [options] + +Common Options: + --outdir Output directory (default: "dist") + --minify Enable minification (or --minify.whitespace, --minify.syntax, etc) + --sourcemap Sourcemap type: none|linked|inline|external + --target Build target: browser|bun|node + --format Output format: esm|cjs|iife + --splitting Enable code splitting + --packages Package handling: bundle|external + --public-path Public path for assets + --env Environment handling: inline|disable|prefix* + --conditions Package.json export conditions (comma separated) + --external External packages (comma separated) + --banner Add banner text to output + --footer Add footer text to output + --define Define global constants (e.g. --define.VERSION=1.0.0) + --help, -h Show this help message + +Example: + bun run build.ts --outdir=dist --minify --sourcemap=linked --external=react,react-dom +`) + process.exit(0) +} + +const toCamelCase = (str: string): string => + str.replace(/-([a-z])/g, (_, letter: string) => letter.toUpperCase()) + +const parseValue = (value: string): any => { + if (value === 'true') return true + if (value === 'false') return false + + if (/^\d+$/.test(value)) return parseInt(value, 10) + if (/^\d*\.\d+$/.test(value)) return parseFloat(value) + + if (value.includes(',')) return value.split(',').map((v) => v.trim()) + + return value +} + +function parseArgs(): Partial { + const config: Record = {} + const args = process.argv.slice(2) + + for (let i = 0; i < args.length; i++) { + const arg = args[i] + if (arg === undefined) continue + if (!arg.startsWith('--')) continue + + if (arg.startsWith('--no-')) { + const key = toCamelCase(arg.slice(5)) + config[key] = false + continue + } + + if (!arg.includes('=') && (i === args.length - 1 || args[i + 1]?.startsWith('--'))) { + const key = toCamelCase(arg.slice(2)) + config[key] = true + continue + } + + let key: string + let value: string + + if (arg.includes('=')) { + ;[key, value] = arg.slice(2).split('=', 2) as [string, string] + } else { + key = arg.slice(2) + value = args[++i] ?? '' + } + + key = toCamelCase(key) + + if (key.includes('.')) { + const parts = key.split('.') + if (parts.length > 2) { + console.warn( + `Warning: Deeply nested option "${key}" is not supported. Only single-level nesting (e.g., --minify.whitespace) is allowed.`, + ) + continue + } + const parentKey = parts[0]! + const childKey = parts[1]! + const existing = config[parentKey] + if (typeof existing !== 'object' || existing === null || Array.isArray(existing)) { + config[parentKey] = {} + } + ;(config[parentKey] as Record)[childKey] = parseValue(value) + } else { + config[key] = parseValue(value) + } + } + + return config as Partial +} + +console.log('\nšŸš€ Starting build process...\n') + +const cliConfig = parseArgs() +const outdir = cliConfig.outdir || path.join(process.cwd(), 'dist') + +if (existsSync(outdir)) { + console.log(`šŸ—‘ļø Cleaning previous build at ${outdir}`) + await rm(outdir, { recursive: true, force: true }) +} + +await Bun.build({ + entrypoints: ['./src/ui/index.html'], + target: 'browser', + outdir: './dist', + minify: true, + plugins: [plugin], + define: { + 'process.env.NODE_ENV': JSON.stringify('production'), + }, +}) diff --git a/src/ui/index.html b/src/ui/index.html index 4f9dabd..f0e763e 100644 --- a/src/ui/index.html +++ b/src/ui/index.html @@ -4,9 +4,6 @@ Forgery - - -