vite-plugin-foundryvtt
Version:
Plugin for building for foundryvtt. Enables hmr and manifest substitution.
107 lines (104 loc) • 3.28 kB
JavaScript
import fs from 'node:fs';
import path from 'node:path';
import { compilePack } from '@foundryvtt/foundryvtt-cli';
import { ClassicLevel } from 'classic-level';
import { mergeConfig } from 'vite';
async function isLocked(dest) {
try {
const db = new ClassicLevel(dest);
await db.open();
await db.close();
} catch {
return true;
}
return false;
}
function foundryvtt(manifest, {
substitutions = {},
type = "system",
packDir = "src/packs",
buildPacks = true,
packOptions = { yaml: true }
} = {}) {
for (const [k, v] of Object.entries(substitutions))
if (v === void 0) delete substitutions[k];
let outdir;
let pubdir;
const hotReload = manifest.flags?.hotReload || null;
const extensions = hotReload?.extensions.map((e) => e);
const paths = hotReload?.paths?.map((e) => e) ?? [""];
return {
name: "foundryvtt-config",
config(cfg, { command }) {
if (command === "build") cfg.base = "./";
cfg.build ??= {};
cfg.build.rollupOptions ??= {};
cfg.build.rollupOptions.output ??= {};
const afn = {
assetFileNames: ({ names: [name] }) => name?.endsWith(".css") ? `styles/${name}` : name ?? "assets/[name]-[hash][extname]"
};
if (Array.isArray(cfg.build.rollupOptions.output)) {
cfg.build.rollupOptions.output.push(afn);
} else {
cfg.build.rollupOptions.output = mergeConfig(
cfg.build.rollupOptions.output,
afn
);
}
return cfg;
},
async configResolved(cfg) {
outdir = cfg.build.outDir;
pubdir = cfg.publicDir;
for (const pack of manifest.packs ?? []) {
if (!buildPacks) break;
const dest = path.resolve(
outdir,
pack.path ?? path.resolve("packs", pack.name)
);
if (await isLocked(dest)) buildPacks = false;
}
},
generateBundle() {
const data = mergeConfig(manifest, substitutions);
const source = JSON.stringify(data, null, 2);
this.emitFile({ type: "asset", fileName: `${type}.json`, source });
},
async writeBundle() {
const packs = manifest.packs?.map((p) => ({
...p,
src: path.resolve(packDir, p.name),
dest: path.resolve(outdir, p.path ?? path.resolve("packs", p.name))
}));
if (!buildPacks || !packs) return;
for (const p of packs) {
try {
await compilePack(p.src, p.dest, packOptions);
this.info(`Built pack ${p.name}`);
} catch (e) {
if (e instanceof Error) this.warn(e);
}
}
buildPacks = false;
},
handleHotUpdate({ file }) {
if (!hotReload || !extensions) return;
if (!file.startsWith(pubdir)) return;
const file_path = path.relative(pubdir, file);
const ext = path.extname(file_path).slice(1);
if (!extensions.includes(ext) || !paths.some((p) => file_path.startsWith(p)))
return;
const dest = path.resolve(outdir, file_path);
const k = {
css: "css",
json: "language",
html: "template",
hbs: "template",
"": ""
};
console.log(`Hot updating ${k[ext.toLowerCase()]} file '${file_path}'`);
fs.copyFileSync(file, dest);
}
};
}
export { foundryvtt as default };