首页 / Bun 入门教程 / 加载器与资源

Bun 入门教程

加载器与资源

本教程共 34 篇 · 第 17 篇 · 更新于 2026-08-06

Bun打包器Loader资源CSS静态文件

本节目标:

  • 理解 loader(加载器)在打包过程中扮演的角色
  • 掌握内置 loader 清单,以及用导入属性/配置覆盖默认行为
  • 学会处理 CSS、图片、字体等静态资源
  • 学会在代码中直接导入 JSON、TOML、YAML 等数据文件

打包器最核心的能力之一,就是把”非 JavaScript 的东西”变成 JavaScript 能消费的东西。比如你在代码里写了 import "./style.css",打包器需要知道”CSS 该怎么办”;你写了 import logo from "./logo.svg",打包器得决定”这个图片是复制出去、还是内联成字符串”。Bun 用 loader 机制统一管理这类转换规则。

17.1 什么是 loader

loader(加载器)决定了”遇到某种文件类型时,打包器怎么做”。当打包器在依赖分析阶段遇到一个导入,它会根据文件扩展名(或你显式指定的规则)选择一个 loader,由该 loader 把文件内容转换成可打包的形式——可能是内联成字符串、解析成 JS 对象,也可能是复制成独立文件并替换为最终 URL。

Bun 内置了丰富的 loader,覆盖常见场景:

  • 代码类:js / jsx / ts / tsx,直接作为代码参与打包;
  • 数据类:json / jsonc(带注释的 JSON)/ toml / yaml / text,在打包时内联为对应对象或字符串;
  • 资源类:css 走内置 CSS 处理,file 把文件复制到输出目录并返回路径,dataurl 把文件内联成 data: URI,wasm 处理 WebAssembly;
  • 特殊类:html 用于 HTML 入口与资源重写(见第 20 章),sqlite 把 SQLite 数据库嵌入产物(仅 target=bun),napi 对应 .node 原生插件。

默认按扩展名匹配的文件类型是这一串:.js .cjs .mjs .mts .cts .ts .tsx .jsx .css .json .jsonc .toml .yaml .yml .txt .wasm .node .html

Note

对于 Bun 不认识、又没有显式配置 loader 的文件类型,默认会回退到 file loader:把它当作静态资源复制到输出目录,导入值变成最终的资源 URL 字符串。这让”未知文件也不会报错”。

17.2 用导入属性指定 loader

最推荐的做法,是用 ECMAScript 的”导入属性”(import attributes)在 import 语句里就地声明文件类型。语法是在导入路径后加 with { type: "..." }

// 把 TOML 文件作为对象直接导入
import config from "./config.toml" with { type: "toml" };
console.log(config.server.port);

// 把任意文件作为纯文本字符串导入
import readme from "./README.md" with { type: "text" };
console.log(readme.length);

这种方式的好处是:loader 的选择和导入语句写在一起,可读性高,也避免了全局配置”影响所有同名扩展名文件”的副作用。常见的 type 取值包括 tomlyamljsontextfilesqlite 等,与内置 loader 一一对应。

Tip

当你只想在某个特定导入上覆盖默认行为时,优先用 with { type } 而不是全局 loader 配置。范围越小,越不容易”误伤”其他文件。

17.3 用配置/CLI 覆盖 loader

如果你希望”所有 .conf 文件都按 TOML 解析”,或者命令行快速试一下,可以用 loader 选项(JS API)或 --loader 参数全局映射扩展名到 loader:

await Bun.build({
  entrypoints: ["./index.ts"],
  outdir: "./dist",
  loader: {
    // 把 .conf 扩展名映射成 toml loader
    ".conf": "toml",
    // 把 .data 映射成 text loader
    ".data": "text",
  },
});
# CLI 方式:扩展名和 loader 名之间用冒号分隔,可以重复传多次
bun build ./index.ts --outdir ./dist --loader .conf:toml --loader .data:text

注意 CLI 的分隔符是冒号.conf:toml),别写成等号。JS API 里的 loader 则是一个”扩展名 → loader 名”的映射表,键要带点号(如 ".conf")。

映射表适合做项目级的统一约定,with { type } 适合做局部、一次性覆盖。两者可以共存,导入属性优先级更高。

17.4 处理 CSS

CSS 在 Bun 里有”一等公民”待遇。它的 CSS 解析器与打包器是 LightningCSS 的直接移植,打包思路参考了 esbuild,默认就做转译与厂商前缀补全。你在入口里 import "./style.css",打包器会把它收集起来,最终输出成一个 .css 文件(或在 HTML 场景下自动关联)。

// 在 JS/TS 入口中导入 CSS
import "./styles/global.css";

document.body.textContent = "Hello Bun";
/* styles/global.css */
:root {
  --brand: oklch(70% 0.2 250);
}
.box {
  background: var(--brand);
  padding: 1rem;
}

现代 CSS 特性如嵌套(nesting)、color-mix()@import 合并等都被支持;Bun 还会对标目标浏览器做语法降级与前缀补全。关于 CSS Modules(.module.css)、组合(composes)等更深入的话题,属于 CSS 子主题的进阶内容,这里先建立”CSS 可被直接 import”的认识。

Warning

如果你在浏览器 target 下导入 CSS,产物是一个独立的 .css 文件,需要你自己用 <link> 引用,或在 HTML 入口中让它自动关联(见第 20 章)。不要假设 CSS 会被自动塞进 JS。

17.5 处理图片、字体等静态资源(file loader)

图片、字体、音视频这类二进制资源,默认走 file loader:打包时复制到输出目录,导入值变成指向产物的路径字符串。产物名按 --asset-naming 生成,默认模板是 [name]-[hash].[ext],内容哈希天然避开了缓存冲突。

import logo from "./logo.svg";

const img = document.createElement("img");
img.src = logo; // logo 是打包后的 URL,例如 "./logo-a7305bdef.svg"
document.body.appendChild(img);

注意上面的 logo 打包后并不是文件对象,而是一个字符串路径。这就是 file loader 的标准行为:把”文件”抽象成”可引用的地址”。想强调这层意图,可以显式写 with { type: "file" }

字体、PDF、压缩包等也是同理:凡是”应该原样复制到输出目录、代码里只引用其路径”的,基本都交给 file loader 处理。

import resume from "./assets/resume.pdf" with { type: "file" };
console.log("简历下载地址:", resume);

17.6 导入数据文件(json / toml / yaml / text)

数据文件是 loader 的”高光场景”。Bun 在打包期就把结构化数据内联进产物,运行时不依赖外部文件:

// JSON(含 jsonc,支持注释)
import pkg from "./package.json" with { type: "json" };
console.log(pkg.name);

// TOML
import dbConfig from "./db.toml" with { type: "toml" };
console.log(dbConfig.database.url);

// YAML
import specs from "./openapi.yaml" with { type: "yaml" };
console.log(specs.info.title);

// 纯文本
import banner from "./banner.txt" with { type: "text" };
console.log(banner);

json/jsonc 导入为 JS 对象,toml/yaml 同样解析为对象,text 则保留为字符串。这类内联意味着:构建完成后,这些配置文件已经”烧录”进产物,部署时无需随包携带源数据文件(除非你刻意用 file loader 保留为外部引用)。

Tip

对于需要在运行时动态切换的配置(比如不同环境的不同密钥),不要用 type: "json" 内联,而应走环境变量(--env)或 define/运行时读取,避免把敏感或易变数据”固化”进构建产物。

17.7 其他 loader 速览

  • napi.node 原生插件的默认 loader,让 Bun 运行时能加载 C/C++ 编译的 Node 插件。要留意一个差异——在打包器里 .node 文件走的是 file loader,也就是被当成静态资源复制出去,而不是就地链接。
  • wasm:导入 .wasm 时返回 WebAssembly 模块,配合 WebAssembly.instantiate 使用。
  • sqlite:通过 import db from "./app.db" with { type: "sqlite" } 把 SQLite 数据库嵌入产物,仅当 target=bun 时可用,适合做带内嵌数据的工具或可执行文件。
  • dataurl:把文件内容编码成 data: URI 直接内联,适合小图标这类”不值得单独发一次请求”的资源,常配合 --loader .png:dataurl 使用。
  • sh:Bun Shell 脚本只在用 bun 直接执行该 .sh 文件时生效,打包器的依赖分析与运行时的 import 都用不了,别指望能 import "./deploy.sh"

覆盖面已经相当广了。但”自定义处理规则”这类需求——比如把 .md 转成 HTML、给图片加自定义压缩——超出了内置 loader 的能力,得靠第 18 章的插件系统。

17.8 小结

本章我们掌握了 Bun 打包器的资源处理主干:

  • loader 决定”遇到某类文件时打包器怎么做”,未知类型默认回退到 file
  • 局部覆盖用 with { type: "..." } 导入属性,全局约定用 loader 映射或 --loader .ext:name
  • CSS 是一等公民,可直接 import,由 LightningCSS 移植而来的管线转译与补全前缀;
  • 图片、字体等走 file loader,导入值是指向产物的路径字符串;
  • json/jsonc/toml/yaml/text 会在打包期内联为对象或字符串;
  • dataurl/wasm/sqlite/napi 各有分工,sh 只在 Bun 直接执行脚本时生效。
Tip

loader 选择冲突时,导入属性 with { type } 优先级最高,其次是 Bun.buildloader 映射,最后才是按扩展名推断。记住这个顺序,排查”为什么某个文件没按预期处理”会快很多。

有了 loader 打底,下章用插件系统对任意文件做完全自定义的转换。