
上一回我們講到 Macro 的基本操作,今天我們要講 Macro 比較進階的部分
可能有人在上一篇比較多理論和基本觀念的部分,對於實戰派的朋友,可能雲裡霧裡的
不過今天,我打算補齊上一篇留下來的伏筆,一些困難的部分範例,可以用 Macro 處理可以比較優雅的部分
今天會提供幾個實例去展示如何實現和解決相關問題的問題
其實這個範例,是官方提供的,我個人認為這相當實用,
因此我打算推薦給大家用
比如說有時候需要版本好或是展現現在的版本在哪個位置方便查察
可以當作版本 ID 作為使用,以方便確認版本在哪個位置
這對於 Debug 或是版本追蹤非常有用
我們建立一個 getGitCommitHash.ts
import { $ } from 'bun'
// 有看前面文章的知道可以這樣寫
export const getGitCommitHash = async (): Promise<string> => {
return await $`git rev-parse HEAD`.text();
}
// === 這個是官方提供的 ===
// export function getGitCommitHash() {
// const { stdout } = Bun.spawnSync({
// cmd: ["git", "rev-parse", "HEAD"],
// stdout: 'pipe',
// });
// return stdout.toString();
// }
這裡可以用 index.ts
index.ts
import { getGitCommitHash } from './getGitCommitHash' with { type: 'macro' }
console.log(`The current Git commit hash is ${getGitCommitHash()}`);
這樣我們就可以在打包時立即拿到當下的 git hash 其實相當簡單,我們看看結果

這個也是個相當實用的做法,不過也因為實用,這樣的運用有機會被濫用,
也就是說,可以在 build 的時候送出 HTTP 請求,這樣做就會有很多想像空間
比如 :
...etc
很多想像空間可以再這期間做這些事情,那我們就開始做一個稍微的實作去達成這件事
我們來執行最後一個我提及的範例 「打包時解析結果把回應並內嵌進去到 jsx/tsx」
我們會用到 bun 提供的 HTMLRewriter
補充介紹 : 目前它是 bun 內部可以提供的 api 它是基於 cloudflare 的 lol-html 實作的,
可以取代特定 tag 內文或是文字
詳細文件可以參考
我們建立一個 meta.ts 用 macro 來進行內嵌
interface MetaResult {
title: string
[T: string]: string
}
export const extractMetaTag = async (url: string): Promise<MetaResult> => {
const meta: MetaResult = { title: '' };
const response = await fetch(url);
// 這裡我們針對 拿到的 url 做 rewrite
new HTMLRewriter()
.on('title', {
text(element) {
// 這裡我們加入一些 text
meta.title += element.text;
}
})
.on('meta', {
element(element) {
const name =
element.getAttribute('name') ||
element.getAttribute('porperty') ||
element.getAttribute('itemprop');
if (name) {
const content = element.getAttribute('content');
if (content !== null) {
meta[name] = content;
}
}
}
})
.transform(response);
return meta;
}
建立一個 index.tsx
import { extractMetaTag } from './meta' with { type: 'macro' }
export const head = async () => {
const headTag = await extractMetaTag('<這裡我們用 live-server 先起來,假設有自己的 template server 可以用自己的 url: 通常是 http://127.0.0.1:8080/>')
return (
<head>
<title>{headTag.title}</title>
<meta name="viewport" content={headTag.viewport} />
</head>
)
}
我們要用 live-server 把 要拿取的網站的 metaTag 還有 title 內嵌,到我們的網站
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>這是一個測試用的 title</title>
</head>
<body>
這是一個測試的模板
</body>
</html>
跑起來
bunx live-server index.html
我們打包 index.tsx 看看
bun build ./index.tsx --outdir out
結果 :

那我們看看打包完內部 ./out/index.js 內部長得如何

這篇我們從一個簡單到有點無聊的 Git hash 範例出發,一路走到「打包時發 HTTP 請求、抓資料、內嵌進 JSX」這種聽起來有點瘋狂的操作。
如果你跟著做到這裡,應該已經感覺到 Macro 不只是個「編譯時小工具」,
而是一個能重新定義 Build Time 與 Runtime 界線的機制。
它可以讓你的 Server-Side Rendering 更聰明、讓 Build 產物攜帶更多上下文,
但同時也打開了一扇門——一扇通往「build 時期副作用」的門。
這扇門後面藏著什麼?效能陷阱、快取策略、還是更多意想不到的應用場景?
下一篇,我們往應用走。