Skip to content

InjectScript

什么是 InjectScript

InjectScript(非官方命名)是指通过 background.js 注入到页面的脚本文件。如下面的例子,injects/index.js 会在符合 https://github.com/* 规则的网页加载完成后被注入到页面中。

typescript
browser.scripting.registerContentScripts([
  {
    id: `inject-module`,
    js: ["injects/index.js"],
    matches: ["https://github.com/*"],
    runAt: "document_end",
    world: "MAIN",
  },
]);
browser.scripting.registerContentScripts([
  {
    id: `inject-module`,
    js: ["injects/index.js"],
    matches: ["https://github.com/*"],
    runAt: "document_end",
    world: "MAIN",
  },
]);

使用 InjectScript 而不是 contentScript 的主要原因是 MV3 中强制对 contentScript 实行了隔离策略,见官方文档 Work in isolated worlds

Content scripts live in an isolated world, allowing a content script to make changes to its JavaScript environment without conflicting with the page or other extensions' content scripts.

这意味着我们无法在 contentScript 中读取或者修改页面中 window 上的数据.

为了让扩展能像 MV2 一样读取和修改页面中 window 上的数据,我们需要通过 browser.scripting.registerContentScripts 这个 API 来注入代码文件到页面中。

这种通过 browser.scripting.registerContentScripts API 注册的脚本文件,我们称之为 InjectScript

TIP

由于 browser.scripting.registerContentScripts API 只支持 IIFE(立即调用函数表达式)文件注册(不允许其中包含 require 或者 import 的模块引用),需要注册的脚本文件为 IIFE 格式,否则会报错

如何配置

webextkits 开箱即用,默认不需要任何配置。

如果你想要(最好不要)指定 injectScripts 的默认文件夹,可以通过 injectsInputFolderPath 配置来指定文件夹位置。

typescript
import { defineConfig } from "vite";

export default defineConfig({
  //  ...
  plugins: [
    //    ...
    //    在这里你可以配置所有 webextkits 提供的 vite 插件
    ViteWebExtKits({
      extensionId: extId,
      transformersInputFolderPath: "./injectScripts",
    }),
  ],
});
import { defineConfig } from "vite";

export default defineConfig({
  //  ...
  plugins: [
    //    ...
    //    在这里你可以配置所有 webextkits 提供的 vite 插件
    ViteWebExtKits({
      extensionId: extId,
      transformersInputFolderPath: "./injectScripts",
    }),
  ],
});

转换原理与规则

项目启动时默认会读取 /src/scopes/injects 文件夹下所有以 *.entry.{ts,tsx} 格式命名的入口文件,经过 Vite 打包后存放到 /dist/injects 文件夹下。

因此我们需要保证入口文件的命名格式符合 *.entry.{ts,tsx} 规则。

然后在 background.ts 中把它们注册为 InjectScript 即可。

比如 main.entry.tsadd-friends.entry.tsx,转换后会存放到 /dist/injects/main.js/dist/injects/add-friends.js

background 中注册:

TIP

如果你在入口文件中引入了样式文件,它们也会被打包存放在 /dist/injects/[入口文件名称].css 中,比如 add-friends.css

typescript
browser.scripting.registerContentScripts([
  {
    id: `inject-module`,
    js: ["injects/main.js"],
    matches: ["https://github.com/"],
    runAt: "document_end",
    world: "MAIN",
  },
]);

browser.scripting.registerContentScripts([
  {
    id: `inject-add-friends-module`,
    js: ["injects/add-firends.js"],
    css: ["injects/add-friends.css"],
    matches: ["https://github.com/add-firends"],
    runAt: "document_end",
    world: "MAIN",
  },
]);
browser.scripting.registerContentScripts([
  {
    id: `inject-module`,
    js: ["injects/main.js"],
    matches: ["https://github.com/"],
    runAt: "document_end",
    world: "MAIN",
  },
]);

browser.scripting.registerContentScripts([
  {
    id: `inject-add-friends-module`,
    js: ["injects/add-firends.js"],
    css: ["injects/add-friends.css"],
    matches: ["https://github.com/add-firends"],
    runAt: "document_end",
    world: "MAIN",
  },
]);

WARNING

/src/scopes/injects 目录下只有符合 *.entry.{ts,tsx} 命名规则的文件才会被当成 injectScript 的入口文件并经过 Vite 转换,不符合命名规则的文件不会被转换

多入口

要实现多入口,只需要添加多个符合 *.entry.{ts,tsx} 命名规则的文件 即可,比如下面的文件夹中存在 3 个入口 addFriends, index, 和 main

text
📦injects
 ┣ 📜addFriends.entry.ts
 ┣ 📜index.entry.tsx
 ┗ 📜main.entry.tsx
📦injects
 ┣ 📜addFriends.entry.ts
 ┣ 📜index.entry.tsx
 ┗ 📜main.entry.tsx

WARNING

如果你发现添加了入口文件,但是项目没有重新编译时,请重新启动下项目

模块文件夹

当 injectScript 代码逻辑变得庞大需要拆分时,为了让 Vite 能正确 watch 拆分后的文件,你应该将它们放在 /src/scopes/injects/[入口文件名称]/ 文件夹下。

比如入口文件 index.entry.tsx 引用了一个 ShowMeMore.tsx 的 React 组件,那么 ShowMeMore.tsx 应该放在 /src/scopes/injects/index/ShowMeMore.tsx 中。只有这样 Vite 的 watch 才能监听到文件更新并重新编译。目录结构如下:

text
📦injects
 ┣ 📂index
 ┃ ┣ 📜ShowMeMore.tsx
 ┣ 📜index.entry.tsx
📦injects
 ┣ 📂index
 ┃ ┣ 📜ShowMeMore.tsx
 ┣ 📜index.entry.tsx

如果你有多个入口文件,每个入口文件都有对应的依赖文件,那么它们看起来是这样的

text
📦injects
 ┣ 📂index
 ┃ ┣ 📜ShowMeMore.tsx
 ┣ 📂main
 ┃ ┗ 📜utils.tsx
 ┣ 📜index.entry.tsx
 ┗ 📜main.entry.tsx
📦injects
 ┣ 📂index
 ┃ ┣ 📜ShowMeMore.tsx
 ┣ 📂main
 ┃ ┗ 📜utils.tsx
 ┣ 📜index.entry.tsx
 ┗ 📜main.entry.tsx

Powered by Vitepress