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 来注入代码文件到页面中,进而达到获取和修改页面中 window 上的数据。

这种通过 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: [
    //    ...
    //    在这里你可以配置所有 webextkit 提供的 vite 插件
    ViteWebExtKits({
      extensionId: extId,
      transformersInputFolderPath: "./injectScripts",
    }),
  ],
});
import { defineConfig } from "vite";

export default defineConfig({
  //  ...
  plugins: [
    //    ...
    //    在这里你可以配置所有 webextkit 提供的 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.tsxreact 组件,那么这个 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