首页 / WXT 浏览器扩展框架教程 / 静态资源与图标:图片、CSS、WASM

WXT 浏览器扩展框架教程

静态资源与图标:图片、CSS、WASM

本教程共 45 篇 · 第 23 篇 · 更新于 2026-08-13 · 约 3 分钟阅读

WXT静态资源图标faviconWASM内容脚本

本节目标:分清 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.pngicon-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();
}
Warning

favicon 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>'],
      },
    ],
  },
});