diff --git a/.devflow/features/bundler-plugins/KNOWLEDGE.md b/.devflow/features/bundler-plugins/KNOWLEDGE.md new file mode 100644 index 0000000..fe655e1 --- /dev/null +++ b/.devflow/features/bundler-plugins/KNOWLEDGE.md @@ -0,0 +1,187 @@ +--- +feature: bundler-plugins +name: Bundler Plugins (bundler-utils + Vite/Rollup/Webpack/Rspack) +description: "Use when adding a new bundler integration, modifying the emitted-module contract, debugging HMR behavior, working on the CJS compatibility shim, updating the transformer/loader factory, registering a new package in the release pipeline, or investigating why a .mds file emits unexpected output. Keywords: createMdsTransformer, createMdsLoader, bundler-utils, vite-plugin, rollup-plugin, webpack-loader, rspack-loader, addWatchFile, addDependency, handleHotUpdate, emitted module contract, export default string, export default Message[], safeJsonForJs, escapeForJs, metadata, kind, markdown, messages, discriminated union, mds.d.ts, MdsMessage, string | MdsMessage[]." +category: component-patterns +directories: ["packages/bundler-utils/", "packages/vite-plugin/", "packages/rollup-plugin/", "packages/webpack-loader/", "packages/rspack-loader/"] +referencedFiles: + - packages/bundler-utils/src/transform.ts + - packages/bundler-utils/src/types.ts + - packages/bundler-utils/src/loader.ts + - packages/bundler-utils/src/frontmatter.ts + - packages/bundler-utils/src/lazy-init.ts + - packages/bundler-utils/mds.d.ts + - packages/bundler-utils/src/index.ts + - packages/vite-plugin/src/index.ts + - packages/rollup-plugin/src/index.ts + - packages/webpack-loader/src/index.ts + - packages/rspack-loader/src/index.ts +created: 2026-06-26 +updated: 2026-06-26 +--- + +# Bundler Plugins (bundler-utils + Vite/Rollup/Webpack/Rspack) + +## Overview + +`packages/bundler-utils/` is the shared transformation layer consumed by four bundler plugins: `vite-plugin`, `rollup-plugin`, `webpack-loader`, `rspack-loader`. It implements `createMdsTransformer` (used by Vite/Rollup) and `createMdsLoader` (used by Webpack/Rspack). After the intrinsic-output refactor, the emitted JS module branches on the compiled `kind` — a markdown `.mds` emits a string default export, a messages `.mds` emits a `Message[]` default export. The published `mds.d.ts` ambient declaration reflects this widened type. + +## Core Responsibilities + +- `transform.ts`: compile `.mds` files via `MdsApi.compileFile`, emit the JS module source (`export default`), serialize metadata +- `loader.ts`: webpack/rspack integration via `createMdsLoader` +- `frontmatter.ts`: `shouldTransform(id)` — decides if a module ID refers to an `.mds` file +- `lazy-init.ts`: `LazyInit` — ensures `mds.init()` is awaited exactly once per transformer instance +- Does NOT: implement compilation logic, manage caching, handle HMR (delegated to plugin wrappers) + +## Standard Structure + +### Emitted module contract (post-refactor) + +The emitted JS module branches on `result.kind`: + +```typescript +// transform.ts — inside transform() +let defaultExport: string; +if (result.kind === 'markdown') { + // Escape the string for embedding in a double-quoted JS literal + defaultExport = `export default "${escapeForJs(result.output)}";\n`; +} else { + // kind === 'messages' — serialize the messages array as safe inline JSON + defaultExport = `export default ${safeJsonForJs(result.messages)};\n`; +} + +const code = + defaultExport + + `export const metadata = ${safeJsonForJs({ warnings: result.warnings, dependencies: result.dependencies })};\n`; +``` + +So for a markdown `.mds`: `export default "..."` (string) +For a messages `.mds`: `export default [{role:"...", content:"..."}]` (array literal) + +Both emit `export const metadata = { warnings: [...], dependencies: [...] };` + +### safeJsonForJs vs escapeForJs + +These two serializers have different contracts and must not be swapped: + +- `escapeForJs(str: string): string` — escapes special chars for embedding inside a double-quoted JS string literal (`"..."`) +- `safeJsonForJs(value: unknown): string` — `JSON.stringify` + escapes `<`, U+2028, U+2029 for safe inline `