用 Vite 搭建开发环境
本教程共 56 篇 · 第 54 篇 · 更新于 2026-08-13 · 约 6 分钟阅读
本节目标:学完你能用 Vite 加 @crxjs/vite-plugin 起一个支持多入口、带构建产物的 MV3 扩展开发环境。
前面五十多章,我们写的扩展大多是一两个 manifest.json 加几个裸 js 文件。那种写法简单直接,适合学概念。可一旦你想用 Vue、想用 TypeScript、想有热重载,手写就力不从心了。
这一章不写完整项目,只讲工具链怎么搭。你理解了配置,后面接任何框架都顺。
54-1 为什么普通目录不够用
裸目录的痛点是:浏览器只认最终的 HTML、JS、CSS 文件。你用 .ts 写的代码它看不懂;你把组件拆成几十个 .vue 文件,它也不会自动拼起来。
构建工具干的事,就是把你写的「开发态代码」转成「浏览器能跑的产物」。
Note构建工具不替你写扩展逻辑,它只负责打包、转译、注入清单。扩展能做什么,仍然由 MV3 的
chrome.*API 决定。
Vite 这类工具还有一个隐藏价值:它把「源码」和「产物」彻底分开。你日常只碰 src,构建时才生成 dist。这种分离让你能放心用高级语法,不用担心浏览器认不认,构建工具会替你翻译成兼容形式。
Vite 是当下最顺手的选择。它启动快、配置轻,关键是它对「多入口」这种需求天生友好——而扩展正好就是多入口:弹出页一个页、选项一个页、后台一个脚本、内容脚本又一个入口。
54-2 核心插件 @crxjs/vite-plugin
光有 Vite 还不够。Vite 默认按「网站」的思路打包,而扩展有一份特殊的 manifest.json,还有后台服务工作者、内容脚本这些网站没有的上下文。
@crxjs/vite-plugin(社区常叫 crxjs)就是补上这层差异的插件。它做三件关键事:
- 读你的
manifest配置,自动生成最终manifest.json。 - 把清单里声明的每个入口(popup、background、content_scripts)单独打包。
- 在 dev 模式下打通热重载,让改代码后扩展自动更新。
Tip安装时认准
@crxjs/vite-plugin,版本选 2.x 以上,对 MV3 支持才完整。别装成旧版的非 MV3 插件。
初始化一个项目,依赖就这么几行:
{
"devDependencies": {
"vite": "^7.0.0",
"@crxjs/vite-plugin": "^2.3.0",
"typescript": "^5.9.0"
}
}
装完在 package.json 里加两个脚本就够了:
{
"scripts": {
"dev": "vite",
"build": "vite build"
}
}
54-3 一份最小 vite.config
Vite 的配置写在 vite.config.ts 里。最小可跑的扩展配置长这样:
import { defineConfig } from "vite"
import { crx } from "@crxjs/vite-plugin"
import manifest from "./manifest.config"
export default defineConfig({
plugins: [crx({ manifest })],
build: {
outDir: "dist/chrome",
rollupOptions: {
input: {
popup: "src/ui/popup/index.html",
options: "src/ui/options/index.html",
},
},
},
})
注意三点。plugins 里挂上 crx,并把清单配置传进去。outDir 指定产物落哪个目录,这里用 dist/chrome,方便以后再加 dist/firefox。rollupOptions.input 里列的是「HTML 入口」,也就是那些独立的页面。
Note后台服务工作者和内容脚本不用写进
input。它们由 manifest 里的background.service_worker和content_scripts[].js声明,crxjs 会自己找、自己打包。
54-4 清单用 TS 写更省心
前面章节的 manifest.json 是纯 JSON。到了构建工具里,我们把它升级成 manifest.config.ts,好处是能复用 package.json 里的版本号,还能有类型校验。
import type { ManifestV3Export } from "@crxjs/vite-plugin"
const manifest: ManifestV3Export = {
manifest_version: 3,
name: "我的扩展",
version: "0.0.1",
action: {
default_popup: "src/ui/popup/index.html",
},
background: {
service_worker: "src/background/index.ts",
type: "module",
},
content_scripts: [
{
js: ["src/content-script/index.ts"],
matches: ["<all_urls>"],
run_at: "document_end",
},
],
}
export default manifest
这里每一处都是 MV3 写法:manifest_version: 3、background.service_worker、内容脚本走 content_scripts 数组。crxjs 在构建时会把 src/... 这些开发路径,替换成打包后的真实产物路径,你不用手动维护。
54-5 多入口到底指什么
「多入口」是扩展构建和单页网站最大的不同。一个网站通常只有一个 HTML 进去;扩展却是好几个互不相关的入口拼在一起。
典型的入口清单:
- 弹出页:
src/ui/popup/index.html - 选项页:
src/ui/options/index.html - 侧边栏:
src/ui/side-panel/index.html - 后台服务工作者:
src/background/index.ts(不是 HTML) - 内容脚本:
src/content-script/index.ts(也不是 HTML)
HTML 类入口要写进 rollupOptions.input;脚本类入口靠 manifest 声明,插件自动处理。两者分工明确,别重复配置。
Tip目录怎么排没有强制规范,但约定俗成就好维护。常见做法是
src/ui/下放所有页面,src/background/、src/content-script/各管一个上下文。
54-6 构建产物长什么样
跑一次 npm run build,dist/chrome 里会出现一套浏览器能直接加载的目录。结构和你裸写扩展时几乎一致:
dist/chrome/
├── manifest.json
├── assets/
│ ├── popup-[hash].js
│ ├── popup-[hash].css
│ ├── background-[hash].js
│ └── content-script-[hash].js
├── ui/
│ ├── popup/index.html
│ └── options/index.html
└── ...
manifest.json 里的路径已经被改成 assets/... 这种打包后的真实地址。你拿 dist/chrome 整个文件夹去 chrome://extensions 点「加载已解压的扩展程序」就能跑。
Note文件名带
[hash]是 Vite 的内容哈希,用于缓存控制。开发时一般不会带,只有生产构建才有。
54-7 dev 模式怎么用
开发阶段别用 build,用 dev。它会起一个本地服务,配合 crxjs 做热重载。
npm run dev
启动后,去 chrome://extensions 打开开发者模式,点「加载已解压的扩展程序」,选 dist/chrome 目录(dev 模式下产物也会实时写在这里)。之后你改 src 里的源码,扩展多半会自动刷新,不用手动重载。
Tip第一次加载还是手点一次。热重载负责「改完自动更新」,但「首次加载」这步浏览器不会替你做。
54-8 加载前的环境准备
开始之前,确认两件事。一是本地装了 Node.js,版本选长期支持版(LTS)即可,Vite 7 需要 Node 20 以上。二是浏览器用较新的 Chromium 内核版本,老版本对 MV3 服务工作者支持不全。
node -v
能打印出 v20.x 或更高就合格。版本太旧,Vite 会直接启动报错,而不是悄悄出问题,这点反而好排查。
Tip不确定装没装 Node,先跑上面这条命令。没输出或报「命令找不到」,就是没装,去 Node 官网下 LTS 版装好再回来。
项目根目录还要有一个 index.html 吗?不需要。网站项目才需要根 index.html 当主入口;扩展的每个页面都自带 index.html(在 src/ui/*/ 下),根目录留空反而干净。
54-9 一个容易踩的坑
dev 模式下如果浏览器报「找不到文件」,先确认你加载的是 dist/chrome 而不是 src。src 里是开发态源码,浏览器读不了 .ts、读不了 .vue。
另一个坑:清单里写的是 src/ui/popup/index.html,但加载目录得是 dist/chrome。这两套路径别搞混,构建工具就是负责在它们之间做翻译的。
Note如果你之后要同时发 Chrome 和 Firefox,可以再加
vite.firefox.config.ts,共用同一份基础配置,只换浏览器参数。跨浏览器细节前面模块十二已经讲过。
54-10 小结
这一章搭起了一个能跑的 Vite 扩展骨架:用 @crxjs/vite-plugin 接管 manifest 和多入口,用 vite.config.ts 管打包,用 manifest.config.ts 管清单声明。
你还没写业务逻辑,但环境已经就位。下一章我们往里面塞框架和 TypeScript,让代码更现代、更不易出错。