首页 / 浏览器扩展开发入门教程 / 用 Vite 搭建开发环境

浏览器扩展开发入门教程

用 Vite 搭建开发环境

本教程共 56 篇 · 第 54 篇 · 更新于 2026-08-13 · 约 6 分钟阅读

Vite@crxjs/vite-plugin构建工具多入口dev模式MV3脚手架

本节目标:学完你能用 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)就是补上这层差异的插件。它做三件关键事:

  1. 读你的 manifest 配置,自动生成最终 manifest.json
  2. 把清单里声明的每个入口(popup、background、content_scripts)单独打包。
  3. 在 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/firefoxrollupOptions.input 里列的是「HTML 入口」,也就是那些独立的页面。

Note

后台服务工作者和内容脚本不用写进 input。它们由 manifest 里的 background.service_workercontent_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: 3background.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 builddist/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 而不是 srcsrc 里是开发态源码,浏览器读不了 .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,让代码更现代、更不易出错。