mirror of
https://github.com/quartz-community/fonts.git
synced 2026-07-22 03:00:28 +00:00
116 lines
3.6 KiB
TypeScript
116 lines
3.6 KiB
TypeScript
import { defineConfig } from "tsup";
|
|
import type { Plugin } from "esbuild";
|
|
import path from "path";
|
|
/**
|
|
* Esbuild plugin that bundles `.inline.ts` files into browser-ready JavaScript strings.
|
|
*
|
|
* Problem: Inline scripts are embedded as raw text into `<script>` tags in the browser.
|
|
* The previous text-loader read `.inline.ts` files verbatim, meaning TypeScript syntax
|
|
* (type annotations, `as` casts, non-null assertions, interfaces) survived into the
|
|
* browser and caused parse errors.
|
|
*
|
|
* Solution: Use `esbuild.build()` to transpile TypeScript and bundle local/npm imports
|
|
* into a single self-contained script. The result is returned as a text string that can
|
|
* be safely injected into a `<script>` tag.
|
|
*
|
|
* This mirrors Quartz v5's own `inline-script-loader` in `quartz/cli/handlers.js`.
|
|
*/
|
|
const inlineScriptPlugin: Plugin = {
|
|
name: "inline-script-loader",
|
|
setup(parentBuild) {
|
|
const absWorkingDir = parentBuild.initialOptions.absWorkingDir ?? process.cwd();
|
|
|
|
// SCSS files are compiled to CSS via sass, matching Quartz v5 core behavior
|
|
parentBuild.onLoad({ filter: /\.scss$/ }, async (args) => {
|
|
const sass = await import("sass");
|
|
const result = sass.compile(args.path);
|
|
return { contents: result.css, loader: "text" };
|
|
});
|
|
|
|
// Inline TypeScript files are transpiled + bundled for the browser
|
|
parentBuild.onLoad({ filter: /\.inline\.ts$/ }, async (args) => {
|
|
const esbuild = await import("esbuild");
|
|
const fs = await import("fs");
|
|
let text = await fs.promises.readFile(args.path, "utf8");
|
|
|
|
// Strip export statements that were added for the module system —
|
|
// inline scripts run in a <script> tag, not as ES modules
|
|
text = text.replace(/^export default /gm, "");
|
|
text = text.replace(/^export /gm, "");
|
|
|
|
const resolveDir = path.dirname(args.path);
|
|
const sourcefile = path.relative(absWorkingDir, args.path);
|
|
|
|
const result = await esbuild.build({
|
|
stdin: {
|
|
contents: text,
|
|
loader: "ts",
|
|
resolveDir,
|
|
sourcefile,
|
|
},
|
|
write: false,
|
|
bundle: true,
|
|
minify: true,
|
|
platform: "browser",
|
|
format: "esm",
|
|
target: "es2020",
|
|
sourcemap: false,
|
|
// Preserve dynamic CDN imports (e.g. graph plugin loading d3/pixi from CDN)
|
|
external: ["http://*", "https://*"],
|
|
});
|
|
|
|
const js = result.outputFiles?.[0]?.text;
|
|
if (!js) throw new Error(`inline-script-loader: no JS output for ${args.path}`);
|
|
|
|
return {
|
|
contents: js,
|
|
loader: "text",
|
|
};
|
|
});
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Singleton externals: packages that MUST be the same instance at runtime
|
|
* across all plugins and the Quartz host. Everything else gets bundled.
|
|
*/
|
|
const SINGLETON_EXTERNALS = [
|
|
"preact",
|
|
"preact/hooks",
|
|
"preact/jsx-runtime",
|
|
"preact/compat",
|
|
"@jackyzha0/quartz",
|
|
"@jackyzha0/quartz/*",
|
|
"vfile",
|
|
"vfile/*",
|
|
"unified",
|
|
"google-font-metadata",
|
|
];
|
|
|
|
export default defineConfig({
|
|
entry: {
|
|
index: "src/index.ts",
|
|
types: "src/types.ts",
|
|
emitter: "src/emitter.ts",
|
|
},
|
|
format: ["esm"],
|
|
dts: true,
|
|
tsconfig: "tsconfig.build.json",
|
|
sourcemap: true,
|
|
clean: true,
|
|
treeshake: true,
|
|
target: "es2022",
|
|
splitting: false,
|
|
outDir: "dist",
|
|
platform: "node",
|
|
noExternal: [/.*/],
|
|
external: SINGLETON_EXTERNALS,
|
|
banner: {
|
|
js: 'import { createRequire } from "module"; const require = createRequire(import.meta.url);',
|
|
},
|
|
esbuildOptions(options) {
|
|
options.jsx = "automatic";
|
|
options.jsxImportSource = "preact";
|
|
},
|
|
esbuildPlugins: [inlineScriptPlugin],
|
|
});
|