/** * Build script for the markdown-review MCP server. * * Produces two self-contained artifacts in dist/ with ZERO runtime node_modules: * - dist/index.js Node MCP server, all deps inlined (run: node dist/index.js --stdio) * - dist/mcp-app.html Single-file webview app (HTML + inlined JS/CSS) * * Build-time deps live in node_modules; runtime needs only `node`. Commit dist/ * so a fresh install runs without `npm install`. */ import { build, context } from "esbuild"; import { readFile, writeFile, mkdir } from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; const root = path.dirname(fileURLToPath(import.meta.url)); const dist = path.join(root, "dist"); const watch = process.argv.includes("--watch"); const serverOpts = { entryPoints: [path.join(root, "src/main.ts")], outfile: path.join(dist, "index.js"), bundle: true, platform: "node", format: "esm", target: "node20", // ESM output that bundles CJS deps needs createRequire shimmed in. banner: { js: [ "#!/usr/bin/env node", "import { createRequire as __cr } from 'node:module';", "const require = __cr(import.meta.url);", ].join("\n"), }, logLevel: "info", }; /** Bundle the browser app to a string of JS, then inline it into the HTML shell. */ async function buildApp() { const result = await build({ entryPoints: [path.join(root, "src/app/mcp-app.ts")], bundle: true, platform: "browser", format: "iife", target: "es2022", minify: !watch, sourcemap: watch ? "inline" : false, write: false, logLevel: "info", }); const js = result.outputFiles[0].text; // Escape any literal "" inside the bundle, or the HTML parser closes // the inline `); await writeFile(path.join(dist, "mcp-app.html"), html, "utf-8"); console.log("[build] dist/mcp-app.html"); } async function run() { await mkdir(dist, { recursive: true }); if (watch) { const ctx = await context(serverOpts); await ctx.watch(); await buildApp(); console.log("[build] watching server; rebuild app manually on change"); } else { await build(serverOpts); await buildApp(); console.log("[build] done"); } } run().catch((e) => { console.error(e); process.exit(1); });