From 26c31fded6b3bde82cc79078ccc6a525f0162e31 Mon Sep 17 00:00:00 2001 From: mifi Date: Fri, 13 Feb 2026 15:17:59 -0300 Subject: [PATCH] A better build --- .gitignore | 1 + Dockerfile | 2 +- package.json | 4 +++ scripts/build.js | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ src/index.html | 2 +- 5 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 scripts/build.js diff --git a/.gitignore b/.gitignore index 695c41a..2f4ac0a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ node_modules pnpm-lock.yaml .eslintcache .stylelintcache +dist diff --git a/Dockerfile b/Dockerfile index 675a1ed..465f3e0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ FROM nginx:alpine COPY nginx/conf.d/ /etc/nginx/conf.d/ -COPY src/ /usr/share/nginx/html/ +COPY dist/ /usr/share/nginx/html/ diff --git a/package.json b/package.json index c51a18f..68b8e7a 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "version": "1.0.0", "packageManager": "pnpm@10.29.3", "scripts": { + "build": "node scripts/build.js", "docker:build": "docker build --platform linux/amd64 -t git.mifi.dev/mifi-holdings/landing:latest .", "docker:push": "docker push git.mifi.dev/mifi-holdings/landing:latest", "format": "prettier --write .", @@ -18,11 +19,14 @@ "lint:fix:yaml": "yamllint .woodpecker/ci.yml .woodpecker/build.yml .woodpecker/deploy.yml docker-compose.yml --fix" }, "devDependencies": { + "clean-css": "^5.3.3", + "critters": "^0.0.25", "eslint": "^10.0.0", "eslint-config-prettier": "^10.1.8", "prettier": "^3.4.2", "stylelint": "^17.3.0", "stylelint-config-standard": "^40.0.0", + "terser": "^5.46.0", "yaml-lint": "^1.7.0" }, "repository": { diff --git a/scripts/build.js b/scripts/build.js new file mode 100644 index 0000000..0965945 --- /dev/null +++ b/scripts/build.js @@ -0,0 +1,69 @@ +/** + * Build script: copy src → dist, minify JS/CSS, inline critical CSS (Critters). + * Run with: pnpm build + */ +import { rmSync, mkdirSync, readFileSync, writeFileSync, cpSync, readdirSync } from 'fs' +import { join, dirname, extname } from 'path' +import { fileURLToPath } from 'url' +import Critters from 'critters' +import { minify as minifyJs } from 'terser' +import CleanCSS from 'clean-css' + +const __dirname = dirname(fileURLToPath(import.meta.url)) +const root = join(__dirname, '..') +const srcDir = join(root, 'src') +const distDir = join(root, 'dist') + +function getFiles(dir, files = []) { + const entries = readdirSync(dir, { withFileTypes: true }) + for (const e of entries) { + const full = join(dir, e.name) + if (e.isDirectory()) getFiles(full, files) + else files.push(full) + } + return files +} + +async function main() { + // 1. Clean and copy src → dist + rmSync(distDir, { recursive: true, force: true }) + mkdirSync(distDir, { recursive: true }) + cpSync(srcDir, distDir, { recursive: true }) + + const distFiles = getFiles(distDir) + + // 2. Minify JS + const jsFiles = distFiles.filter((f) => extname(f) === '.js') + for (const f of jsFiles) { + const code = readFileSync(f, 'utf8') + const result = await minifyJs(code, { format: { comments: false } }) + if (result.code) writeFileSync(f, result.code) + } + + // 3. Minify CSS + const cleanCss = new CleanCSS({ level: 2 }) + const cssFiles = distFiles.filter((f) => extname(f) === '.css') + for (const f of cssFiles) { + const code = readFileSync(f, 'utf8') + const result = cleanCss.minify(code) + if (!result.errors.length) writeFileSync(f, result.styles) + } + + // 4. Inline critical CSS with Critters (no browser; works in CI) + const critters = new Critters({ + path: distDir, + preload: 'default', + logLevel: 'warn', + }) + const indexPath = join(distDir, 'index.html') + const html = readFileSync(indexPath, 'utf8') + const inlined = await critters.process(html) + writeFileSync(indexPath, inlined) + + console.log('Build complete: dist/') +} + +main().catch((err) => { + console.error(err) + process.exit(1) +}) diff --git a/src/index.html b/src/index.html index b344ce2..9e4a8cd 100644 --- a/src/index.html +++ b/src/index.html @@ -14,7 +14,7 @@ - +