From f7a34a5d55865f391ca7fdfab1394330f48a9030 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Sat, 7 Oct 2023 17:08:32 +1100 Subject: [PATCH] Introduce script to purge orphaned assets --- bin/purge-orphaned-assets.js | 91 ++++++++++++++++++++++++++++++++++++ package.json | 4 ++ 2 files changed, 95 insertions(+) create mode 100755 bin/purge-orphaned-assets.js diff --git a/bin/purge-orphaned-assets.js b/bin/purge-orphaned-assets.js new file mode 100755 index 0000000..6a3364e --- /dev/null +++ b/bin/purge-orphaned-assets.js @@ -0,0 +1,91 @@ +#!/usr/bin/env node + +import { readFileSync, readdirSync, unlinkSync } from 'fs' +import { dirname } from 'path' + +/* + * Argv helpers. + */ + +const argument = (name, fallback) => { + const index = process.argv.findIndex(argument => argument.startsWith(`--${name}=`)) + + return index === -1 + ? fallback() + : process.argv[index].substring(`--${name}=`.length) +} + +const option = (name) => process.argv.includes(`--${name}`) + +/* + * Configuration. + */ + +const dryRun = option(`dry-run`) +const quiet = option(`quiet`) +const wantsSsr = option('ssr') +const manifestPath = argument(`manifest`, () => wantsSsr ? `./bootstrap/ssr/ssr-manifest.json` : `./public/build/manifest.json`) +const assetsDirectory = argument(`assets`, () => `${dirname(manifestPath)}/assets`) + +/* + * Helpers. + */ + +const write = quiet ? (() => undefined) : console.log + +/* + * Clean. + */ + +const main = () => { + write(`Reading manifest [${manifestPath}].`) + + const manifest = JSON.parse(readFileSync(manifestPath).toString()) + + const manifestKeys = Object.keys(manifest) + + const isSsr = Array.isArray(manifest[manifestKeys[0]]) + + if (wantsSsr && ! isSsr) { + write('Did not find an SSR manifest.') + + process.exit(1) + } + + isSsr + ? write(`SSR manifest found.`) + : write(`Non-SSR manifest found.`) + + const manifestAssets = isSsr + ? manifestKeys.flatMap(key => manifest[key]) + : manifestKeys.map(key => manifest[key].file) + + write(`Verify assets in [${assetsDirectory}].`) + + const allAssets = readdirSync(assetsDirectory, { withFileTypes: true }) + + const orphanedAssets = allAssets.filter(file => file.isFile()) + .filter(file => manifestAssets.findIndex(asset => asset.endsWith(`/${file.name}`)) === -1) + + if (orphanedAssets.length === 0) { + write(`No ophaned assets found.`) + } else { + orphanedAssets.length === 1 + ? write(`[${orphanedAssets.length}] orphaned asset found.`) + : write(`[${orphanedAssets.length}] orphaned assets found.`) + + orphanedAssets.forEach(asset => { + const path = `${assetsDirectory}/${asset.name}` + + dryRun + ? write(`Orphaned asset [${path}] would be removed.`) + : write(`Removing orphaned asset [${path}].`) + + if (! dryRun) { + unlinkSync(path) + } + }) + } +} + +main() diff --git a/package.json b/package.json index 30a103a..ec198df 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "name": "laravel-vite-plugin", + "type": "module", "version": "0.8.1", "description": "Laravel plugin for Vite.", "keywords": [ @@ -30,6 +31,9 @@ "/dist", "/inertia-helpers" ], + "bin": { + "purge-orphaned-assets": "bin/purge-orphaned-assets.js" + }, "scripts": { "build": "npm run build-plugin && npm run build-inertia-helpers", "build-plugin": "rm -rf dist && npm run build-plugin-types && npm run build-plugin-esm && cp src/dev-server-index.html dist/",