diff --git a/Dockerfile b/Dockerfile index 7519fb4..cece135 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,11 +5,11 @@ WORKDIR /build COPY ./package*json ./ RUN npm ci COPY . . -RUN node --experimental-strip-types build.ts && \ +RUN npm run build && \ npm exec tsc && \ npm ci --only=production --omit=dev -FROM base as deploy +FROM base AS deploy WORKDIR /srv/archery diff --git a/build.ts b/build.ts deleted file mode 100644 index db114a5..0000000 --- a/build.ts +++ /dev/null @@ -1,171 +0,0 @@ -import fs from 'fs'; -import path from 'path'; -import child_process from 'child_process'; -import uglifyjs from "uglify-js"; -import * as sass from 'sass'; -import * as csso from 'csso'; - -const spawn = child_process.spawn; -const fsp = fs.promises; -const STYLESDIR = 'styles'; -const SCRIPTSDIR = 'scripts'; -const IMAGESDIR = path.join('assets', 'images'); -const STYLEOUTDIR = process.env.STYLEOUTDIR || path.join(import.meta.dirname, 'assets', 'css'); -const SCRIPTSOUTDIR = process.env.SCRIPTSOUTDIR || path.join(import.meta.dirname, 'assets', 'js'); -const IMAGESOUTDIR = process.env.IMAGESOUTDIR || path.join(import.meta.dirname, 'assets', 'webp'); -const STYLEOUTFILE = process.env.STYLEOUTFILE || 'styles.css'; -const SQUASH = new RegExp('^[0-9]+-'); - -async function emptyDir(dir: string) { - await Promise.all((await fsp.readdir(dir, { withFileTypes: true })).map(f => path.join(dir, f.name)).map(p => fsp.rm(p, { - recursive: true, - force: true - }))); -} - -async function mkdir(dir: string | string[]) { - if (typeof dir === 'string') { - await fsp.mkdir(dir, { recursive: true }); - } - else { - await Promise.all(dir.map(mkdir)); - } -} - -// Process styles -async function styles() { - await mkdir([STYLEOUTDIR, STYLESDIR]); - await emptyDir(STYLEOUTDIR); - let styles: string[] = []; - let files = await fsp.readdir(STYLESDIR); - await Promise.all(files.map(f => new Promise(async (res, reject) => { - let p = path.join(STYLESDIR, f); - console.log(`Processing style ${p}`); - let style = sass.compile(p).css; - if (f.charAt(0) !== '_') { - if (SQUASH.test(f)) { - styles.push(style); - } - else { - let o = path.join(STYLEOUTDIR, f.substring(0, f.lastIndexOf('.')) + '.css'); - await fsp.writeFile(o, csso.minify(style).css); - console.log(`Wrote ${o}`); - } - } - res(0); - }))); - let out = csso.minify(styles.join('\n')).css; - let outpath = path.join(STYLEOUTDIR, STYLEOUTFILE); - await fsp.writeFile(outpath, out); - console.log(`Wrote ${outpath}`); -} - -// Process scripts -async function scripts() { - await mkdir([SCRIPTSOUTDIR, SCRIPTSDIR]); - await emptyDir(SCRIPTSOUTDIR); - let files = await fsp.readdir(SCRIPTSDIR); - await Promise.all(files.map(f => new Promise(async (res, reject) => { - let p = path.join(SCRIPTSDIR, f); - let o = path.join(SCRIPTSOUTDIR, f); - console.log(`Processing script ${p}`); - try { - await fsp.writeFile(o, uglifyjs.minify((await fsp.readFile(p)).toString()).code); - console.log(`Wrote ${o}`); - } - catch (ex) { - console.log(`error writing ${o}: ${ex}`); - } - res(0); - }))); -} - -// Process images -async function images(dir = '') { - let p = path.join(IMAGESDIR, dir); - await mkdir(p); - if (dir.length === 0) { - await mkdir(IMAGESOUTDIR) - await emptyDir(IMAGESOUTDIR); - } - let files = await fsp.readdir(p, { - withFileTypes: true - }); - if (files.length) { - await Promise.all(files.map(f => new Promise(async (res, reject) => { - if (f.isFile()) { - let outDir = path.join(IMAGESOUTDIR, dir); - let infile = path.join(p, f.name); - let outfile = path.join(outDir, f.name.substring(0, f.name.lastIndexOf('.')) + '.webp'); - await mkdir(outDir); - console.log(`Processing image ${infile}`) - let process = spawn('cwebp', ['-mt', '-q', '50', infile, '-o', outfile]); - let timeout = setTimeout(() => { - reject('Timed out'); - process.kill(); - }, 30000); - process.on('exit', async (code) => { - clearTimeout(timeout); - if (code === 0) { - console.log(`Wrote ${outfile}`); - res(null); - } - else { - reject(code); - } - }); - } - else if (f.isDirectory()) { - images(path.join(dir, f.name)).then(res).catch(reject); - } - }))); - } -} - -function isAbortError(err: unknown): boolean { - return typeof err === 'object' && err !== null && 'name' in err && err.name === 'AbortError'; -} - -(async function () { - await Promise.all([styles(), scripts(), images()]); - if (process.argv.indexOf('--watch') >= 0) { - console.log('watching for changes...'); - (async () => { - try { - const watcher = fsp.watch(STYLESDIR); - for await (const _ of watcher) - await styles(); - } catch (err) { - if (isAbortError(err)) - return; - throw err; - } - })(); - - (async () => { - try { - const watcher = fsp.watch(SCRIPTSDIR); - for await (const _ of watcher) - await scripts(); - } catch (err) { - if (isAbortError(err)) - return; - throw err; - } - })(); - - (async () => { - try { - const watcher = fsp.watch(IMAGESDIR, { - recursive: true // no Linux ☹️ - }); - for await (const _ of watcher) - await images(); - } catch (err) { - if (isAbortError(err)) - return; - throw err; - } - })(); - } -})(); diff --git a/package-lock.json b/package-lock.json index b1a0477..3654075 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "archery", - "version": "0.1.4", + "version": "0.1.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "archery", - "version": "0.1.4", + "version": "0.1.5", "license": "MIT", "dependencies": { "body-parser": "^1.20.3", @@ -23,9 +23,7 @@ "@types/express-ws": "3.0.5", "@types/node": "^22.10.5", "@types/uglify-js": "3.17.5", - "csso": "5.0.5", - "sass": "1.83.1", - "uglify-js": "3.19.3" + "forking-build-shit": "0.0.2" }, "peerDependencies": { "typescript": "5.7.3" @@ -1031,6 +1029,21 @@ "node": ">= 0.8" } }, + "node_modules/forking-build-shit": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/forking-build-shit/-/forking-build-shit-0.0.2.tgz", + "integrity": "sha512-1qpXIK3nX8ZPTbwojsqxjTp5qDITX24MkKaX/8p6mMkIAQiVul1nhdYCAFLpnpnLon87Ru1exlJKhkvIKT7b+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "csso": "5.0.5", + "sass": "1.86.0", + "uglify-js": "3.19.3" + }, + "bin": { + "build-shit": "bin/build-shit.js" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1698,9 +1711,9 @@ "license": "MIT" }, "node_modules/sass": { - "version": "1.83.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.83.1.tgz", - "integrity": "sha512-EVJbDaEs4Rr3F0glJzFSOvtg2/oy2V/YrGFPqPY24UqcLDWcI9ZY5sN+qyO3c/QCZwzgfirvhXvINiJCE/OLcA==", + "version": "1.86.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.86.0.tgz", + "integrity": "sha512-zV8vGUld/+mP4KbMLJMX7TyGCuUp7hnkOScgCMsWuHtns8CWBoz+vmEhoGMXsaJrbUP8gj+F1dLvVe79sK8UdA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 8a1695e..dddfbd9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "archery", - "version": "0.1.4", + "version": "0.1.5", "description": "Build Arch packages through a web interface", "keywords": [ "docker", @@ -34,11 +34,13 @@ "@types/express-ws": "3.0.5", "@types/node": "^22.10.5", "@types/uglify-js": "3.17.5", - "csso": "5.0.5", - "sass": "1.83.1", - "uglify-js": "3.19.3" + "forking-build-shit": "0.0.2" }, "peerDependencies": { "typescript": "5.7.3" + }, + "scripts": { + "build": "npx build-shit", + "watch": "npx build-shit --watch" } }