Files
finos--perspective/docs/build.config.mjs
T
2026-07-13 12:23:53 +08:00

177 lines
6.6 KiB
JavaScript

// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
// ┃ This file is part of the Perspective library, distributed under the terms ┃
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
import * as esbuild from "esbuild";
import * as fs from "node:fs";
import * as path from "node:path";
import { createRequire } from "module";
import { bundleAsync as bundleCssAsync, composeVisitors } from "lightningcss";
import { fileURLToPath } from "node:url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const DIST = path.join(__dirname, "dist");
function copyRecursive(src, dest) {
if (!fs.existsSync(src)) return;
const stat = fs.statSync(src);
if (stat.isDirectory()) {
fs.mkdirSync(dest, { recursive: true });
for (const child of fs.readdirSync(src)) {
copyRecursive(path.join(src, child), path.join(dest, child));
}
} else {
fs.copyFileSync(src, dest);
}
}
// Inline url() asset references as data URIs.
export function inlineUrlVisitor(fromFile) {
const dir = path.dirname(fromFile);
return composeVisitors([
{
Url(url) {
const ext = path.extname(url.url).toLowerCase();
if (![".svg", ".png", ".gif"].includes(ext)) {
return;
}
const resolved = path.resolve(dir, url.url);
if (!fs.existsSync(resolved)) {
throw new Error(`File not found ${url.url}`);
// return;
}
const content = fs.readFileSync(resolved);
const mime =
ext === ".svg"
? "image/svg+xml"
: ext === ".png"
? "image/png"
: "image/gif";
const new_content = content
.toString("base64")
.split("\n")
.map((x) => x.trim())
.join("");
return {
url: `data:${mime};base64,${new_content}`,
loc: url.loc,
};
},
},
]);
}
export const resolveNPM = (url) => ({
read(filePath) {
if (filePath.startsWith("http")) {
return `@import url("${filePath}");`;
}
return fs.readFileSync(filePath, "utf8");
},
resolve(specifier, from) {
if (specifier.startsWith("http")) {
return { external: specifier };
}
const _require = createRequire(url);
if (specifier.startsWith(".") || specifier.startsWith("/")) {
return path.resolve(path.dirname(from), specifier);
}
return _require.resolve(specifier);
},
});
async function build() {
// Clean and create dist
fs.mkdirSync(DIST, { recursive: true });
// Bundle CSS
const { code: cssCode } = await bundleCssAsync({
filename: path.join(__dirname, "./src/css/style.css"),
minify: true,
resolver: resolveNPM(import.meta.url),
visitor: inlineUrlVisitor("./src/css/style.css"),
});
fs.mkdirSync(path.join(DIST, "css"), { recursive: true });
fs.writeFileSync(path.join(DIST, "style.css"), cssCode);
// Bundle JS entry points
await esbuild.build({
entryPoints: [
path.join(__dirname, "src/index.ts"),
path.join(__dirname, "src/examples.ts"),
path.join(__dirname, "src/block.ts"),
],
bundle: true,
splitting: true,
format: "esm",
outdir: DIST,
minify: true,
sourcemap: true,
target: ["es2022"],
define: {
global: "window",
},
loader: {
".wasm": "file",
".arrow": "file",
},
});
// Copy HTML files
for (const html of ["index.html", "examples.html", "block.html"]) {
fs.copyFileSync(
path.join(__dirname, "src", html),
path.join(DIST, html),
);
}
// Copy static assets
copyRecursive(path.join(__dirname, "static"), DIST);
// Generate blocks manifest
const blocksDir = path.join(DIST, "blocks");
if (fs.existsSync(blocksDir)) {
const manifest = {};
for (const example of fs.readdirSync(blocksDir)) {
const exDir = path.join(blocksDir, example);
if (!fs.statSync(exDir).isDirectory()) continue;
manifest[example] = fs
.readdirSync(exDir)
.filter(
(f) =>
!f.startsWith(".") &&
!f.endsWith(".png") &&
!f.endsWith(".arrow"),
);
}
fs.writeFileSync(
path.join(blocksDir, "manifest.json"),
JSON.stringify(manifest),
);
}
console.log("Build complete: dist/");
}
build().catch((e) => {
console.error(e);
process.exit(1);
});