155 lines
3.8 KiB
TypeScript
155 lines
3.8 KiB
TypeScript
import brotliPromise from "brotli-wasm";
|
|
import { spawn } from "bun";
|
|
import { dir } from "dir";
|
|
import { Plugin, context } from "esbuild";
|
|
import { $ } from "execa";
|
|
import { fdir } from "fdir";
|
|
import { statSync } from "fs";
|
|
import {
|
|
listAsync,
|
|
removeAsync,
|
|
writeAsync,
|
|
inspectTree,
|
|
existsAsync,
|
|
copyAsync,
|
|
} from "fs-jetpack";
|
|
const brotli = await brotliPromise;
|
|
|
|
await removeAsync(dir.path("app/web/.parcel-cache"));
|
|
await removeAsync(dir.path("app/static"));
|
|
|
|
const args = [
|
|
"node",
|
|
dir.path("node_modules/.bin/parcel"),
|
|
"build",
|
|
"./src/index.tsx",
|
|
// "--no-optimize",
|
|
"--no-scope-hoist",
|
|
"--dist-dir",
|
|
dir.path(`app/static`),
|
|
];
|
|
|
|
const parcel = spawn({
|
|
cmd: args,
|
|
cwd: dir.path("app/web"),
|
|
stdio: ["ignore", "inherit", "inherit"],
|
|
});
|
|
await parcel.exited;
|
|
|
|
const public_br = dir.path("app/web/public-br");
|
|
if (!(await existsAsync(public_br))) {
|
|
const api = new fdir().withRelativePaths().crawl(dir.path("app/web/public"));
|
|
const files = api.sync();
|
|
if (files) {
|
|
await Promise.all(
|
|
files.map(async (file) => {
|
|
const br = brotli.compress(
|
|
new Uint8Array(
|
|
await Bun.file(dir.path(`app/web/public/${file}`)).arrayBuffer()
|
|
),
|
|
{ quality: 11 }
|
|
);
|
|
if (br) {
|
|
console.log(`Compressing ${file}`);
|
|
await writeAsync(
|
|
dir.path(`app/web/public-br/${file}`),
|
|
Buffer.from(br)
|
|
);
|
|
}
|
|
})
|
|
);
|
|
}
|
|
}
|
|
|
|
const static_br = dir.path("app/static-br");
|
|
await removeAsync(static_br);
|
|
const files = await listAsync(dir.path("app/static"));
|
|
if (files) {
|
|
await Promise.all(
|
|
files
|
|
.filter((file) => statSync(dir.path(`app/static/${file}`)).isFile())
|
|
.map(async (file) => {
|
|
if (!(await Bun.file(dir.path(`app/static-br/${file}`)).exists())) {
|
|
const br = brotli.compress(
|
|
new Uint8Array(
|
|
await Bun.file(dir.path(`app/static/${file}`)).arrayBuffer()
|
|
),
|
|
{ quality: 11 }
|
|
);
|
|
if (br) {
|
|
console.log(`Compressing ${file}`);
|
|
await writeAsync(
|
|
dir.path(`app/static-br/${file}`),
|
|
Buffer.from(br)
|
|
);
|
|
}
|
|
}
|
|
})
|
|
);
|
|
|
|
const pub = await listAsync(dir.path("app/web/public-br"));
|
|
if (pub) {
|
|
await Promise.all(
|
|
pub.map((file) =>
|
|
copyAsync(
|
|
dir.path(`app/web/public-br/${file}`),
|
|
dir.path(`app/static-br/${file}`),
|
|
{ overwrite: true }
|
|
)
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
const buildSite = async () => {
|
|
await removeAsync(dir.path("app/srv/site"));
|
|
const onEndPlugin: Plugin = {
|
|
name: "on-end",
|
|
setup(build) {
|
|
build.onEnd(async (result) => {
|
|
console.log("Compressing deploy");
|
|
await removeAsync(dir.path("app/srv/site.zip"));
|
|
await $({ cwd: dir.path("app/srv") })`zip -r site.zip site`;
|
|
process.exit(0);
|
|
});
|
|
},
|
|
};
|
|
|
|
console.log("Building deploy");
|
|
const ctx = await context({
|
|
bundle: true,
|
|
absWorkingDir: dir.path(""),
|
|
entryPoints: [dir.path("app/web/src/render/site/site.tsx")],
|
|
outdir: dir.path("app/srv/site"),
|
|
splitting: true,
|
|
format: "esm",
|
|
jsx: "transform",
|
|
minify: true,
|
|
sourcemap: true,
|
|
logLevel: "error",
|
|
plugins: [onEndPlugin],
|
|
define: {
|
|
"process.env.NODE_ENV": `"production"`,
|
|
},
|
|
});
|
|
await ctx.rebuild();
|
|
await writeAsync(
|
|
dir.path("app/srv/site/index.html"),
|
|
`
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title></title>
|
|
<link rel="stylesheet" href="https://prasi.app/index.css">
|
|
</head>
|
|
<body class="flex-col flex-1 w-full min-h-screen flex opacity-0">
|
|
<div id="root"></div>
|
|
<script src="/site.js" type="module"></script>
|
|
</body>
|
|
</html>`
|
|
);
|
|
};
|
|
await buildSite();
|