Skip to content

常见问题

关于如何使用 WXT 或其行为原因的常见问题。

为什么内容脚本没有被添加到 manifest 中?

在开发过程中,WXT 会动态注册内容脚本,这样在保存文件时可以单独重新加载它们,而无需重新加载整个扩展。

要列出开发过程中注册的内容脚本,请打开 Service Worker 的控制台并运行:

js
await chrome.scripting.getRegisteredContentScripts();

如何禁止开发时自动打开浏览器?

参见 https://wxt.dev/guide/essentials/config/browser-startup.html#disable-opening-browser

如何在开发过程中保持网站的登录状态?

参见 https://wxt.dev/guide/essentials/config/browser-startup.html#persist-data

我的组件库在内容脚本中无法正常工作

使用 createShadowRootUi 时,这通常由以下一个(或两个)原因导致:

  1. 样式被添加到了 ShadowRoot 之外

    Details

    某些组件库会通过添加 <style><link> 元素来手动将 CSS 添加到页面中。默认情况下,它们会将这些元素放置在文档的 <head> 中。这会导致你的样式被放置在 ShadowRoot 之外,而 Shadow DOM 的隔离特性会阻止这些样式应用到你的 UI 上。

    当组件库出现这种情况时,你需要告诉组件库将样式放在哪里。以下是一些流行组件库的文档:

    如果你的组件库未在上面列出,请尝试在其文档/issues 中搜索 "shadow root"、"shadow dom" 或 "css container"。并非所有组件库都支持 Shadow DOM,你可能需要提交 issue 来请求此功能。

    以下是配置 Antd 样式的示例:

    tsx
    import { StyleProvider } from '@ant-design/cssinjs';
    import ReactDOM from 'react-dom/client';
    import App from './App.tsx';
    
    const ui = await create`ShadowRoot`Ui(ctx, {
      // ...
      onMount: (container, shadow) => {
        const cssContainer = shadow.querySelector('head')!;
        const root = ReactDOM.createRoot(container);
        root.render(
          <StyleProvider container={cssContainer}>
            <App />
          </StyleProvider>,
        );
        return root;
      },
    });
  2. UI 元素被添加到了 ShadowRoot 之外

    Details

    这主要是由 TeleportPortal 组件引起的,这些组件会将元素渲染到 DOM 中的其他位置,通常是文档的 <body> 中。这常见于对话框或弹出层组件。由于元素被渲染到了 ShadowRoot 之外,样式无法应用到它上面。

    要解决此问题,你需要同时为应用提供一个目标元素,并将该目标传递给 Teleport/Portal

    首先,存储对 ShadowRoot<body> 元素(而非文档的 <body>)的引用:

    ts
    import { createApp } from 'vue';
    import App from './App.vue';
    
    const ui = await create`ShadowRoot`Ui(ctx, {
      // ...
      onMount: (container, shadow) => {
        const teleportTarget = shadow.querySelector('body')!;
        const app = createApp(App)
          .provide('TeleportTarget', teleportTarget)
          .mount(container);
        return app;
      },
    });
    ui.mount();
    tsx
    // hooks/PortalTargetContext.ts
    import { createContext } from 'react';
    
    export const PortalTargetContext = createContext<HTMLElement>();
    
    // entrypoints/example.content.ts
    import ReactDOM from 'react-dom/client';
    import App from './App.tsx';
    import PortalTargetContext from '~/hooks/PortalTargetContext';
    
    const ui = await create`ShadowRoot`Ui(ctx, {
      // ...
      onMount: (container, shadow) => {
        const portalTarget = shadow.querySelector('body')!;
        const root = ReactDOM.createRoot(container);
        root.render(
          <PortalTargetContext.Provider value={portalTarget}>
            <App />
          </PortalTargetContext.Provider>,
        );
        return root;
      },
    });
    ui.mount();

    然后在将 UI 的一部分传送/传递到 DOM 中的其他位置时使用该引用:

    vue
    <script lang="ts" setup>
    import { Teleport } from 'vue';
    
    const teleportTarget = inject('TeleportTarget');
    </script>
    
    <template>
      <div>
        <Teleport :to="teleportTarget">
          <dialog>My dialog</dialog>
        </Teleport>
      </div>
    </template>
    tsx
    import { useContext } from 'react';
    import { createPortal } from 'react-dom';
    import PortalTargetContext from '~/hooks/PortalTargetContext';
    
    const MyComponent = () => {
      const portalTarget = useContext(PortalTargetContext);
    
      return <div>{createPortal(<dialog>My dialog</dialog>, portalTarget)}</div>;
    };

    如果你使用 ShadCN,请参阅这篇博客文章

这两个问题有相同的根本原因:组件库将某些内容放置在了 ShadowRoot 之外,而 ShadowRoot 的隔离特性阻止了 CSS 应用到你的 UI 上。

这两个问题的解决方法也相同:告诉组件库将元素放置在 ShadowRoot 内部,而不是外部。请参阅上面的详细信息,了解更多信息和每个问题的示例修复方法。

WXT 是否提供 LLM 文档?

是的,WXT 的文档基于 /llms.txt 提案 提供了 Markdown 文件。

是否有基于 WXT 文档训练的 LLM 可以对话?

是的!页面右下角有一个 "Ask AI" 按钮,快试试吧!或者访问 https://knowledge.wxt.dev/ 获得全屏体验。

此外,如果你想训练自己的模型或为编辑器提供上下文,可以使用网站托管的 LLM 知识文件:

https://wxt.dev/knowledge/index.json

你不需要爬取整个网站,这些文件已经包含了所有与训练 LLM 相关的 WXT 文档。但如果你愿意,也可以自行爬取并生成自己的文件!

如何使用 Docker / devcontainers 运行 WXT 项目?

要在 devcontainer 中运行 WXT 开发服务器,但在浏览器中加载扩展的开发构建版本:

  1. 将项目目录绑定挂载到宿主机 如果你使用 VS Code,可以通过 Dev Containers: Open Folder in Container... 命令打开项目文件夹。这会保持文件夹在宿主机和 devcontainer 之间的同步,确保扩展的 dist 目录从宿主机仍然可以访问。

  2. 禁用自动打开浏览器 WXT 在开发过程中会自动打开浏览器,但由于你在容器中运行,它无法访问浏览器。请按照此处的指南wxt.config.ts 中禁用浏览器自动打开。

  3. 让 WXT 监听所有网络接口 要启用热重载,你的扩展需要连接到容器内运行的 WXT 开发服务器。WXT 默认只监听 localhost,这会阻止来自 devcontainer 外部的连接。要解决此问题,你可以使用 wxt --host 0.0.0.0 让 WXT 监听所有接口。

如何使用 Chrome 的新 Prompt API?

如果你让 WXT 在开发模式下打开浏览器,负责 Prompt API 的服务默认不会启用。检查 LanguageModel.availability 时,你将始终收到 "unavailable"。

你有两个选择:

  1. 传递 --disable-features=DisableLoadExtensionCommandLineSwitch 功能标志以在 WXT 打开的浏览器中启用该服务:

    ts
    // wxt.config.ts
    export default defineConfig({
      webExt: {
        chromiumArgs: [
          '--disable-features=DisableLoadExtensionCommandLineSwitch',
        ],
      },
    });
  2. 禁用 runner 并在常规 Chrome 配置文件中手动安装扩展:

    ts
    // wxt.config.ts
    export default defineConfig({
      webExt: {
        disabled: true,
      },
    });