入口点(Entrypoints)
WXT 在打包你的扩展程序时,会使用 entrypoints/
目录内的文件作为输入。这些文件可以是 HTML、JS、CSS 或 Vite 支持的任何变体文件类型(TS、JSX、SCSS 等)。
文件夹结构
在 entrypoints/
目录中,入口点被定义为其中的单个文件或目录(包含一个 index
文件)。
📂 entrypoints/
📄 {name}.{ext}
📂 entrypoints/
📂 {name}/
📄 index.{ext}
入口点的 name
决定了入口点的类型。例如,要添加一个"后台"入口点,以下任意文件均可生效:
📂 entrypoints/
📄 background.ts
📂 entrypoints/
📂 background/
📄 index.ts
完整的入口点类型列表及其文件名模式,请参阅入口点类型章节。
包含其他文件
当使用入口点目录 entrypoints/{name}/index.{ext}
时,你可以在 index
文件旁边添加相关文件。
📂 entrypoints/
📂 popup/
📄 index.html ← 此文件是入口点
📄 main.ts
📄 style.css
📂 background/
📄 index.ts ← 此文件是入口点
📄 alarms.ts
📄 messaging.ts
📂 youtube.content/
📄 index.ts ← 此文件是入口点
📄 style.css
DANGER
切勿将入口点相关文件直接放在 entrypoints/
目录中。WXT 会将其视为入口点并尝试构建,通常会导致错误。
应使用目录存放该入口点:
📂 entrypoints/
📄 popup.html
📄 popup.ts
📄 popup.css
📂 popup/
📄 index.html
📄 main.ts
📄 style.css
深层嵌套的入口点
虽然 entrypoints/
目录可能类似于 Nuxt 或 Next.js 等 Web 框架的 pages/
目录,但它不支持以相同方式进行深层嵌套入口点。
入口点必须位于零级或一级深度,WXT 才能发现并构建它们:
📂 entrypoints/
📂 youtube/
📂 content/
📄 index.ts
📄 ...
📂 injected/
📄 index.ts
📄 ...
📂 youtube.content/
📄 index.ts
📄 ...
📂 youtube-injected/
📄 index.ts
📄 ...
未列出的入口点(Unlisted Entrypoints)
在 Web 扩展中,有两种类型的入口点:
- 已列出(Listed):在
manifest.json
中被引用 - 未列出(Unlisted):未在
manifest.json
中被引用
在 WXT 文档的其余部分中,已列出的入口点按其名称引用。例如:
- Popup(弹出页)
- Options(选项页)
- Background(后台)
- Content Script(内容脚本)
然而,并非所有 Web 扩展中的入口点都在清单中列出。有些未在清单中列出,但仍被扩展使用。例如:
- 安装扩展时在新标签页显示的欢迎页面
- 由内容脚本注入主世界的 JS 文件
有关如何添加未列出入口点的详细信息,请参阅:
定义清单选项
大多数已列出的入口点都有需要添加到 manifest.json
的选项。但在 WXT 中,你无需在单独文件中定义这些选项,而是在入口点文件本身内部定义这些选项。
例如,以下是如何为内容脚本定义 matches
:
export default defineContentScript({
matches: ['*://*.wxt.dev/*'],
main() {
// ...
},
});
对于 HTML 入口点,选项通过 <meta>
标签配置。例如,为 MV2 弹出页使用 page_action
:
<!doctype html>
<html lang="en">
<head>
<meta name="manifest.type" content="page_action" />
</head>
</html>
有关每个入口点内可配置选项的列表及定义方式,请参阅入口点类型章节。
在构建扩展时,WXT 会查看入口点中定义的选项,并据此生成清单文件。
入口点类型
后台(Background)
Filename | Output Path | |
---|---|---|
entrypoints/background.[jt]s | /background.js | |
entrypoints/background/index.[jt]s | /background.js |
export default defineBackground(() => {
// 后台加载时执行
});
export default defineBackground({
// 设置清单选项
persistent: undefined | true | false,
type: undefined | 'module',
// 设置 include/exclude 以从某些构建中移除后台
include: undefined | string[],
exclude: undefined | string[],
main() {
// 后台加载时执行,不能是异步函数
},
});
对于 MV2,后台作为脚本添加到后台页面。对于 MV3,后台变为 Service Worker。
定义后台入口点时,请记住 WXT 会在构建过程中在 NodeJS 环境中导入此文件。这意味着你不能在 main
函数之外放置任何运行时代码。
browser.action.onClicked.addListener(() => {
// ...
});
export default defineBackground(() => {
browser.action.onClicked.addListener(() => {
// ...
});
});
更多详情请参阅入口点加载器文档。
书签页(Bookmarks)
Filename | Output Path | |
---|---|---|
entrypoints/bookmarks.html | /bookmarks.html | |
entrypoints/bookmarks/index.html | /bookmarks.html |
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>标题</title>
<!-- 设置 include/exclude 以从某些构建中移除页面 -->
<meta name="manifest.include" content="['chrome', ...]" />
<meta name="manifest.exclude" content="['chrome', ...]" />
</head>
<body>
<!-- ... -->
</body>
</html>
定义书签页入口点时,WXT 会自动更新清单,用你的 HTML 页面覆盖浏览器的书签页面。
内容脚本(Content Scripts)
Filename | Output Path | |
---|---|---|
entrypoints/content.[jt]sx? | /content-scripts/content.js | |
entrypoints/content/index.[jt]sx? | /content-scripts/content.js | |
entrypoints/{name}.content.[jt]sx? | /content-scripts/{name}.js | |
entrypoints/{name}.content/index.[jt]sx? | /content-scripts/{name}.js |
export default defineContentScript({
// 设置清单选项
matches: string[],
excludeMatches: undefined | [],
includeGlobs: undefined | [],
excludeGlobs: undefined | [],
allFrames: undefined | true | false,
runAt: undefined | 'document_start' | 'document_end' | 'document_idle',
matchAboutBlank: undefined | true | false,
matchOriginAsFallback: undefined | true | false,
world: undefined | 'ISOLATED' | 'MAIN',
// 设置 include/exclude 以从某些构建中移除后台
include: undefined | string[],
exclude: undefined | string[],
// 配置 CSS 注入页面的方式
cssInjectionMode: undefined | "manifest" | "manual" | "ui",
// 配置内容脚本的注册方式/时机
registration: undefined | "manifest" | "runtime",
main(ctx: ContentScriptContext) {
// 内容脚本加载时执行,可以是异步函数
},
});
定义内容脚本入口点时,请记住 WXT 会在构建过程中在 NodeJS 环境中导入此文件。这意味着你不能在 main
函数之外放置任何运行时代码。
browser.runtime.onMessage.addListener((message) => {
// ...
});
export default defineBackground(() => {
browser.runtime.onMessage.addListener((message) => {
// ...
});
});
更多详情请参阅入口点加载器文档。
有关在内容脚本中创建 UI 和包含 CSS 的更多信息,请参阅内容脚本 UI。
开发者工具(Devtools)
Filename | Output Path | |
---|---|---|
entrypoints/devtools.html | /devtools.html | |
entrypoints/devtools/index.html | /devtools.html |
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- 设置 include/exclude 以从某些构建中移除页面 -->
<meta name="manifest.include" content="['chrome', ...]" />
<meta name="manifest.exclude" content="['chrome', ...]" />
</head>
<body>
<!-- ... -->
</body>
</html>
请参考开发者工具示例来添加不同的面板和窗格。
历史记录页(History)
Filename | Output Path | |
---|---|---|
entrypoints/history.html | /history.html | |
entrypoints/history/index.html | /history.html |
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>标题</title>
<!-- 设置 include/exclude 以从某些构建中移除页面 -->
<meta name="manifest.include" content="['chrome', ...]" />
<meta name="manifest.exclude" content="['chrome', ...]" />
</head>
<body>
<!-- ... -->
</body>
</html>
定义历史记录页入口点时,WXT 会自动更新清单,用你的 HTML 页面覆盖浏览器的历史记录页面。
新标签页(Newtab)
Filename | Output Path | |
---|---|---|
entrypoints/newtab.html | /newtab.html | |
entrypoints/newtab/index.html | /newtab.html |
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>标题</title>
<!-- 设置 include/exclude 以从某些构建中移除页面 -->
<meta name="manifest.include" content="['chrome', ...]" />
<meta name="manifest.exclude" content="['chrome', ...]" />
</head>
<body>
<!-- ... -->
</body>
</html>
定义新标签页入口点时,WXT 会自动更新清单,用你的 HTML 页面覆盖浏览器的新标签页。
选项页(Options)
Filename | Output Path | |
---|---|---|
entrypoints/options.html | /options.html | |
entrypoints/options/index.html | /options.html |
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>选项标题</title>
<!-- 自定义清单选项 -->
<meta name="manifest.open_in_tab" content="true|false" />
<meta name="manifest.chrome_style" content="true|false" />
<meta name="manifest.browser_style" content="true|false" />
<!-- 设置 include/exclude 以从某些构建中移除页面 -->
<meta name="manifest.include" content="['chrome', ...]" />
<meta name="manifest.exclude" content="['chrome', ...]" />
</head>
<body>
<!-- ... -->
</body>
</html>
弹出页(Popup)
Filename | Output Path | |
---|---|---|
entrypoints/popup.html | /popup.html | |
entrypoints/popup/index.html | /popup.html |
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- 设置清单中的 `action.default_title` -->
<title>默认弹出页标题</title>
<!-- 自定义清单选项 -->
<meta
name="manifest.default_icon"
content="{
16: '/icon-16.png',
24: '/icon-24.png',
...
}"
/>
<meta name="manifest.type" content="page_action|browser_action" />
<meta name="manifest.browser_style" content="true|false" />
<!-- 设置 include/exclude 以从某些构建中移除页面 -->
<meta name="manifest.include" content="['chrome', ...]" />
<meta name="manifest.exclude" content="['chrome', ...]" />
</head>
<body>
<!-- ... -->
</body>
</html>
沙盒页(Sandbox)
仅限 Chromium
Firefox 不支持沙盒页面。
Filename | Output Path | |
---|---|---|
entrypoints/sandbox.html | /sandbox.html | |
entrypoints/sandbox/index.html | /sandbox.html | |
entrypoints/{name}.sandbox.html | /{name}.html | |
entrypoints/{name}.sandbox/index.html | /{name}.html |
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>标题</title>
<!-- 设置 include/exclude 以从某些构建中移除页面 -->
<meta name="manifest.include" content="['chrome', ...]" />
<meta name="manifest.exclude" content="['chrome', ...]" />
</head>
<body>
<!-- ... -->
</body>
</html>
侧边面板(Side Panel)
Filename | Output Path | |
---|---|---|
entrypoints/sidepanel.html | /sidepanel.html | |
entrypoints/sidepanel/index.html | /sidepanel.html | |
entrypoints/{name}.sidepanel.html | /{name}.html` | |
entrypoints/{name}.sidepanel/index.html | /{name}.html` |
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>默认侧边面板标题</title>
<!-- 自定义清单选项 -->
<meta
name="manifest.default_icon"
content="{
16: '/icon-16.png',
24: '/icon-24.png',
...
}"
/>
<meta name="manifest.open_at_install" content="true|false" />
<meta name="manifest.browser_style" content="true|false" />
<!-- 设置 include/exclude 以从某些构建中移除页面 -->
<meta name="manifest.include" content="['chrome', ...]" />
<meta name="manifest.exclude" content="['chrome', ...]" />
</head>
<body>
<!-- ... -->
</body>
</html>
在 Chrome 中,侧边面板使用 side_panel
API,而 Firefox 使用 sidebar_action
API。
未列出的 CSS(Unlisted CSS)
Filename | Output Path | |
---|---|---|
entrypoints/{name}.(css|scss|sass|less|styl|stylus) | /{name}.css | |
entrypoints/{name}/index.(css|scss|sass|less|styl|stylus) | /{name}.css | |
entrypoints/content.(css|scss|sass|less|styl|stylus) | /content-scripts/content.css | |
entrypoints/content/index.(css|scss|sass|less|styl|stylus) | /content-scripts/content.css | |
entrypoints/{name}.content.(css|scss|sass|less|styl|stylus) | /content-scripts/{name}.css | |
entrypoints/{name}.content/index.(css|scss|sass|less|styl|stylus) | /content-scripts/{name}.css |
body {
/* ... */
}
按照 Vite 指南设置你选择的预处理器:https://vitejs.dev/guide/features.html#css-pre-processors
CSS 入口点始终未列出。要将 CSS 添加到内容脚本,请参阅内容脚本文档。
未列出的页面(Unlisted Pages)
Filename | Output Path | |
---|---|---|
entrypoints/{name}.html | /{name}.html | |
entrypoints/{name}/index.html | /{name}.html |
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>标题</title>
<!-- 设置 include/exclude 以从某些构建中移除页面 -->
<meta name="manifest.include" content="['chrome', ...]" />
<meta name="manifest.exclude" content="['chrome', ...]" />
</head>
<body>
<!-- ... -->
</body>
</html>
在运行时,未列出的页面可通过 /{name}.html
访问:
const url = browser.runtime.getURL('/{name}.html');
console.log(url); // "chrome-extension://{id}/{name}.html"
window.open(url); // 在新标签页中打开页面
未列出的脚本(Unlisted Scripts)
Filename | Output Path | |
---|---|---|
entrypoints/{name}.[jt]sx? | /{name}.js | |
entrypoints/{name}/index.[jt]sx? | /{name}.js |
export default defineUnlistedScript(() => {
// 脚本加载时执行
});
export default defineUnlistedScript({
// 设置 include/exclude 以从某些构建中移除脚本
include: undefined | string[],
exclude: undefined | string[],
main() {
// 脚本加载时执行
},
});
在运行时,未列出的脚本可通过 /{name}.js
访问:
const url = browser.runtime.getURL('/{name}.js');
console.log(url); // "chrome-extension://{id}/{name}.js"
你需要负责在需要的地方加载/运行这些脚本。如有必要,请勿忘记将脚本和/或任何相关资源添加到 web_accessible_resources
。
定义未列出的脚本时,请记住 WXT 会在构建过程中在 NodeJS 环境中导入此文件。这意味着你不能在 main
函数之外放置任何运行时代码。
document.querySelectorAll('a').forEach((anchor) => {
// ...
});
export default defineUnlistedScript(() => {
document.querySelectorAll('a').forEach((anchor) => {
// ...
});
});
更多详情请参阅入口点加载器文档。