---
The way we do this kind of thing at Notion is very simple. We have normal CLI commands that generate code and write it to disk, and we check in those outputs. Then in CI, we run all the generation commands and verify the codegen is up-to-date. Checking in generated code means it's really easy to understand the behavior of codegen and how it changes, and everyone gets excellent typechecking and auto-completion of codegen'd artifacts.
The downside to static codegen is that the "templates" we use for codegen need to be valid Typescript files, or we risk breakage if imports or types change.
Bun macros have some advantages like execution at build time for stuff like Git SHA interpolation, but because these macros can't actually emit code, they feel less powerful that straight-up codegen. I could replace a lot of the Notion CLI commands with Bun macros if:
1. There's a return type for macros that emits code, like:
// src/macros/prism.ts
export function emitPrismImports() {
const importOrder = toposortLangagues(PRISM_LANGUAGES)
const imports = importOrder
.map(lang => `await import(/* webpackChunkName: "prism" */ "${importPath}"`)
.join('\n')
return Bun.code`${imports}`
}
// src/client/syntaxHighlighting.ts
import { emitPrismImports } from '@notionhq/macros/prism' with { type: 'macro' }
async function highlight(text, lang) {
emitPrismImports()
return Prism.highlight(text, lang)
}
2. There's a way to run `bun build` and just do macro evaluation. I need to continue using Typescript, Webpack, Jest, etc for now, so we need eval'd macros on disk so they can be typechecked, tab-completed, and bundled by other tools.The uncompiled versions still wouldn't typecheck nicely though :thinking_face: