Skip to content

Instantly share code, notes, and snippets.

@justisr
Last active November 24, 2023 21:16
Show Gist options
  • Save justisr/4fdaeb9635c685c1082ea8e6eb8f2d06 to your computer and use it in GitHub Desktop.
Save justisr/4fdaeb9635c685c1082ea8e6eb8f2d06 to your computer and use it in GitHub Desktop.
import { readdir, rm, mkdir, rename } from 'node:fs/promises';
import { join, resolve } from 'path';
const start = performance.now();
const srcDir = join('src', 'main', 'resources', '_static');
const targetDir = join('target', 'classes', '_static');
async function fileHash(file) {
const md5Hasher = new Bun.CryptoHasher('md5');
return md5Hasher.update(await file.text()).digest('hex').substring(0, 16);
}
async function deleteExistingOutput() {
await Promise.all(['styles', 'js'].map(async resource => {
const folder = join(targetDir, resource);
await rm(folder, { recursive: true });
await mkdir(folder);
}));
}
async function exportTailwind() {
const tailwindInput = join(srcDir, 'styles', 'style.css');
const tailwindOutput = join(targetDir, 'styles', `style.min.css`);
const exitCode = await Bun.spawn([join('node_modules', 'bun', 'bin', 'bun'), 'tailwindcss', '-i', tailwindInput, '-o', tailwindOutput, '--minify'], {stdio: ['inherit', 'ignore', 'ignore']}).exited;
if (exitCode !== 0) console.error("TailwindCSS bundling failed with exit code ", exitCode);
await rename(tailwindOutput, join(targetDir, 'styles', `style--${await fileHash(Bun.file(tailwindOutput))}.min.css`));
return exitCode === 0;
}
async function exportBundles() {
const plugins = [
{
name: 'export-css',
setup: (build) => {
build.onLoad({filter: /\.css$/}, async ({path}) => {
const fileName = path.replace(/.*\//, '').replace(/(--.*)?\..+$/, '');
const inputFile = Bun.file(path);
const outputName = `${fileName}--${await fileHash(inputFile)}.min.css`;
const outputFile = Bun.file(join(targetDir, 'styles', outputName));
await Bun.write(outputFile, inputFile);
return { contents: `window.requires('/_static/styles/${outputName}');`, loader: 'js' }
});
}
},
{
name: 'inject-local',
setup: (build) => {
build.onResolve({filter: /local_modules/}, async ({path}) => {
const newPath = join(resolve(), path);
return { path: newPath, loader: 'js' };
});
}
}
];
const jsPath = join(srcDir, 'js');
const build = await Bun.build({
entrypoints: (await readdir(jsPath)).map(fn => join(jsPath, fn)),
outdir: join(targetDir, 'js'),
minify: {
whitespace: true,
identifiers: true,
syntax: true,
},
sourcemap: 'external',
target: 'browser',
naming: '[name]--[hash].min.[ext]',
plugins: plugins
});
if (!build.success) console.error("Bun build failed with the following logs: ", build.logs);
return build.success;
}
await deleteExistingOutput();
const result = await Promise.all([exportTailwind(), exportBundles()]);
if (result.includes(false)) console.error("Resource bundling failed, see console for details");
else console.log(`Resource bundling completed in ${Math.round(performance.now() - start)}ms`);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment