普通视图

发现新文章,点击刷新页面。
昨天以前首页

WXT浏览器插件开发中文教程(18)----存储详解

2025年3月30日 12:22

前言

大家好,我是倔强青铜三。是一名热情的软件工程师,我热衷于分享和传播IT技术,致力于通过我的知识和技能推动技术交流与创新,欢迎关注我,微信公众号:倔强青铜三。欢迎点赞、收藏、关注,一键三连!!!

存储

Chrome 文档Firefox 文档

您可以使用原生 API(请参阅上面的文档),使用 WXT 的内置存储 API,或从 NPM 安装一个包。

替代方案

  1. wxt/utils/storage(推荐):WXT 自带了一个围绕原生存储 API 的封装,简化了常见的使用场景。

  2. DIY:如果您正在迁移到 WXT 并且已经有了一个存储封装,可以继续使用它。将来,如果您想删除该代码,可以使用这些替代方案之一,但在迁移过程中没有理由替换正在工作的代码。

  3. 其他任何 NPM 包:有很多围绕存储 API 的封装,您可以找到喜欢的一个。这里是一些流行的:

    • webext-storage - 一个更可用的类型化存储 API,适用于 Web 扩展
    • @webext-core/storage - 一个类型安全的、类似 localStorage 的封装,围绕 Web 扩展存储 API

WXT 存储

变更日志

扩展存储 API 的简化封装。

安装

使用 WXT

此模块已内置在 WXT 中,因此您不需要安装任何东西。

import { storage } from '#imports';

如果您使用自动导入,storage 会自动为您导入,因此您甚至不需要导入它!

不使用 WXT

安装 NPM 包:

npm i @wxt-dev/storage
pnpm add @wxt-dev/storage
yarn add @wxt-dev/storage
bun add @wxt-dev/storage
import { storage } from '@wxt-dev/storage';

存储权限

要使用 @wxt-dev/storage API,必须在清单中添加 "storage" 权限:

wxt.config.ts

export default defineConfig({
  manifest: {
    permissions: ['storage'],
  },
});

基本用法

所有存储键必须以其存储区域为前缀。

// ❌ 这将抛出错误
await storage.getItem('installDate');
// ✅ 这是正确的
await storage.getItem('local:installDate');

您可以使用 local:session:sync:managed:

如果您使用 TypeScript,可以在大多数方法中添加类型参数以指定键值的预期类型:

await storage.getItem<number>('local:installDate');
await storage.watch<number>(
  'local:installDate',
  (newInstallDate, oldInstallDate) => {
    // ...
  },
);
await storage.getMeta<{ v: number }>('local:installDate');

有关可用方法的完整列表,请参见 API 参考

监听器

要监听存储更改,请使用 storage.watch 函数。它允许您为单个键设置监听器:

const unwatch = storage.watch<number>('local:counter', (newCount, oldCount) => {
  console.log('计数已更改:', { newCount, oldCount });
});

要移除监听器,请调用返回的 unwatch 函数:

const unwatch = storage.watch(...);
// 一段时间后...
unwatch();

元数据

@wxt-dev/storage 还支持为键设置元数据,存储在 key + "$" 处。元数据是与键关联的一组属性。它可能是一个版本号、最后修改日期等。

除了版本控制之外,您还需要负责管理字段的元数据:

await Promise.all([
  storage.setItem('local:preference', true),
  storage.setMeta('local:preference', { lastModified: Date.now() }),
]);

当从多次调用中设置不同属性的元数据时,这些属性会被合并而不是被覆盖:

await storage.setMeta('local:preference', { lastModified: Date.now() });
await storage.setMeta('local:preference', { v: 2 });
await storage.getMeta('local:preference'); // { v: 2, lastModified: 1703690746007 }

您可以移除与键关联的所有元数据,或仅移除特定属性:

// 移除所有属性
await storage.removeMeta('local:preference');
// 仅移除 "lastModified" 属性
await storage.removeMeta('local:preference', 'lastModified');
// 移除多个属性
await storage.removeMeta('local:preference', ['lastModified', 'v']);

定义存储项

一遍又一遍地为同一个键编写键和类型参数可能会很烦人。作为替代方案,您可以使用 storage.defineItem 创建一个“存储项”。

存储项包含与 storage 变量相同的 API,但您可以在一个地方配置其类型、默认值等:

// utils/storage.ts
const showChangelogOnUpdate = storage.defineItem<boolean>(
  'local:showChangelogOnUpdate',
  {
    fallback: true,
  },
);

现在,您可以使用创建的存储项上的辅助函数,而不是使用 storage 变量:

await showChangelogOnUpdate.getValue();
await showChangelogOnUpdate.setValue(false);
await showChangelogOnUpdate.removeValue();
const unwatch = showChangelogOnUpdate.watch((newValue) => {
  // ...
});

有关可用属性和方法的完整列表,请参见 API 参考

版本控制

如果期望存储项随着时间增长或变化,您可以为其添加版本控制。在定义项目的第一个版本时,从版本 1 开始。

例如,考虑一个存储项,它存储被扩展忽略的网站列表。

v1

type IgnoredWebsiteV1 = string;
export const ignoredWebsites = storage.defineItem<IgnoredWebsiteV1[]>(
  'local:ignoredWebsites',
  {
    fallback: [],
    version: 1,
  },
);

v2

import { nanoid } from 'nanoid'; 
type IgnoredWebsiteV1 = string;
interface IgnoredWebsiteV2 { 
  id: string; 
  website: string; 
} 
export const ignoredWebsites = storage.defineItem<IgnoredWebsiteV1[]>( 
export const ignoredWebsites = storage.defineItem<IgnoredWebsiteV2[]>( 
  'local:ignoredWebsites',
  {
    fallback: [],
    version: 1, 
    version: 2, 
    migrations: { 
      // 从 v1 迁移到 v2 时运行
      2: (websites: IgnoredWebsiteV1[]): IgnoredWebsiteV2[] => { 
        return websites.map((website) => ({ id: nanoid(), website })); 
      }, 
    }, 
  },
);

v3

import { nanoid } from 'nanoid';
type IgnoredWebsiteV1 = string;
interface IgnoredWebsiteV2 {
  id: string;
  website: string;
}
interface IgnoredWebsiteV3 { 
  id: string; 
  website: string; 
  enabled: boolean; 
} 
export const ignoredWebsites = storage.defineItem<IgnoredWebsiteV2[]>( 
export const ignoredWebsites = storage.defineItem<IgnoredWebsiteV3[]>( 
  'local:ignoredWebsites',
  {
    fallback: [],
    version: 2, 
    version: 3, 
    migrations: {
      // 从 v1 迁移到 v2 时运行
      2: (websites: IgnoredWebsiteV1[]): IgnoredWebsiteV2[] => {
        return websites.map((website) => ({ id: nanoid(), website }));
      },
      // 从 v2 迁移到 v3 时运行
      3: (websites: IgnoredWebsiteV2[]): IgnoredWebsiteV3[] => { 
        return websites.map((website) => ({ ...website, enabled: true })); 
      }, 
    },
  },
);

INFO

内部使用一个名为 v 的元数据属性来跟踪值的当前版本。

在这种情况下,我们认为忽略的网站列表将来可能会发生变化,并能够从一开始就设置一个版本化的存储项。

实际上,直到需要更改其模式时,您才会知道某个项需要版本控制。幸运的是,向未版本化的存储项添加版本控制非常简单。

当找不到先前版本时,WXT 假定版本为 1。这意味着您只需设置 version: 2 并为 2 添加迁移,它就会正常工作!

让我们再看一下之前的忽略网站示例,但这次从一个未版本化的项开始:

未版本化

export const ignoredWebsites = storage.defineItem<string[]>(
  'local:ignoredWebsites',
  {
    fallback: [],
  },
);

v2

import { nanoid } from 'nanoid'; 
// 回溯性地为第一个版本添加类型
type IgnoredWebsiteV1 = string; 
interface IgnoredWebsiteV2 { 
  id: string; 
  website: string; 
} 
export const ignoredWebsites = storage.defineItem<string[]>( 
export const ignoredWebsites = storage.defineItem<IgnoredWebsiteV2[]>( 
  'local:ignoredWebsites',
  {
    fallback: [],
    version: 2, 
    migrations: { 
      // 从 v1 迁移到 v2 时运行
      2: (websites: IgnoredWebsiteV1[]): IgnoredWebsiteV2[] => { 
        return websites.map((website) => ({ id: nanoid(), website })); 
      }, 
    }, 
  },
);

运行迁移

一旦调用 storage.defineItem,WXT 就会检查是否需要运行迁移,如果需要,则运行它们。对存储项的值或元数据进行获取或更新的调用(如 getValuesetValueremoveValuegetMeta 等)会自动等待迁移过程完成后再实际读取或写入值。

默认值

使用 storage.defineItem,有多种方式定义默认值:

  1. fallback - 如果值缺失,则从 getValue 返回此值而不是 null

    此选项非常适合为设置提供默认值:

    const theme = storage.defineItem('local:theme', {
      fallback: 'dark',
    });
    const allowEditing = storage.defineItem('local:allow-editing', {
      fallback: true,
    });
    
  2. init - 如果尚未保存,则初始化并保存一个值到存储中。

    这对于需要初始化或一次设置的值非常有用:

    const userId = storage.defineItem('local:user-id', {
      init: () => globalThis.crypto.randomUUID(),
    });
    const installDate = storage.defineItem('local:install-date', {
      init: () => new Date().getTime(),
    });
    

    值会立即在存储中初始化。

批量操作

当一次性获取或设置多个值时,您可以执行批量操作以通过减少单独的存储调用来提高性能。storage API 提供了几个用于执行批量操作的方法:

  • getItems - 一次性获取多个值。
  • getMetas - 一次性获取多个项的元数据。
  • setItems - 一次性设置多个值。
  • setMetas - 一次性设置多个项的元数据。
  • removeItems - 一次性移除多个值(可选移除元数据)。

所有这些 API 都支持字符串键和定义的存储项:

const userId = storage.defineItem('local:userId');
await storage.setItems([
  { key: 'local:installDate', value: Date.now() },
  { item: userId, value: generateUserId() },
]);

有关如何使用所有批量 API 的类型和示例,请参见 API 参考

最后感谢阅读!欢迎关注我,微信公众号倔强青铜三。欢迎点赞收藏关注,一键三连!!!

WXT浏览器插件开发中文教程(12)----WXT配置详解之Hooks

2025年3月30日 08:22

前言

大家好,我是倔强青铜三。是一名热情的软件工程师,我热衷于分享和传播IT技术,致力于通过我的知识和技能推动技术交流与创新,欢迎关注我,微信公众号:倔强青铜三。欢迎点赞、收藏、关注,一键三连!!!

Hooks

WXT 包含一个系统,允许你在构建过程中插入Hooks并进行更改。

添加Hooks

通过 wxt.config.ts 添加Hooks是最简单的方式。以下是一个示例Hooks,它在将 manifest.json 文件写入输出目录之前对其进行修改:

wxt.config.ts

export default defineConfig({
  hooks: {
    'build:manifestGenerated': (wxt, manifest) => {
      if (wxt.config.mode === 'development') {
        manifest.title += ' (DEV)';
      }
    },
  },
});

大多数Hooks将 wxt 对象作为第一个参数提供。它包含已解析的配置和其他有关当前构建的信息。其他参数可以通过引用修改,从而更改构建系统的不同部分。

将此类一次性Hooks放入配置文件中非常简单,但如果你发现自己编写了许多Hooks,则应将它们提取到 WXT Modules 中。

执行顺序

由于Hooks可以在多个地方定义,包括 WXT Modules,因此它们的执行顺序可能很重要。Hooks的执行顺序如下:

  1. 按照在 modules 配置 中列出的顺序执行 NPM 模块
  2. 加载位于 /modules 文件夹 中的用户模块,按字母顺序加载
  3. 执行 wxt.config.ts 中列出的Hooks

要查看项目的执行顺序,请运行带有 wxt prepare --debug 标志的命令,并搜索“Hook execution order”:

⚙ Hook execution order:
⚙   1. wxt:built-in:unimport
⚙   2. src/modules/auto-icons.ts
⚙   3. src/modules/example.ts
⚙   4. src/modules/i18n.ts
⚙   5. wxt.config.ts > hooks

更改执行顺序很简单:

  • 在用户模块的文件名前加上数字(数字越小越先加载):

    📁 modules/
       📄 0.my-module.ts
       📄 1.another-module.ts
    
  • 如果你需要在用户模块之后运行一个 NPM 模块,只需将其作为用户模块,并在文件名前加上数字!

    // modules/2.i18n.ts
    export { default } from '@wxt-dev/i18n/module';
    

最后感谢阅读!欢迎关注我,微信公众号倔强青铜三。欢迎点赞收藏关注,一键三连!!!

WXT浏览器插件开发中文教程(11)----WXT配置详解之TypeScript 配置

2025年3月30日 08:15

前言

大家好,我是倔强青铜三。是一名热情的软件工程师,我热衷于分享和传播IT技术,致力于通过我的知识和技能推动技术交流与创新,欢迎关注我,微信公众号:倔强青铜三。欢迎点赞、收藏、关注,一键三连!!!

TypeScript 配置

当你运行wxt prepare时,WXT会在你的项目根目录下生成一个基础的TSConfig文件,位于<rootDir>/.wxt/tsconfig.json

至少,你需要在根目录下创建一个TSConfig,内容如下:

// <rootDir>/tsconfig.json
{
  "extends": ".wxt/tsconfig.json",
}

如果你处于一个单体仓库中,可能不希望扩展配置。如果不扩展配置,你需要将.wxt/wxt.d.ts添加到TypeScript项目中:

/// <reference path="./.wxt/wxt.d.ts" />

编译器选项

要指定自定义编译器选项,请在<rootDir>/tsconfig.json中添加它们:

// <rootDir>/tsconfig.json
{
  "extends": ".wxt/tsconfig.json",
  "compilerOptions": {
    "jsx": "preserve",
  },
}

TSConfig 路径

WXT提供了一组默认的路径别名。

别名 对应路径 示例
~~ <rootDir>/* import "~~/scripts"
@@ <rootDir>/* import "@@/scripts"
~ <srcDir>/* import { toLowerCase } from "~/utils/strings"
@ <srcDir>/* import { toLowerCase } from "@/utils/strings"

要添加自定义别名,请不要直接在tsconfig.json中添加!相反,使用wxt.config.ts中的alias选项

这将在你下次运行wxt prepare时,将自定义别名添加到<rootDir>/.wxt/tsconfig.json中。同时,它也会将别名添加到打包器中,以便解析导入。

import { resolve } from 'node:path';
export default defineConfig({
  alias: {
    // 目录:
    testing: resolve('utils/testing'),
    // 文件:
    strings: resolve('utils/strings.ts'),
  },
});
import { fakeTab } from 'testing/fake-objects';
import { toLowerCase } from 'strings';

最后感谢阅读!欢迎关注我,微信公众号倔强青铜三。欢迎点赞收藏关注,一键三连!!!

WXT浏览器插件开发中文教程(10)----WXT配置详解之构建模式

2025年3月29日 15:15

前言

大家好,我是倔强青铜三。是一名热情的软件工程师,我热衷于分享和传播IT技术,致力于通过我的知识和技能推动技术交流与创新,欢迎关注我,微信公众号:倔强青铜三。欢迎点赞、收藏、关注,一键三连!!!

构建模式

因为 WXT 是基于 Vite 构建的,所以它以相同的方式支持 模式

在运行任何开发或构建命令时,可以通过传递 --mode 标志来指定模式:

wxt --mode production
wxt build --mode development
wxt zip --mode testing

默认情况下,对于开发命令,--modedevelopment,而对于所有其他命令(构建、打包等),--modeproduction

在运行时获取模式

您可以通过 import.meta.env.MODE 在扩展中访问当前模式:

switch (import.meta.env.MODE) {
  case 'development': // ...
  case 'production': // ...
  // 使用 --mode 指定的自定义模式
  case 'testing': // ...
  case 'staging': // ...
  // ...
}

最后感谢阅读!欢迎关注我,微信公众号倔强青铜三。欢迎点赞收藏关注,一键三连!!!

WXT浏览器插件开发中文教程(7)----WXT配置详解之运行时配置

2025年3月29日 15:02

前言

大家好,我是倔强青铜三。是一名热情的软件工程师,我热衷于分享和传播IT技术,致力于通过我的知识和技能推动技术交流与创新,欢迎关注我,微信公众号:倔强青铜三。欢迎点赞、收藏、关注,一键三连!!!

运行时配置

此 API 仍在开发中,更多功能即将到来!

在单一位置 <srcDir>/app.config.ts 定义运行时配置:

import { defineAppConfig } from '#imports';
// 为配置定义类型
declare module 'wxt/utils/define-app-config' {
  export interface WxtAppConfig {
    theme?: 'light' | 'dark';
  }
}
export default defineAppConfig({
  theme: 'dark',
});

警告

此文件会提交到代码仓库中,因此不要在此处放置任何机密信息。相反,请使用环境变量

要访问运行时配置,WXT 提供了 useAppConfig 函数:

import { useAppConfig } from '#imports';
console.log(useAppConfig()); // { theme: "dark" }

在应用配置中使用环境变量

你可以在 app.config.ts 文件中使用环境变量。

declare module 'wxt/utils/define-app-config' {
  export interface WxtAppConfig {
    apiKey?: string;
    skipWelcome: boolean;
  }
}
export default defineAppConfig({
  apiKey: import.meta.env.WXT_API_KEY,
  skipWelcome: import.meta.env.WXT_SKIP_WELCOME === 'true',
});

这有以下几大优势:

  • 在一个文件中定义所有预期的环境变量
  • 将字符串转换为其他类型,例如布尔值或数组
  • 如果未提供环境变量,则提供默认值

最后感谢阅读!欢迎关注我,微信公众号倔强青铜三。欢迎点赞收藏关注,一键三连!!!

WXT浏览器插件开发中文教程(6)----WXT配置详解之环境变量

2025年3月29日 14:56

前言

大家好,我是倔强青铜三。是一名热情的软件工程师,我热衷于分享和传播IT技术,致力于通过我的知识和技能推动技术交流与创新,欢迎关注我,微信公众号:倔强青铜三。欢迎点赞、收藏、关注,一键三连!!!

环境变量

Dotenv 文件

WXT 以与 Vite 相同的方式支持 dotenv 文件。可以创建以下文件:

.env
.env.local
.env.[mode]
.env.[mode].local
.env.[browser]
.env.[browser].local
.env.[mode].[browser]
.env.[mode].[browser].local

在这些文件中列出的任何环境变量都将在运行时可用:

# .env
WXT_API_KEY=...
await fetch(`/some-api?apiKey=${import.meta.env.WXT_API_KEY}`);

请记住,按照 Vite 的约定,环境变量必须以 WXT_VITE_ 开头,否则它们在运行时将不可用。

内置环境变量

WXT 根据当前命令提供了一些自定义环境变量:

用法 类型 描述
import.meta.env.MANIFEST_VERSION 2 │ 3 目标清单版本
import.meta.env.BROWSER string 目标浏览器
import.meta.env.CHROME boolean 等同于 import.meta.env.BROWSER === "chrome"
import.meta.env.FIREFOX boolean 等同于 import.meta.env.BROWSER === "firefox"
import.meta.env.SAFARI boolean 等同于 import.meta.env.BROWSER === "safari"
import.meta.env.EDGE boolean 等同于 import.meta.env.BROWSER === "edge"
import.meta.env.OPERA boolean 等同于 import.meta.env.BROWSER === "opera"

您还可以访问所有 Vite 的环境变量

用法 类型 描述
import.meta.env.MODE string 扩展程序运行的 模式
import.meta.env.PROD boolean NODE_ENV='production'
import.meta.env.DEV boolean import.meta.env.PROD 的相反值

其他 Vite 环境变量

Vite 提供了另外两个环境变量,但在 WXT 项目中它们并不实用:

  • import.meta.env.BASE_URL:应使用 browser.runtime.getURL 代替。
  • import.meta.env.SSR:始终为 false

清单中使用环境变量

要在清单中使用环境变量,您需要使用函数语法:

export default defineConfig({
  extensionApi: 'chrome',
  modules: ['@wxt-dev/module-vue'],
  manifest: { 
    oauth2: { 
      client_id: import.meta.env.WXT_APP_CLIENT_ID
    } 
  } 
  manifest: () => ({ 
    oauth2: { 
      client_id: import.meta.env.WXT_APP_CLIENT_ID
    } 
  }), 
});

WXT 在加载配置文件后才能加载您的 .env 文件。因此,通过使用函数语法为 manifest 延迟创建对象,直到 .env 文件被加载到进程中。

最后感谢阅读!欢迎关注我,微信公众号倔强青铜三。欢迎点赞收藏关注,一键三连!!!

WXT浏览器插件开发中文教程(6)----WXT配置详解之自动导入

2025年3月29日 14:50

前言

大家好,我是倔强青铜三。是一名热情的软件工程师,我热衷于分享和传播IT技术,致力于通过我的知识和技能推动技术交流与创新,欢迎关注我,微信公众号:倔强青铜三。欢迎点赞、收藏、关注,一键三连!!!

自动导入

WXT 使用了与 Nuxt 相同的工具 unimport 来设置自动导入。

export default defineConfig({
  // 请参阅 [https://www.npmjs.com/package/unimport#configurations](https://www.npmjs.com/package/unimport#configurations)
  imports: {
    // ...
  },
});

默认情况下,WXT 会自动为自身的所有 API 以及项目中的某些目录设置自动导入:

  • <srcDir>/components/*
  • <srcDir>/composables/*
  • <srcDir>/hooks/*
  • <srcDir>/utils/*

这些目录中的文件的所有命名导出和默认导出都可以在项目中的其他地方直接使用,无需手动导入。

要查看完整的自动导入 API 列表,请运行 wxt prepare 命令,并查看项目中的 .wxt/types/imports-module.d.ts 文件。

TypeScript

为了让 TypeScript 和编辑器识别自动导入的变量,你需要运行 wxt prepare 命令。

将此命令添加到你的 postinstall 脚本中,以便在安装依赖项后,编辑器能够正确报告类型错误:

// package.json
{
  "scripts": {
    "postinstall": "wxt prepare", 
  },
}

ESLint

除非在 ESLint 的 globals 中明确声明,否则 ESLint 无法识别自动导入的变量。默认情况下,如果 WXT 检测到项目中安装了 ESLint,它会自动生成配置文件。如果配置文件没有自动生成,你可以手动让 WXT 生成它。

ESLint 9 配置如下:

export default defineConfig({
  imports: {
    eslintrc: {
      enabled: 9,
    },
  },
});

ESLint 8配置如下:

export default defineConfig({
  imports: {
    eslintrc: {
      enabled: 8,
    },
  },
});

然后在你的 ESLint 配置文件中,导入并使用生成的文件:

ESLint 9 配置如下:

// eslint.config.mjs
import autoImports from './.wxt/eslint-auto-imports.mjs';
export default [
  autoImports,
  {
    // 你的其他配置...
  },
];

ESLint 8 配置如下:

// .eslintrc.mjs
export default {
  extends: ['./.wxt/eslintrc-auto-import.json'],
  // 你的其他配置...
};

禁用自动导入

并非所有开发人员都喜欢自动导入。要禁用自动导入,将 imports 设置为 false

export default defineConfig({
  imports: false, 
});

显式导入 (#imports)

你可以通过 #imports 模块手动导入 WXT 的所有 API:

import {
  createShadowRootUi,
  ContentScriptContext,
  MatchPattern,
} from '#imports';

要了解 #imports 模块的工作原理,请阅读 相关博客文章

如果你已经禁用了自动导入,仍然应该使用 #imports 从单一位置导入 WXT 的所有 API。

最后感谢阅读!欢迎关注我,微信公众号倔强青铜三。欢迎点赞收藏关注,一键三连!!!

WXT浏览器插件开发中文教程(5)----WXT配置详解之浏览器启动设置

2025年3月29日 14:39

前言

大家好,我是倔强青铜三。是一名热情的软件工程师,我热衷于分享和传播IT技术,致力于通过我的知识和技能推动技术交流与创新,欢迎关注我,微信公众号:倔强青铜三。欢迎点赞、收藏、关注,一键三连!!!

浏览器启动设置

请参阅 API 参考 以获取完整的配置列表。

在开发过程中,WXT 使用 Mozilla 提供的 web-ext 自动打开一个已安装您扩展程序的浏览器窗口。

配置文件

您可以在以下三个位置配置浏览器启动:

  1. <rootDir>/web-ext.config.ts:此文件不纳入版本控制,允许您为特定项目配置自己的选项,而不会影响其他开发人员

    import { defineWebExtConfig } from 'wxt';
    export default defineWebExtConfig({
      // ...
    });
    
  2. <rootDir>/wxt.config.ts:通过 runner 配置,包含在版本控制中

  3. $HOME/web-ext.config.ts:为计算机上的所有 WXT 项目提供默认值

设置浏览器二进制文件

设置或自定义开发期间打开的浏览器:

export default defineWebExtConfig({
  binaries: {
    chrome: '/path/to/chrome-beta', // 使用 Chrome Beta 而不是常规 Chrome
    firefox: 'firefoxdeveloperedition', // 使用 Firefox Developer Edition 而不是常规 Firefox
    edge: '/path/to/edge', // 在运行 "wxt -b edge" 时打开 MS Edge
  },
});

默认情况下,WXT 会尝试自动发现 Chrome/Firefox 的安装位置。但是,如果您将 chrome 安装在非标准位置,您需要像上面所示手动设置它。

持久化数据

默认情况下,为了避免修改浏览器现有的配置文件,web-ext 每次运行 dev 脚本时都会创建一个全新的配置文件。

目前,基于 Chromium 的浏览器是唯一支持覆盖此行为并在多次运行 dev 脚本时持久化数据的浏览器。

要持久化数据,请设置 --user-data-dir 标志:

Mac/Linux

export default defineWebExtConfig({
  chromiumArgs: ['--user-data-dir=./.wxt/chrome-data'],
});

Windows

import { resolve } from 'node:path';
export default defineWebExtConfig({
  // 在 Windows 上,路径必须是绝对路径
  chromiumProfile: resolve('.wxt/chrome-data'),
  keepProfileChanges: true,
});

现在,下次您运行 dev 脚本时,将在 .wxt/chrome-data/{profile-name} 中创建一个持久化配置文件。使用持久化配置文件,您可以安装开发工具扩展程序以帮助开发,允许浏览器记住登录信息等,而不必担心下次运行 dev 脚本时配置文件会被重置。

提示

您可以使用任何目录作为 --user-data-dir,上面的示例为每个 WXT 项目创建了一个持久化配置文件。要为所有 WXT 项目创建一个配置文件,您可以将 chrome-data 目录放在用户主目录中。

禁用打开浏览器

如果您更愿意手动将扩展程序加载到浏览器中,您可以禁用自动打开行为:

export default defineWebExtConfig({
  disabled: true,
});

最后感谢阅读!欢迎关注我,微信公众号倔强青铜三。欢迎点赞收藏关注,一键三连!!!

WXT浏览器插件开发中文教程(4)----WXT配置详解之manifest清单

2025年3月29日 14:27

前言

大家好,我是倔强青铜三。是一名热情的软件工程师,我热衷于分享和传播IT技术,致力于通过我的知识和技能推动技术交流与创新,欢迎关注我,微信公众号:倔强青铜三。欢迎点赞、收藏、关注,一键三连!!!

清单

=======================

在 WXT 中,您的源代码中没有 manifest.json 文件。相反,WXT 从多个来源生成清单:

运行 wxt build 时,扩展的 manifest.json 将输出到 .output/{target}/manifest.json

全局选项

要向清单中添加属性,请在 wxt.config.ts 中使用 manifest 配置:

export default defineConfig({
  manifest: {
    // 在此处进行手动更改
  },
});

您还可以将清单定义为一个函数,并使用 JavaScript 根据目标浏览器、模式等生成清单。

export default defineConfig({
  manifest: ({ browser, manifestVersion, mode, command }) => {
    return {
      // ...
    };
  },
});

MV2 和 MV3 兼容性

在向清单添加属性时,尽可能使用 MV3 格式。当针对 MV2 时,WXT 会自动将这些属性转换为 MV2 格式。

例如,对于以下配置:

export default defineConfig({
  manifest: {
    action: {
      default_title: 'Some Title',
    },
    web_accessible_resources: [
      {
        matches: ['*://*.google.com/*'],
        resources: ['icon/*.png'],
      },
    ],
  },
});

WXT 将生成以下清单:

MV2版本的清单

{
  "manifest_version": 2,
  // ...
  "browser_action": {
    "default_title": "Some Title"
  },
  "web_accessible_resources": ["icon/*.png"]
}

MV3版本的清单

{
  "manifest_version": 3,
  // ...
  "action": {
    "default_title": "Some Title"
  },
  "web_accessible_resources": [
    {
      "matches": ["*://*.google.com/*"],
      "resources": ["icon/*.png"]
    }
  ]
}

您还可以指定特定于单个清单版本的属性,这些属性将在针对其他清单版本时被移除。

名称

Chrome 文档

如果未通过 manifest 配置提供名称,清单的 name 属性默认为 package.jsonname 属性。

版本和版本名称

Chrome 文档

扩展的 versionversion_name 基于 package.jsonversion

  • version_name 是列出的确切字符串
  • version 是清理后的字符串,去除了任何无效的后缀

示例:

// package.json
{
  "version": "1.3.0-alpha2"
}
// .output/<target>/manifest.json
{
  "version": "1.3.0",
  "version_name": "1.3.0-alpha2"
}

如果 package.json 中没有版本,它默认为 "0.0.0"

图标

WXT 通过查看 public/ 目录中的文件自动发现扩展的图标:

public/
├─ icon-16.png
├─ icon-24.png
├─ icon-48.png
├─ icon-96.png
└─ icon-128.png

具体来说,图标必须匹配以下正则表达式才能被发现:

const iconRegex = [
  /^icon-([0-9]+)\.png$/,                 // icon-16.png
  /^icon-([0-9]+)x[0-9]+\.png$/,          // icon-16x16.png
  /^icon@([0-9]+)w\.png$/,                // icon@16w.png
  /^icon@([0-9]+)h\.png$/,                // icon@16h.png
  /^icon@([0-9]+)\.png$/,                 // icon@16.png
  /^icons?[/\\]([0-9]+)\.png$/,          // icon/16.png | icons/16.png
  /^icons?[/\\]([0-9]+)x[0-9]+\.png$/,   // icon/16x16.png | icons/16x16.png
];

如果您不喜欢这些文件名,或者正在迁移到 WXT 而不想重命名文件,可以在清单中手动指定 icon

export default defineConfig({
  manifest: {
    icons: {
      16: '/extension-icon-16.png',
      24: '/extension-icon-24.png',
      48: '/extension-icon-48.png',
      96: '/extension-icon-96.png',
      128: '/extension-icon-128.png',
    },
  },
});

或者,您可以使用 @wxt-dev/auto-icons 让 WXT 生成所需尺寸的图标。

权限

Chrome 文档

大多数情况下,您需要手动向清单中添加权限。只有在少数特定情况下会自动添加权限:

  • 在开发过程中:会添加 tabsscripting 权限以启用热重载。
  • 当存在 sidepanel 入口点时:会添加 sidepanel 权限。
export default defineConfig({
  manifest: {
    permissions: ['storage', 'tabs'],
  },
});

主机权限

Chrome 文档

export default defineConfig({
  manifest: {
    host_permissions: ['https://www.google.com/  *'],
  },
});

警告

如果您使用主机权限并同时针对 MV2 和 MV3,请确保仅包含每个版本所需的主机权限:

export default defineConfig({
  manifest: ({ manifestVersion }) => ({
    host_permissions: manifestVersion === 2 ? [...] : [...],
  }),
});

默认语言

export default defineConfig({
  manifest: {
    name: '__MSG_extName__',
    description: '__MSG_extDescription__',
    default_locale: 'en',
  },
});

有关国际化扩展的完整指南,请参阅 I18n 文档

Action

在 MV2 中,您有两个选择:browser_actionpage_action。在 MV3 中,它们合并为一个 action API。

默认情况下,每当生成 action 时,WXT 在针对 MV2 时会回退到 browser_action

带有弹出窗口的Action

要生成在点击图标后显示 UI 的清单,只需创建一个 弹出窗口入口点。如果您想在 MV2 中使用 page_action,请在 HTML 文档的头部添加以下元标签:

<meta name="manifest.type" content="page_action" />

不带弹出窗口的Action

如果您想使用 activeTab 权限或 browser.action.onClicked 事件,但不想显示弹出窗口:

  1. 如果存在 弹出窗口入口点,请将其删除

  2. 在清单中添加 action 键:

    export default defineConfig({
      manifest: {
        action: {},
      },
    });
    

与带弹出窗口的Action相同,WXT 会回退到使用 MV2 的 browser_action。如果想改用 page_action,也添加该键:

export default defineConfig({
  manifest: {
    action: {},
    page_action: {},
  },
});

最后感谢阅读!欢迎关注我,微信公众号倔强青铜三。欢迎点赞收藏关注,一键三连!!!

❌
❌