You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chrome扩展注入内容脚本的React渲染及Import依赖问题求助

解决方案:Chrome扩展注入React组件 + Vite打包配置

问题根源

你当前通过chrome.scripting.executeScript的func参数注入ui函数时,函数会被序列化为纯字符串传递到主世界执行,但外部依赖(如createRoot、App组件)不会被一同序列化。主世界环境中没有这些依赖的定义,因此会出现"渲染函数未定义"的错误。另外,Vite默认的打包逻辑不适配Chrome扩展的多入口(后台Service Worker、内容脚本、注入脚本)需求,需要针对性配置。


解决步骤

1. 重构注入逻辑:从注入函数改为注入打包后的脚本

放弃func参数传递带依赖的函数,改为将React相关代码打包成独立脚本,通过files参数注入。

后台脚本修改(background.ts)

(() => {
    async function inject(tabId: number, scriptPath: string, ...args: Array<any>) {
        // 先将参数挂载到主世界的全局变量
        await chrome.scripting.executeScript({
            target: { tabId },
            world: "MAIN",
            injectImmediately: true,
            func: (args) => {
                (window as any).__INJECT_ARGS__ = args;
            },
            args: [args],
        });

        // 注入打包后的UI脚本
        await chrome.scripting.executeScript({
            target: { tabId },
            world: "MAIN",
            injectImmediately: true,
            files: [scriptPath],
        });

        return !chrome.runtime.lastError;
    }

    chrome.runtime.onConnect.addListener(async (connection) => {
        if (connection.name === "connect") {
            await inject(connection.sender.tab.id!, "/dist/ui-inject.js", chrome.runtime.id);
        }
    });
})();

独立UI注入脚本(ui-inject.tsx)

将React组件渲染逻辑和依赖全部包含在这个文件中,通过全局变量获取注入参数:

import { createRoot } from "react-dom/client";
import { App } from "./ui/App.tsx";

// 获取后台注入的参数
const [runtimeId] = (window as any).__INJECT_ARGS__;

const connection = chrome.runtime.connect(runtimeId, { name: "ui" });
// 处理连接逻辑...

function render() {
    if (!document.head || !document.body) {
        setTimeout(render, 100);
        return;
    }

    const element = document.createElement("div");
    // 给容器加样式避免和页面样式冲突
    element.style.position = "fixed";
    element.style.zIndex = "9999";
    element.style.top = "0";
    element.style.left = "0";
    document.body.appendChild(element);

    const root = createRoot(element);
    root.render(<App />);
}

render();

2. Vite打包配置适配Chrome扩展

修改vite.config.ts,配置多入口打包,适配后台Service Worker、内容脚本、UI注入脚本的需求:

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
    plugins: [react()],
    build: {
        rollupOptions: {
            // 配置多个入口文件
            input: {
                background: "./src/background.ts",
                content: "./src/content-script.ts", // 你的WebSocket连接内容脚本
                "ui-inject": "./src/ui-inject.tsx",
            },
            output: {
                // 输出到dist目录,保持文件名和入口名一致
                entryFileNames: "[name].js",
                chunkFileNames: "[name].js",
                assetFileNames: "[name].[ext]",
            },
        },
        // 禁用sourcemap,避免Chrome扩展加载报错
        sourcemap: false,
        outDir: "dist",
    },
});

3. Manifest配置(manifest.json)

确保Manifest v3配置正确关联打包后的文件:

{
    "manifest_version": 3,
    "name": "你的扩展名称",
    "version": "1.0",
    "background": {
        "service_worker": "dist/background.js"
    },
    "content_scripts": [
        {
            "matches": ["<all_urls>"],
            "js": ["dist/content.js"],
            "run_at": "document_start"
        }
    ],
    "permissions": ["scripting", "activeTab"],
    "host_permissions": ["<all_urls>"]
}

关键注意事项

  • 主世界与隔离世界:注入的UI脚本运行在页面的主世界(MAIN),可以直接操作DOM,但无法访问其他内容脚本的变量,必须通过Chrome扩展API(如chrome.runtime.connect)与后台通信。
  • 依赖打包:Vite会自动将React、ReactDOM以及你的App组件打包进ui-inject.js,无需额外引入CDN资源。
  • 开发调试:使用vite build --watch命令开启监听模式,修改代码后自动重新打包,刷新Chrome扩展即可看到效果。

内容的提问来源于stack exchange,提问作者xaller

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 10:52:32