Tiny script for preparing web assets for deployment

initial commit

sanin.dev 20a8e7b3

+101
.gitignore
··· 1 + # Logs 2 + logs 3 + *.log 4 + npm-debug.log* 5 + yarn-debug.log* 6 + yarn-error.log* 7 + lerna-debug.log* 8 + 9 + # Diagnostic reports (https://nodejs.org/api/report.html) 10 + report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 + 12 + # Runtime data 13 + pids 14 + *.pid 15 + *.seed 16 + *.pid.lock 17 + 18 + # Directory for instrumented libs generated by jscoverage/JSCover 19 + lib-cov 20 + 21 + # Coverage directory used by tools like istanbul 22 + coverage 23 + *.lcov 24 + 25 + # nyc test coverage 26 + .nyc_output 27 + 28 + # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 + .grunt 30 + 31 + # Bower dependency directory (https://bower.io/) 32 + bower_components 33 + 34 + # node-waf configuration 35 + .lock-wscript 36 + 37 + # Compiled binary addons (https://nodejs.org/api/addons.html) 38 + build/Release 39 + 40 + # Dependency directories 41 + node_modules/ 42 + jspm_packages/ 43 + 44 + # TypeScript v1 declaration files 45 + typings/ 46 + 47 + # TypeScript cache 48 + *.tsbuildinfo 49 + 50 + # Optional npm cache directory 51 + .npm 52 + 53 + # Optional eslint cache 54 + .eslintcache 55 + 56 + # Microbundle cache 57 + .rpt2_cache/ 58 + .rts2_cache_cjs/ 59 + .rts2_cache_es/ 60 + .rts2_cache_umd/ 61 + 62 + # Optional REPL history 63 + .node_repl_history 64 + 65 + # Output of 'npm pack' 66 + *.tgz 67 + 68 + # Yarn Integrity file 69 + .yarn-integrity 70 + 71 + # dotenv environment variables file 72 + .env 73 + .env.test 74 + 75 + # parcel-bundler cache (https://parceljs.org/) 76 + .cache 77 + 78 + # next.js build output 79 + .next 80 + 81 + # nuxt.js build output 82 + .nuxt 83 + 84 + # gatsby files 85 + .cache/ 86 + public 87 + 88 + # vuepress build output 89 + .vuepress/dist 90 + 91 + # Serverless directories 92 + .serverless/ 93 + 94 + # FuseBox cache 95 + .fusebox/ 96 + 97 + # DynamoDB Local files 98 + .dynamodb/ 99 + 100 + distribution/* 101 + bin/*
+21
LICENSE
··· 1 + MIT License 2 + 3 + Copyright (c) 2020 Cory Sanin 4 + 5 + Permission is hereby granted, free of charge, to any person obtaining a copy 6 + of this software and associated documentation files (the "Software"), to deal 7 + in the Software without restriction, including without limitation the rights 8 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 + copies of the Software, and to permit persons to whom the Software is 10 + furnished to do so, subject to the following conditions: 11 + 12 + The above copyright notice and this permission notice shall be included in all 13 + copies or substantial portions of the Software. 14 + 15 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 + SOFTWARE.
+20
README.md
··· 1 + # build-shit 2 + A build script for preparing files for production. It handles CSS and JavaScript minification, Sass compilation, and image conversion to WebP. 3 + 4 + WebP conversion requires libwebp. 5 + 6 + ## Installation 7 + 8 + ``` 9 + npm install --save-dev build-shit 10 + ``` 11 + 12 + ## Usage 13 + 14 + build-shit processes files from the following relative directories: 15 + 16 + - `styles/` - Contains SCSS files 17 + - `scripts/` - Contains JavaScript files 18 + - `assets/images/original/` - Contains image files 19 + 20 + After populating these directories, run the build script with `npx build-shit`.
+632
package-lock.json
··· 1 + { 2 + "name": "build-shit", 3 + "version": "0.0.1", 4 + "lockfileVersion": 3, 5 + "requires": true, 6 + "packages": { 7 + "": { 8 + "name": "build-shit", 9 + "version": "0.0.1", 10 + "license": "MIT", 11 + "dependencies": { 12 + "csso": "5.0.5", 13 + "sass": "1.86.0", 14 + "uglify-js": "3.19.3" 15 + }, 16 + "bin": { 17 + "build-shit": "bin/build-shit.js" 18 + }, 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": { 28 + "version": "2.5.1", 29 + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", 30 + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", 31 + "hasInstallScript": true, 32 + "license": "MIT", 33 + "optional": true, 34 + "dependencies": { 35 + "detect-libc": "^1.0.3", 36 + "is-glob": "^4.0.3", 37 + "micromatch": "^4.0.5", 38 + "node-addon-api": "^7.0.0" 39 + }, 40 + "engines": { 41 + "node": ">= 10.0.0" 42 + }, 43 + "funding": { 44 + "type": "opencollective", 45 + "url": "https://opencollective.com/parcel" 46 + }, 47 + "optionalDependencies": { 48 + "@parcel/watcher-android-arm64": "2.5.1", 49 + "@parcel/watcher-darwin-arm64": "2.5.1", 50 + "@parcel/watcher-darwin-x64": "2.5.1", 51 + "@parcel/watcher-freebsd-x64": "2.5.1", 52 + "@parcel/watcher-linux-arm-glibc": "2.5.1", 53 + "@parcel/watcher-linux-arm-musl": "2.5.1", 54 + "@parcel/watcher-linux-arm64-glibc": "2.5.1", 55 + "@parcel/watcher-linux-arm64-musl": "2.5.1", 56 + "@parcel/watcher-linux-x64-glibc": "2.5.1", 57 + "@parcel/watcher-linux-x64-musl": "2.5.1", 58 + "@parcel/watcher-win32-arm64": "2.5.1", 59 + "@parcel/watcher-win32-ia32": "2.5.1", 60 + "@parcel/watcher-win32-x64": "2.5.1" 61 + } 62 + }, 63 + "node_modules/@parcel/watcher-android-arm64": { 64 + "version": "2.5.1", 65 + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", 66 + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", 67 + "cpu": [ 68 + "arm64" 69 + ], 70 + "license": "MIT", 71 + "optional": true, 72 + "os": [ 73 + "android" 74 + ], 75 + "engines": { 76 + "node": ">= 10.0.0" 77 + }, 78 + "funding": { 79 + "type": "opencollective", 80 + "url": "https://opencollective.com/parcel" 81 + } 82 + }, 83 + "node_modules/@parcel/watcher-darwin-arm64": { 84 + "version": "2.5.1", 85 + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", 86 + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", 87 + "cpu": [ 88 + "arm64" 89 + ], 90 + "license": "MIT", 91 + "optional": true, 92 + "os": [ 93 + "darwin" 94 + ], 95 + "engines": { 96 + "node": ">= 10.0.0" 97 + }, 98 + "funding": { 99 + "type": "opencollective", 100 + "url": "https://opencollective.com/parcel" 101 + } 102 + }, 103 + "node_modules/@parcel/watcher-darwin-x64": { 104 + "version": "2.5.1", 105 + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", 106 + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", 107 + "cpu": [ 108 + "x64" 109 + ], 110 + "license": "MIT", 111 + "optional": true, 112 + "os": [ 113 + "darwin" 114 + ], 115 + "engines": { 116 + "node": ">= 10.0.0" 117 + }, 118 + "funding": { 119 + "type": "opencollective", 120 + "url": "https://opencollective.com/parcel" 121 + } 122 + }, 123 + "node_modules/@parcel/watcher-freebsd-x64": { 124 + "version": "2.5.1", 125 + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", 126 + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", 127 + "cpu": [ 128 + "x64" 129 + ], 130 + "license": "MIT", 131 + "optional": true, 132 + "os": [ 133 + "freebsd" 134 + ], 135 + "engines": { 136 + "node": ">= 10.0.0" 137 + }, 138 + "funding": { 139 + "type": "opencollective", 140 + "url": "https://opencollective.com/parcel" 141 + } 142 + }, 143 + "node_modules/@parcel/watcher-linux-arm-glibc": { 144 + "version": "2.5.1", 145 + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", 146 + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", 147 + "cpu": [ 148 + "arm" 149 + ], 150 + "license": "MIT", 151 + "optional": true, 152 + "os": [ 153 + "linux" 154 + ], 155 + "engines": { 156 + "node": ">= 10.0.0" 157 + }, 158 + "funding": { 159 + "type": "opencollective", 160 + "url": "https://opencollective.com/parcel" 161 + } 162 + }, 163 + "node_modules/@parcel/watcher-linux-arm-musl": { 164 + "version": "2.5.1", 165 + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", 166 + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", 167 + "cpu": [ 168 + "arm" 169 + ], 170 + "license": "MIT", 171 + "optional": true, 172 + "os": [ 173 + "linux" 174 + ], 175 + "engines": { 176 + "node": ">= 10.0.0" 177 + }, 178 + "funding": { 179 + "type": "opencollective", 180 + "url": "https://opencollective.com/parcel" 181 + } 182 + }, 183 + "node_modules/@parcel/watcher-linux-arm64-glibc": { 184 + "version": "2.5.1", 185 + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", 186 + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", 187 + "cpu": [ 188 + "arm64" 189 + ], 190 + "license": "MIT", 191 + "optional": true, 192 + "os": [ 193 + "linux" 194 + ], 195 + "engines": { 196 + "node": ">= 10.0.0" 197 + }, 198 + "funding": { 199 + "type": "opencollective", 200 + "url": "https://opencollective.com/parcel" 201 + } 202 + }, 203 + "node_modules/@parcel/watcher-linux-arm64-musl": { 204 + "version": "2.5.1", 205 + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", 206 + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", 207 + "cpu": [ 208 + "arm64" 209 + ], 210 + "license": "MIT", 211 + "optional": true, 212 + "os": [ 213 + "linux" 214 + ], 215 + "engines": { 216 + "node": ">= 10.0.0" 217 + }, 218 + "funding": { 219 + "type": "opencollective", 220 + "url": "https://opencollective.com/parcel" 221 + } 222 + }, 223 + "node_modules/@parcel/watcher-linux-x64-glibc": { 224 + "version": "2.5.1", 225 + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", 226 + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", 227 + "cpu": [ 228 + "x64" 229 + ], 230 + "license": "MIT", 231 + "optional": true, 232 + "os": [ 233 + "linux" 234 + ], 235 + "engines": { 236 + "node": ">= 10.0.0" 237 + }, 238 + "funding": { 239 + "type": "opencollective", 240 + "url": "https://opencollective.com/parcel" 241 + } 242 + }, 243 + "node_modules/@parcel/watcher-linux-x64-musl": { 244 + "version": "2.5.1", 245 + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", 246 + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", 247 + "cpu": [ 248 + "x64" 249 + ], 250 + "license": "MIT", 251 + "optional": true, 252 + "os": [ 253 + "linux" 254 + ], 255 + "engines": { 256 + "node": ">= 10.0.0" 257 + }, 258 + "funding": { 259 + "type": "opencollective", 260 + "url": "https://opencollective.com/parcel" 261 + } 262 + }, 263 + "node_modules/@parcel/watcher-win32-arm64": { 264 + "version": "2.5.1", 265 + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", 266 + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", 267 + "cpu": [ 268 + "arm64" 269 + ], 270 + "license": "MIT", 271 + "optional": true, 272 + "os": [ 273 + "win32" 274 + ], 275 + "engines": { 276 + "node": ">= 10.0.0" 277 + }, 278 + "funding": { 279 + "type": "opencollective", 280 + "url": "https://opencollective.com/parcel" 281 + } 282 + }, 283 + "node_modules/@parcel/watcher-win32-ia32": { 284 + "version": "2.5.1", 285 + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", 286 + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", 287 + "cpu": [ 288 + "ia32" 289 + ], 290 + "license": "MIT", 291 + "optional": true, 292 + "os": [ 293 + "win32" 294 + ], 295 + "engines": { 296 + "node": ">= 10.0.0" 297 + }, 298 + "funding": { 299 + "type": "opencollective", 300 + "url": "https://opencollective.com/parcel" 301 + } 302 + }, 303 + "node_modules/@parcel/watcher-win32-x64": { 304 + "version": "2.5.1", 305 + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", 306 + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", 307 + "cpu": [ 308 + "x64" 309 + ], 310 + "license": "MIT", 311 + "optional": true, 312 + "os": [ 313 + "win32" 314 + ], 315 + "engines": { 316 + "node": ">= 10.0.0" 317 + }, 318 + "funding": { 319 + "type": "opencollective", 320 + "url": "https://opencollective.com/parcel" 321 + } 322 + }, 323 + "node_modules/@sindresorhus/tsconfig": { 324 + "version": "7.0.0", 325 + "resolved": "https://registry.npmjs.org/@sindresorhus/tsconfig/-/tsconfig-7.0.0.tgz", 326 + "integrity": "sha512-i5K04hLAP44Af16zmDjG07E1NHuDgCM07SJAT4gY0LZSRrWYzwt4qkLem6TIbIVh0k51RkN2bF+lP+lM5eC9fw==", 327 + "dev": true, 328 + "license": "MIT", 329 + "engines": { 330 + "node": ">=18" 331 + }, 332 + "funding": { 333 + "url": "https://github.com/sponsors/sindresorhus" 334 + } 335 + }, 336 + "node_modules/@types/css-tree": { 337 + "version": "2.3.10", 338 + "resolved": "https://registry.npmjs.org/@types/css-tree/-/css-tree-2.3.10.tgz", 339 + "integrity": "sha512-WcaBazJ84RxABvRttQjjFWgTcHvZR9jGr0Y3hccPkHjFyk/a3N8EuxjKr+QfrwjoM5b1yI1Uj1i7EzOAAwBwag==", 340 + "dev": true, 341 + "license": "MIT" 342 + }, 343 + "node_modules/@types/csso": { 344 + "version": "5.0.4", 345 + "resolved": "https://registry.npmjs.org/@types/csso/-/csso-5.0.4.tgz", 346 + "integrity": "sha512-W/FsRkm/9c04x9ON+bj+HQ0cSgNkG1LvcfuBCpkP7cpikM7+RkrNFLGtiofb++xBG6KGMUycLoDbi9/K621ZCw==", 347 + "dev": true, 348 + "license": "MIT", 349 + "dependencies": { 350 + "@types/css-tree": "*" 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": { 364 + "version": "3.17.5", 365 + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.17.5.tgz", 366 + "integrity": "sha512-TU+fZFBTBcXj/GpDpDaBmgWk/gn96kMZ+uocaFUlV2f8a6WdMzzI44QBCmGcCiYR0Y6ZlNRiyUyKKt5nl/lbzQ==", 367 + "dev": true, 368 + "license": "MIT", 369 + "dependencies": { 370 + "source-map": "^0.6.1" 371 + } 372 + }, 373 + "node_modules/braces": { 374 + "version": "3.0.3", 375 + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", 376 + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", 377 + "license": "MIT", 378 + "optional": true, 379 + "dependencies": { 380 + "fill-range": "^7.1.1" 381 + }, 382 + "engines": { 383 + "node": ">=8" 384 + } 385 + }, 386 + "node_modules/chokidar": { 387 + "version": "4.0.3", 388 + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", 389 + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", 390 + "license": "MIT", 391 + "dependencies": { 392 + "readdirp": "^4.0.1" 393 + }, 394 + "engines": { 395 + "node": ">= 14.16.0" 396 + }, 397 + "funding": { 398 + "url": "https://paulmillr.com/funding/" 399 + } 400 + }, 401 + "node_modules/css-tree": { 402 + "version": "2.2.1", 403 + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", 404 + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", 405 + "license": "MIT", 406 + "dependencies": { 407 + "mdn-data": "2.0.28", 408 + "source-map-js": "^1.0.1" 409 + }, 410 + "engines": { 411 + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", 412 + "npm": ">=7.0.0" 413 + } 414 + }, 415 + "node_modules/csso": { 416 + "version": "5.0.5", 417 + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", 418 + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", 419 + "license": "MIT", 420 + "dependencies": { 421 + "css-tree": "~2.2.0" 422 + }, 423 + "engines": { 424 + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", 425 + "npm": ">=7.0.0" 426 + } 427 + }, 428 + "node_modules/detect-libc": { 429 + "version": "1.0.3", 430 + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", 431 + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", 432 + "license": "Apache-2.0", 433 + "optional": true, 434 + "bin": { 435 + "detect-libc": "bin/detect-libc.js" 436 + }, 437 + "engines": { 438 + "node": ">=0.10" 439 + } 440 + }, 441 + "node_modules/fill-range": { 442 + "version": "7.1.1", 443 + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", 444 + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", 445 + "license": "MIT", 446 + "optional": true, 447 + "dependencies": { 448 + "to-regex-range": "^5.0.1" 449 + }, 450 + "engines": { 451 + "node": ">=8" 452 + } 453 + }, 454 + "node_modules/immutable": { 455 + "version": "5.0.3", 456 + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.3.tgz", 457 + "integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==", 458 + "license": "MIT" 459 + }, 460 + "node_modules/is-extglob": { 461 + "version": "2.1.1", 462 + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 463 + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 464 + "license": "MIT", 465 + "optional": true, 466 + "engines": { 467 + "node": ">=0.10.0" 468 + } 469 + }, 470 + "node_modules/is-glob": { 471 + "version": "4.0.3", 472 + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 473 + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 474 + "license": "MIT", 475 + "optional": true, 476 + "dependencies": { 477 + "is-extglob": "^2.1.1" 478 + }, 479 + "engines": { 480 + "node": ">=0.10.0" 481 + } 482 + }, 483 + "node_modules/is-number": { 484 + "version": "7.0.0", 485 + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 486 + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 487 + "license": "MIT", 488 + "optional": true, 489 + "engines": { 490 + "node": ">=0.12.0" 491 + } 492 + }, 493 + "node_modules/mdn-data": { 494 + "version": "2.0.28", 495 + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", 496 + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", 497 + "license": "CC0-1.0" 498 + }, 499 + "node_modules/micromatch": { 500 + "version": "4.0.8", 501 + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", 502 + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", 503 + "license": "MIT", 504 + "optional": true, 505 + "dependencies": { 506 + "braces": "^3.0.3", 507 + "picomatch": "^2.3.1" 508 + }, 509 + "engines": { 510 + "node": ">=8.6" 511 + } 512 + }, 513 + "node_modules/node-addon-api": { 514 + "version": "7.1.1", 515 + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", 516 + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", 517 + "license": "MIT", 518 + "optional": true 519 + }, 520 + "node_modules/picomatch": { 521 + "version": "2.3.1", 522 + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 523 + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 524 + "license": "MIT", 525 + "optional": true, 526 + "engines": { 527 + "node": ">=8.6" 528 + }, 529 + "funding": { 530 + "url": "https://github.com/sponsors/jonschlinkert" 531 + } 532 + }, 533 + "node_modules/readdirp": { 534 + "version": "4.1.2", 535 + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", 536 + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", 537 + "license": "MIT", 538 + "engines": { 539 + "node": ">= 14.18.0" 540 + }, 541 + "funding": { 542 + "type": "individual", 543 + "url": "https://paulmillr.com/funding/" 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", 553 + "immutable": "^5.0.2", 554 + "source-map-js": ">=0.6.2 <2.0.0" 555 + }, 556 + "bin": { 557 + "sass": "sass.js" 558 + }, 559 + "engines": { 560 + "node": ">=14.0.0" 561 + }, 562 + "optionalDependencies": { 563 + "@parcel/watcher": "^2.4.1" 564 + } 565 + }, 566 + "node_modules/source-map": { 567 + "version": "0.6.1", 568 + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 569 + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 570 + "dev": true, 571 + "license": "BSD-3-Clause", 572 + "engines": { 573 + "node": ">=0.10.0" 574 + } 575 + }, 576 + "node_modules/source-map-js": { 577 + "version": "1.2.1", 578 + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", 579 + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", 580 + "license": "BSD-3-Clause", 581 + "engines": { 582 + "node": ">=0.10.0" 583 + } 584 + }, 585 + "node_modules/to-regex-range": { 586 + "version": "5.0.1", 587 + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 588 + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 589 + "license": "MIT", 590 + "optional": true, 591 + "dependencies": { 592 + "is-number": "^7.0.0" 593 + }, 594 + "engines": { 595 + "node": ">=8.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": { 605 + "tsc": "bin/tsc", 606 + "tsserver": "bin/tsserver" 607 + }, 608 + "engines": { 609 + "node": ">=14.17" 610 + } 611 + }, 612 + "node_modules/uglify-js": { 613 + "version": "3.19.3", 614 + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", 615 + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", 616 + "license": "BSD-2-Clause", 617 + "bin": { 618 + "uglifyjs": "bin/uglifyjs" 619 + }, 620 + "engines": { 621 + "node": ">=0.8.0" 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 + } 631 + } 632 + }
+39
package.json
··· 1 + { 2 + "name": "build-shit", 3 + "version": "0.0.1", 4 + "description": "Tiny script for preparing web assets for deployment", 5 + "homepage": "https://github.com/CorySanin/build-shit#readme", 6 + "bugs": { 7 + "url": "https://github.com/CorySanin/build-shit/issues" 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", 23 + "url": "git+https://github.com/CorySanin/build-shit.git" 24 + }, 25 + "license": "MIT", 26 + "author": { 27 + "name": "Cory Sanin", 28 + "email": "corysanin@artixlinux.org", 29 + "url": "https://sanin.dev" 30 + }, 31 + "type": "module", 32 + "main": "bin/build-shit.js", 33 + "bin": { 34 + "build-shit": "./bin/build-shit.js" 35 + }, 36 + "scripts": { 37 + "build": "tsc" 38 + } 39 + }
+173
src/build-shit.ts
··· 1 + #!/usr/bin/env node 2 + 3 + import fs from 'fs'; 4 + import path from 'path'; 5 + import child_process from 'child_process'; 6 + import uglifyjs from "uglify-js"; 7 + import * as sass from 'sass'; 8 + import * as csso from 'csso'; 9 + 10 + const spawn = child_process.spawn; 11 + const fsp = fs.promises; 12 + const STYLESDIR = 'styles'; 13 + const SCRIPTSDIR = 'scripts'; 14 + const IMAGESDIR = path.join('assets', 'images', 'original'); 15 + const STYLEOUTDIR = process.env.STYLEOUTDIR || path.join(import.meta.dirname, 'assets', 'css'); 16 + const SCRIPTSOUTDIR = process.env.SCRIPTSOUTDIR || path.join(import.meta.dirname, 'assets', 'js'); 17 + const IMAGESOUTDIR = process.env.IMAGESOUTDIR || path.join(import.meta.dirname, 'assets', 'images', 'webp'); 18 + const STYLEOUTFILE = process.env.STYLEOUTFILE || 'styles.css'; 19 + const SQUASH = new RegExp('^[0-9]+-'); 20 + 21 + async function emptyDir(dir: string) { 22 + await Promise.all((await fsp.readdir(dir, { withFileTypes: true })).map(f => path.join(dir, f.name)).map(p => fsp.rm(p, { 23 + recursive: true, 24 + force: true 25 + }))); 26 + } 27 + 28 + async function mkdir(dir: string | string[]) { 29 + if (typeof dir === 'string') { 30 + await fsp.mkdir(dir, { recursive: true }); 31 + } 32 + else { 33 + await Promise.all(dir.map(mkdir)); 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 + } 64 + 65 + // Process scripts 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); 76 + console.log(`Wrote ${o}`); 77 + } 78 + catch (ex) { 79 + console.log(`error writing ${o}: ${ex}`); 80 + } 81 + res(0); 82 + }))); 83 + } 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); 109 + process.on('exit', async (code) => { 110 + clearTimeout(timeout); 111 + if (code === 0) { 112 + console.log(`Wrote ${outfile}`); 113 + res(null); 114 + } 115 + else { 116 + reject(code); 117 + } 118 + }); 119 + } 120 + else if (f.isDirectory()) { 121 + images(path.join(dir, f.name)).then(res).catch(reject); 122 + } 123 + }))); 124 + } 125 + } 126 + 127 + function isAbortError(err: unknown): boolean { 128 + return typeof err === 'object' && err !== null && 'name' in err && err.name === 'AbortError'; 129 + } 130 + 131 + (async function () { 132 + await Promise.all([styles(), scripts(), images()]); 133 + if (process.argv.indexOf('--watch') >= 0) { 134 + console.log('watching for changes...'); 135 + (async () => { 136 + try { 137 + const watcher = fsp.watch(STYLESDIR); 138 + for await (const _ of watcher) 139 + await styles(); 140 + } catch (err) { 141 + if (isAbortError(err)) 142 + return; 143 + throw err; 144 + } 145 + })(); 146 + 147 + (async () => { 148 + try { 149 + const watcher = fsp.watch(SCRIPTSDIR); 150 + for await (const _ of watcher) 151 + await scripts(); 152 + } catch (err) { 153 + if (isAbortError(err)) 154 + return; 155 + throw err; 156 + } 157 + })(); 158 + 159 + (async () => { 160 + try { 161 + const watcher = fsp.watch(IMAGESDIR, { 162 + recursive: true // no Linux ☹️ 163 + }); 164 + for await (const _ of watcher) 165 + await images(); 166 + } catch (err) { 167 + if (isAbortError(err)) 168 + return; 169 + throw err; 170 + } 171 + })(); 172 + } 173 + })();
+19
tsconfig.json
··· 1 + { 2 + "compilerOptions": { 3 + "lib": [ 4 + "ESNext" 5 + ], 6 + "module": "NodeNext", 7 + "target": "ESNext", 8 + "esModuleInterop": true, 9 + "skipLibCheck": true, 10 + "moduleResolution": "node16", 11 + "outDir": "./bin" 12 + }, 13 + "include": [ 14 + "src/**/*" 15 + ], 16 + "exclude": [ 17 + "**/*.spec.ts" 18 + ] 19 + }