Tiny script for preparing web assets for deployment

update sass and use better options for cwebp

+18 -18
package-lock.json
··· 1 { 2 "name": "forking-build-shit", 3 - "version": "0.0.2", 4 "lockfileVersion": 3, 5 "requires": true, 6 "packages": { 7 "": { 8 "name": "forking-build-shit", 9 - "version": "0.0.2", 10 "license": "MIT", 11 "dependencies": { 12 "csso": "5.0.5", 13 - "sass": "1.86.0", 14 "uglify-js": "3.19.3" 15 }, 16 "bin": { ··· 19 "devDependencies": { 20 "@sindresorhus/tsconfig": "7.0.0", 21 "@types/csso": "^5.0.4", 22 - "@types/node": "^22.13.10", 23 "@types/uglify-js": "^3.17.5", 24 - "typescript": "5.8.2" 25 } 26 }, 27 "node_modules/@parcel/watcher": { ··· 351 } 352 }, 353 "node_modules/@types/node": { 354 - "version": "22.13.10", 355 - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz", 356 - "integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==", 357 "dev": true, 358 "license": "MIT", 359 "dependencies": { 360 - "undici-types": "~6.20.0" 361 } 362 }, 363 "node_modules/@types/uglify-js": { ··· 544 } 545 }, 546 "node_modules/sass": { 547 - "version": "1.86.0", 548 - "resolved": "https://registry.npmjs.org/sass/-/sass-1.86.0.tgz", 549 - "integrity": "sha512-zV8vGUld/+mP4KbMLJMX7TyGCuUp7hnkOScgCMsWuHtns8CWBoz+vmEhoGMXsaJrbUP8gj+F1dLvVe79sK8UdA==", 550 "license": "MIT", 551 "dependencies": { 552 "chokidar": "^4.0.0", ··· 596 } 597 }, 598 "node_modules/typescript": { 599 - "version": "5.8.2", 600 - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", 601 - "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", 602 "dev": true, 603 "license": "Apache-2.0", 604 "bin": { ··· 622 } 623 }, 624 "node_modules/undici-types": { 625 - "version": "6.20.0", 626 - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", 627 - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", 628 "dev": true, 629 "license": "MIT" 630 }
··· 1 { 2 "name": "forking-build-shit", 3 + "version": "0.1.0", 4 "lockfileVersion": 3, 5 "requires": true, 6 "packages": { 7 "": { 8 "name": "forking-build-shit", 9 + "version": "0.1.0", 10 "license": "MIT", 11 "dependencies": { 12 "csso": "5.0.5", 13 + "sass": "1.89.0", 14 "uglify-js": "3.19.3" 15 }, 16 "bin": { ··· 19 "devDependencies": { 20 "@sindresorhus/tsconfig": "7.0.0", 21 "@types/csso": "^5.0.4", 22 + "@types/node": "^22.15.23", 23 "@types/uglify-js": "^3.17.5", 24 + "typescript": "5.8.3" 25 } 26 }, 27 "node_modules/@parcel/watcher": { ··· 351 } 352 }, 353 "node_modules/@types/node": { 354 + "version": "22.15.23", 355 + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.23.tgz", 356 + "integrity": "sha512-7Ec1zaFPF4RJ0eXu1YT/xgiebqwqoJz8rYPDi/O2BcZ++Wpt0Kq9cl0eg6NN6bYbPnR67ZLo7St5Q3UK0SnARw==", 357 "dev": true, 358 "license": "MIT", 359 "dependencies": { 360 + "undici-types": "~6.21.0" 361 } 362 }, 363 "node_modules/@types/uglify-js": { ··· 544 } 545 }, 546 "node_modules/sass": { 547 + "version": "1.89.0", 548 + "resolved": "https://registry.npmjs.org/sass/-/sass-1.89.0.tgz", 549 + "integrity": "sha512-ld+kQU8YTdGNjOLfRWBzewJpU5cwEv/h5yyqlSeJcj6Yh8U4TDA9UA5FPicqDz/xgRPWRSYIQNiFks21TbA9KQ==", 550 "license": "MIT", 551 "dependencies": { 552 "chokidar": "^4.0.0", ··· 596 } 597 }, 598 "node_modules/typescript": { 599 + "version": "5.8.3", 600 + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", 601 + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", 602 "dev": true, 603 "license": "Apache-2.0", 604 "bin": { ··· 622 } 623 }, 624 "node_modules/undici-types": { 625 + "version": "6.21.0", 626 + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", 627 + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", 628 "dev": true, 629 "license": "MIT" 630 }
+4 -4
package.json
··· 1 { 2 "name": "forking-build-shit", 3 - "version": "0.0.2", 4 "description": "Tiny script for preparing web assets for deployment", 5 "homepage": "https://github.com/CorySanin/build-shit#readme", 6 "bugs": { ··· 8 }, 9 "dependencies": { 10 "csso": "5.0.5", 11 - "sass": "1.86.0", 12 "uglify-js": "3.19.3" 13 }, 14 "devDependencies": { 15 "@sindresorhus/tsconfig": "7.0.0", 16 "@types/csso": "^5.0.4", 17 - "@types/node": "^22.13.10", 18 "@types/uglify-js": "^3.17.5", 19 - "typescript": "5.8.2" 20 }, 21 "repository": { 22 "type": "git",
··· 1 { 2 "name": "forking-build-shit", 3 + "version": "0.1.0", 4 "description": "Tiny script for preparing web assets for deployment", 5 "homepage": "https://github.com/CorySanin/build-shit#readme", 6 "bugs": { ··· 8 }, 9 "dependencies": { 10 "csso": "5.0.5", 11 + "sass": "1.89.0", 12 "uglify-js": "3.19.3" 13 }, 14 "devDependencies": { 15 "@sindresorhus/tsconfig": "7.0.0", 16 "@types/csso": "^5.0.4", 17 + "@types/node": "^22.15.23", 18 "@types/uglify-js": "^3.17.5", 19 + "typescript": "5.8.3" 20 }, 21 "repository": { 22 "type": "git",
+31 -17
src/build-shit.ts
··· 34 } 35 } 36 37 // Process styles 38 async function styles() { 39 await mkdir([STYLEOUTDIR, STYLESDIR]); 40 await emptyDir(STYLEOUTDIR); 41 - let styles: string[] = []; 42 - let files = await fsp.readdir(STYLESDIR); 43 await Promise.all(files.map(f => new Promise(async (res, reject) => { 44 - let p = path.join(STYLESDIR, f); 45 console.log(`Processing style ${p}`); 46 - let style = sass.compile(p).css; 47 if (f.charAt(0) !== '_') { 48 if (SQUASH.test(f)) { 49 styles.push(style); 50 } 51 else { 52 - let o = path.join(STYLEOUTDIR, f.substring(0, f.lastIndexOf('.')) + '.css'); 53 await fsp.writeFile(o, csso.minify(style).css); 54 console.log(`Wrote ${o}`); 55 } 56 } 57 res(0); 58 }))); 59 - let out = csso.minify(styles.join('\n')).css; 60 - let outpath = path.join(STYLEOUTDIR, STYLEOUTFILE); 61 await fsp.writeFile(outpath, out); 62 console.log(`Wrote ${outpath}`); 63 } ··· 66 async function scripts() { 67 await mkdir([SCRIPTSOUTDIR, SCRIPTSDIR]); 68 await emptyDir(SCRIPTSOUTDIR); 69 - let files = await fsp.readdir(SCRIPTSDIR); 70 await Promise.all(files.map(f => new Promise(async (res, reject) => { 71 - let p = path.join(SCRIPTSDIR, f); 72 - let o = path.join(SCRIPTSOUTDIR, f); 73 console.log(`Processing script ${p}`); 74 try { 75 await fsp.writeFile(o, uglifyjs.minify((await fsp.readFile(p)).toString()).code); ··· 84 85 // Process images 86 async function images(dir = '') { 87 - let p = path.join(IMAGESDIR, dir); 88 await mkdir(p); 89 if (dir.length === 0) { 90 await mkdir(IMAGESOUTDIR) 91 await emptyDir(IMAGESOUTDIR); 92 } 93 - let files = await fsp.readdir(p, { 94 withFileTypes: true 95 }); 96 if (files.length) { 97 await Promise.all(files.map(f => new Promise(async (res, reject) => { 98 if (f.isFile()) { 99 - let outDir = path.join(IMAGESOUTDIR, dir); 100 - let infile = path.join(p, f.name); 101 - let outfile = path.join(outDir, f.name.substring(0, f.name.lastIndexOf('.')) + '.webp'); 102 await mkdir(outDir); 103 console.log(`Processing image ${infile}`) 104 - let process = spawn('cwebp', ['-mt', '-q', '50', infile, '-o', outfile]); 105 - let timeout = setTimeout(() => { 106 reject('Timed out'); 107 process.kill(); 108 }, 30000);
··· 34 } 35 } 36 37 + function getFileExtension(filename: string) { 38 + const split = filename.split('.'); 39 + return split[split.length - 1].toLowerCase(); 40 + } 41 + 42 // Process styles 43 async function styles() { 44 await mkdir([STYLEOUTDIR, STYLESDIR]); 45 await emptyDir(STYLEOUTDIR); 46 + const styles: string[] = []; 47 + const files = await fsp.readdir(STYLESDIR); 48 await Promise.all(files.map(f => new Promise(async (res, reject) => { 49 + const p = path.join(STYLESDIR, f); 50 console.log(`Processing style ${p}`); 51 + const style = sass.compile(p).css; 52 if (f.charAt(0) !== '_') { 53 if (SQUASH.test(f)) { 54 styles.push(style); 55 } 56 else { 57 + const o = path.join(STYLEOUTDIR, f.substring(0, f.lastIndexOf('.')) + '.css'); 58 await fsp.writeFile(o, csso.minify(style).css); 59 console.log(`Wrote ${o}`); 60 } 61 } 62 res(0); 63 }))); 64 + const out = csso.minify(styles.join('\n')).css; 65 + const outpath = path.join(STYLEOUTDIR, STYLEOUTFILE); 66 await fsp.writeFile(outpath, out); 67 console.log(`Wrote ${outpath}`); 68 } ··· 71 async function scripts() { 72 await mkdir([SCRIPTSOUTDIR, SCRIPTSDIR]); 73 await emptyDir(SCRIPTSOUTDIR); 74 + const files = await fsp.readdir(SCRIPTSDIR); 75 await Promise.all(files.map(f => new Promise(async (res, reject) => { 76 + const p = path.join(SCRIPTSDIR, f); 77 + const o = path.join(SCRIPTSOUTDIR, f); 78 console.log(`Processing script ${p}`); 79 try { 80 await fsp.writeFile(o, uglifyjs.minify((await fsp.readFile(p)).toString()).code); ··· 89 90 // Process images 91 async function images(dir = '') { 92 + const p = path.join(IMAGESDIR, dir); 93 await mkdir(p); 94 if (dir.length === 0) { 95 await mkdir(IMAGESOUTDIR) 96 await emptyDir(IMAGESOUTDIR); 97 } 98 + const files = await fsp.readdir(p, { 99 withFileTypes: true 100 }); 101 if (files.length) { 102 await Promise.all(files.map(f => new Promise(async (res, reject) => { 103 if (f.isFile()) { 104 + const outDir = path.join(IMAGESOUTDIR, dir); 105 + const infile = path.join(p, f.name); 106 + const extension = getFileExtension(infile); 107 + const outfile = path.join(outDir, f.name.substring(0, f.name.lastIndexOf('.')) + '.webp'); 108 await mkdir(outDir); 109 console.log(`Processing image ${infile}`) 110 + const libwebpArgs = ['-mt']; 111 + if (extension === 'jpeg' || extension === 'jpg') { 112 + libwebpArgs.push('-q', '60'); 113 + } 114 + else { 115 + libwebpArgs.push('-near_lossless', '55'); 116 + } 117 + libwebpArgs.push(infile, '-o', outfile); 118 + const process = spawn('cwebp', libwebpArgs); 119 + const timeout = setTimeout(() => { 120 reject('Timed out'); 121 process.kill(); 122 }, 30000);