Macros are a mechanism for running JavaScript functions at bundle-time. The value returned from these functions or variables are directly inlined into your bundle.
# npm
npm i -D unplugin-macros
# jsr
npx jsr add -D @unplugin/macrosVite
// vite.config.ts
import Macros from 'unplugin-macros/vite'
export default defineConfig({
plugins: [Macros()],
})Rollup
// rollup.config.js
import Macros from 'unplugin-macros/rollup'
export default {
plugins: [Macros()],
}esbuild
Requires esbuild >= 0.15
// esbuild.config.js
import { build } from 'esbuild'
build({
plugins: [require('unplugin-macros/esbuild')()],
})Webpack
// webpack.config.js
module.exports = {
/* ... */
plugins: [require('unplugin-macros/webpack')()],
}// main.js
import { buildTime, getRandom } from './macros' with { type: 'macro' }
getRandom() // Will be replaced with a random number at build time
buildTime // Will be replaced with the timestamp at the build time// macros.js
export function getRandom() {
return Math.random()
}
export const buildTime = Date.now()You can pass function values as arguments to macros. Functions must be isolated (no references to outside identifiers):
// main.js
import { transform } from './macros' with { type: 'macro' }
transform(() => 42)
transform(async () => await Promise.resolve(42))See more in Bun Macros.
Every macro is invoked with a MacroContext as its this. The most useful fields are:
| Field | Description |
|---|---|
id |
Absolute path of the file being transformed. |
source |
Full source code of the file. |
ast.call |
CallExpression AST node of this macro invocation (await / tagged template are unwrapped). |
ast.program |
Program AST of the whole file. |
emitFile |
Emit additional bundle assets. |
unpluginContext |
The underlying unplugin build context — experimental, may change. |
ast.call carries the standard Babel location info (loc, start, end), which is enough to build callsite-aware macros without paying for a runtime stack walk:
// macros.ts
import path from 'node:path'
import type { MacroContext } from 'unplugin-macros'
export function $callsite(this: MacroContext): string {
const { line, column } = this.ast.call.loc!.start
return `${path.basename(this.id)}:${line}:${column}`
}// main.ts
import { $callsite } from './macros.ts' with { type: 'macro' }
console.log($callsite()) // → 'main.ts:3:12'Import Attributes syntax is supported in TypeScript 5.3 and above.
Import Attributes syntax is supported in ESLint v9.14.0.
Refer to docs.
Thanks to Bun Macros.
MIT License © 2023-PRESENT Kevin Deng