静态资源与图标:图片、CSS、WASM
本教程共 45 篇 · 第 23 篇 · 更新于 2026-08-13 · 约 3 分钟阅读
本节目标:分清 assets 与 public 两个目录,学会在各类入口引用资源,掌握内容脚本资源与 WASM 的特殊处理,以及图标和 favicon 的用法。
两个资源目录,两种命运
assets/ 和 public/ 都能放资源,但处理方式完全不同:
assets/(在 srcDir 下):经过打包器处理。导入时会做哈希、压缩等加工,适合会被代码引用的资源。public/(在项目根目录):原样复制到产物目录,不做任何处理,适合 favicon、扩展图标这类按文件名访问的资源。
assets 的引用方式:
import imageUrl from '~/assets/image.png';
const img = document.createElement('img');
img.src = imageUrl;
public 的引用方式:
import imageUrl from '/image.png'; // 注意是根路径
const img = document.createElement('img');
img.src = imageUrl;
HTML 和 CSS 里类似:assets 用相对路径(如 ../assets/image.png),public 用根路径(如 /image.png)。
打包器处理 assets 时会加上内容哈希,内容变了文件名也跟着变,缓存问题不用操心;public 里的文件名保持原样,适合路径要写死的场景。
内容脚本里的资源是个特例
内容脚本运行在网页里,页面的域名是目标网站的,不是扩展的。这带来两个问题:
public/里的资源,默认在内容脚本中不可访问。要访问,必须把资源加进 manifest 的web_accessible_resources(如 §25 所述)。- 导入返回的是相对路径,直接用作
img.src会去目标网站加载,加载不到。要用browser.runtime.getURL转成完整 URL:
import iconUrl from '/icon/128.png';
export default defineContentScript({
matches: ['*://*.google.com/*'],
main() {
console.log(iconUrl); // "/icon/128.png"
console.log(browser.runtime.getURL(iconUrl)); // "chrome-extension://<id>/icon/128.png"
},
});
WASM:三步接进扩展
WASM 文件需要先「落盘」再被加载。扩展里分三步。
第一步,把 .wasm 文件复制到产物目录。最干净的方式是写一个 WXT 模块,挂在 build:publicAssets 钩子上:
// modules/oxc-parser-wasm.ts
import { resolve } from 'node:path';
export default defineWxtModule((wxt) => {
wxt.hook('build:publicAssets', (_, assets) => {
assets.push({
absoluteSrc: resolve(
'node_modules/@oxc-parser/wasm/web/oxc_parser_wasm_bg.wasm',
),
relativeDest: 'oxc_parser_wasm_bg.wasm',
});
});
});
跑 wxt build,文件就会出现在 .output/chrome-mv3 里。
第二步,如果要在内容脚本里通过网络加载它,把它加进 web_accessible_resources:
export default defineConfig({
manifest: {
web_accessible_resources: [
{
matches: ['*://*.github.com/*'],
resources: ['/oxc_parser_wasm_bg.wasm'],
},
],
},
});
第三步,用 browser.runtime.getURL 拿到完整 URL,传给 wasm 包的初始化函数:
import initWasm from '@oxc-parser/wasm';
export default defineContentScript({
matches: ['*://*.github.com/*'],
async main() {
await initWasm({
module_or_path: browser.runtime.getURL('/oxc_parser_wasm_bg.wasm'),
});
// 之后就能用 parseSync 等 API 了
},
});
拿不准放 `public/` 还是 `assets/` 时,问一句:这个文件需要被构建工具处理吗?不需要就放 `public/`。
## 小结
- `public/` 原样复制、`assets/` 走构建管线,两种资源「命运」不同。
- 内容脚本里引用 `public/` 资源要配 `web_accessible_resources` 并用 `getURL`。
- WASM 三步:`build:publicAssets` 钩子放文件 + WAR 声明 + 运行时加载。
Note扩展里加载 WASM,永远显式传产物目录里的完整 URL。不同包初始化方式大同小异,核心都是「文件在产物里 + 把完整 URL 传给初始化函数」。
图标:五个常用尺寸
浏览器会在工具栏、右键菜单、商店等地方按需取不同尺寸的图标。社区惯例是准备 5 个尺寸:16、32、48、96、128。wxt_books 的 simple_demo 就把它们放在 public/icon/ 下:
public/icon/
├─ 16.png
├─ 32.png
├─ 48.png
├─ 96.png
└─ 128.png
WXT 会自动发现 public/ 根目录下按 icon-{size}.png 命名的文件,写进 manifest 的 icons 字段;文件在子目录或命名不同时,在 manifest 里手动指定即可(如 §25 所述)。嫌麻烦,直接用 @wxt-dev/auto-icons 从一个源图生成全部尺寸,见 §32。
Firefox 还支持明暗主题图标:把 icon-light-16.png、icon-dark-16.png 这类配对文件放在同一目录,构建 Firefox 版本时,WXT 会自动生成 theme_icons 字段,让图标跟随浏览器主题切换。
favicon:网站小图标的获取
Chromium 浏览器缓存了访问过的网站 favicon,扩展可以通过 _favicon/ URL 读取。先声明 favicon 权限:
export default defineConfig({
manifest: {
permissions: ['favicon'],
},
});
然后拼 URL:
function getFaviconUrl(pageUrl: string, size = 16) {
const url = new URL(browser.runtime.getURL('/_favicon/'));
url.searchParams.set('pageUrl', pageUrl);
url.searchParams.set('size', String(size));
return url.toString();
}
Warningfavicon API 只存在于 Chromium。Firefox 没有对应能力,
/_favicon/URL 不会生效。跨浏览器扩展要按浏览器分支声明权限,代码里用import.meta.env.CHROME之类判断。
内容脚本里想用 favicon 当 <img src>,WXT 不会自动加 _favicon/* 的 web_accessible_resources 条目,需要自己加:
export default defineConfig({
manifest: {
permissions: ['favicon'],
web_accessible_resources: [
{
resources: ['_favicon/*'],
matches: ['<all_urls>'],
},
],
},
});