使用 wxt 框架开发浏览器扩展遇到的问题?

这是 A 扩展注入的 content 代码

export default defineContentScript({
  matches: ['<all_urls>'],
  cssInjectionMode: 'ui',
  runAt: 'document_end',
  async main(ctx) {
    console.log('执行 main 函数');
    const ui = await createShadowRootUi(ctx, {
      name: 'example-ui',
      position: 'inline',
      onMount: (uiContainer) => {
        console.log('执行 onMount 函数');
        const app = document.createElement('div');
        uiContainer.append(app);
        const root = createRoot(app);
        root.render(
          <StrictMode>
            <App></App>
          </StrictMode>,
        );
        return root;
      },
      onRemove: (root) => {
        console.log('执行 unmount 函数');
        root?.unmount();
      },
    });
    ui.mount();
  },
});

这是 B 扩展注入的 content 代码

export default defineContentScript({
  matches: ['<all_urls>'],
  async main(ctx) {
    // 给 window 注入 __cls-context__  表示这个是 content 脚本
    window['__cls-context__'] = 'content';
    const ui = await createIntegratedUi(ctx, {
      position: 'inline',
      onMount: (uiContainer) => {
        const app = document.createElement('div');
        uiContainer.append(app);
        const root = createRoot(app);
        root.render(
          <StrictMode>
            <App></App>
          </StrictMode>,
        );
        return root;
      },
      onRemove: (root) => {
        root?.unmount();
      },
    });
    ui.mount();
  },
});

这两个扩展都独立打包。
有用户反映装了 B 扩展后 A 扩展就失效了,通过调试发现如果扩展 B 安装后,扩展 A 的 unmount 函数就会执行,导致扩展 A 的功能不见了。
不知道大家在使用 wxt 时是否遇到这种问题,这问题感觉太奇怪了

阅读 249
avatarAI BotBETA

回答

在使用 wxt 框架开发浏览器扩展时,如果两个扩展都试图在相同的页面上注入 UI,可能会发生冲突。这通常是因为两个扩展都试图修改相同的 DOM 结构或使用了相同的挂载机制。

在你的案例中,扩展 A 使用 createShadowRootUi 方法创建了一个 Shadow Root UI,而扩展 B 使用 createIntegratedUi 方法创建了一个集成 UI。这两个方法可能在内部有不同的 DOM 挂载逻辑,但都可能影响到页面的 DOM 结构。

当扩展 B 安装后,扩展 A 的 unmount 函数被执行,这通常意味着扩展 A 的 UI 被从 DOM 中移除。这可能是因为扩展 B 的 UI 挂载逻辑导致了 DOM 结构的变化,从而触发了扩展 A 的卸载逻辑。

为了解决这个问题,你可以尝试以下几种方法:

  1. 确保 UI 挂载位置不冲突

    • 检查两个扩展的 UI 是否挂载到了相同的 DOM 元素上。
    • 尝试为扩展 A 和扩展 B 指定不同的挂载点或使用不同的挂载方法。
  2. 使用命名空间或唯一标识符

    • 在创建 UI 时,为扩展 A 和扩展 B 使用不同的命名空间或唯一标识符,以避免冲突。
  3. 调试和日志记录

    • 增加更多的日志记录,以便更好地理解扩展 A 的 unmount 函数被触发的原因。
    • 使用浏览器的开发者工具来观察 DOM 结构的变化。
  4. 检查 wxt 框架的文档和社区

    • 查看 wxt 框架的官方文档,了解是否有关于多个扩展共存的最佳实践或指导。
    • 搜索或询问 wxt 框架的社区,看看是否有人遇到过类似的问题并找到了解决方案。

这个问题可能涉及到多个方面的因素,需要仔细调试和分析才能找到根本原因。希望这些建议能帮助你解决问题。

1 个回答

使用 Shadow DOM 来隔离它们的样式和 DOM 结构,这样两个扩展不会相互干扰。

A扩展的改动

在 onMount 函数中,添加了 Shadow DOM 的创建:

const shadowRoot = uiContainer.attachShadow({ mode: 'open' });
const app = document.createElement('div');
shadowRoot.append(app);

B扩展的改动

同样在 onMount 函数中,添加了 Shadow DOM 的创建:

const shadowRoot = uiContainer.attachShadow({ mode: 'open' });
const app = document.createElement('div');
shadowRoot.append(app);

完整改动示例

A 扩展的 content 代码

export default defineContentScript({
  matches: ['<all_urls>'],
  cssInjectionMode: 'ui',
  runAt: 'document_end',
  async main(ctx) {
    console.log('执行 main 函数');
    const ui = await createShadowRootUi(ctx, {
      name: 'example-ui',
      position: 'inline',
      onMount: (uiContainer) => {
        console.log('执行 onMount 函数');
        const shadowRoot = uiContainer.attachShadow({ mode: 'open' }); // 添加了这行
        const app = document.createElement('div');
        shadowRoot.append(app); // 修改了这行
        const root = createRoot(app);
        root.render(
          <StrictMode>
            <App></App>
          </StrictMode>,
        );
        return root;
      },
      onRemove: (root) => {
        console.log('执行 unmount 函数');
        root?.unmount();
      },
    });
    ui.mount();
  },
});

B 扩展的 content 代码

export default defineContentScript({
  matches: ['<all_urls>'],
  async main(ctx) {
    // 给 window 注入 __cls-context__ 表示这个是 content 脚本
    window['__cls-context__'] = 'content';
    const ui = await createIntegratedUi(ctx, {
      position: 'inline',
      onMount: (uiContainer) => {
        const shadowRoot = uiContainer.attachShadow({ mode: 'open' }); // 添加了这行
        const app = document.createElement('div');
        shadowRoot.append(app); // 修改了这行
        const root = createRoot(app);
        root.render(
          <StrictMode>
            <App></App>
          </StrictMode>,
        );
        return root;
      },
      onRemove: (root) => {
        root?.unmount();
      },
    });
    ui.mount();
  },
});
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏