import { nanoid } from "nanoid"; import { build } from "esbuild"; import { mkdir, readFile, rm, writeFile } from "fs/promises"; import { cwd } from "process"; import { basename, dirname, join } from "path"; import h from "vhtml"; globalThis.vhtml = h; export default class JsTransformer { /** * @param {string} inputPath * @param {string} outputPath */ static async build(inputPath, outputPath) { outputPath = join( dirname(outputPath), basename(outputPath, ".s.jsx") + ".html" ); const outfile = join(cwd(), `${nanoid()}.mjs`); await mkdir(dirname(outfile), { recursive: true }); try { await build({ entryPoints: [join(cwd(), inputPath)], outfile, format: "esm", loader: { ".json": "json", }, bundle: true, platform: "node", plugins: [ { name: "svg-jsx", setup(build) { build.onLoad({ filter: /\.svg$/ }, async (args) => { const f = await readFile(args.path, "utf-8"); const js = ` export default (props) => { let s = \`${f}\`; if (props.class) s = s.replace(" ); }; `; return { contents: js, loader: "jsx" }; }); }, }, { name: "relative-import-path", setup(build) { build.onResolve({ filter: /./ }, (args) => { if (args.path.endsWith(".json") || args.path.endsWith(".svg")) return { path: join(args.resolveDir, args.path) }; else if (args.path.startsWith(".")) return { path: join(args.resolveDir, args.path), external: true, }; else return { path: args.path, external: !!args.importer }; }); }, }, ], jsxFactory: "h", banner: { js: `const h = globalThis.vhtml;` }, }); const file = await import(outfile); const html = "" + (await file.render()); await writeFile(outputPath, html); } finally { } await rm(outfile); } }