其他
需要为 Chrome 扩展的…
当用户提到 CRXJS、`@crxjs/vite-plugin`、Chrome 扩展热重载/HMR,或要用任意 Vite 框架搭建、维护、修复 CRXJS 扩展时适用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 35/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 38/100 ×0.15
适用场景
需要为 Chrome 扩展的 popup特定
解决思路
- 使用 `@crxjs/vite-plugin` v2.x(截至 2026 年 3 月最新 v2.4.0),脚手架始终用 `npm create crxjs@latest`,并确认 Vite 版本在 v3 到 v8-beta 兼容范围内;保持更新以跟进 Chrome 变化。
- 新项目:运行 `npm create crxjs@latest`,按交互选择框架来脚手架。
- 已有 Vite 项目:运行 `npm install @crxjs/vite-plugin -D`。
- 在 `vite.config.ts` 中把 CRXJS 作为 Vite 插件加入;React 使用 `@vitejs/plugin-react`(不要用 `plugin-react-swc`)以获得最佳 HMR 兼容性,配置为 `plugins: [react(), crx({ manifest })]`。
- 如果 React 必须用 SWC,则把 JSON manifest 断言为 `ManifestV3Export`:`import { ManifestV3Export } from '@crxjs/vite-plugin'; const manifest = manifestJson as ManifestV3Export;`。
- Vue 配置:`import vue from '@vitejs/plugin-vue'; import { crx } from '@crxjs/vite-plugin'; import manifest from './manifest.json'; export default defineConfig({ plugins: [vue(), crx({ manifest })] });`。
- Svelte 配置:`import { svelte } from '@sveltejs/vite-plugin-svelte'; import { crx } from '@crxjs/vite-plugin'; import manifest from './manifest.json'; export default defineConfig({ plugins: [svelte(), crx({ manifest })] });`。
- Vanilla TypeScript 配置:`import { crx } from '@crxjs/vite-plugin'; import manifest from './manifest.json'; export default defineConfig({ plugins: [crx({ manifest })] });`。
- 用 `defineManifest` 替代静态 JSON:从 `@crxjs/vite-plugin` 导入 `defineManifest`,在 `manifest.ts` 导出 `defineManifest((config) => ({ ... }))`,以获得动态值和 TypeScript 自动补全。
- 在 `defineManifest` 中设置 `manifest_version: 3`、`name`(可用 `config.command === 'serve'` 加 `[DEV]` 前缀)、`version`、`description`、`permissions`(如 `['storage', 'activeTab', 'scripting']`)。
- 在 `defineManifest` 中配置 `action.default_popup`、`action.default_icon`、`background.service_worker` 与 `background.type: 'module'`、`content_scripts` 的 `matches`/`js`/`css`、`options_page`、`side_panel.default_path`、`icons`。
- 在 `vite.config.ts` 中从 `./manifest` 导入 manifest,并传给 `crx({ manifest })`。
- 类型声明:在 `src/vite-env.d.ts` 或 `src/crxjs.d.ts` 添加 `/// <reference types='@crxjs/vite-plugin/client' />`,以启用 `?script` 和 `?script&module` 导入的类型。
- 理解 HMR:Popup、Options page、Side panel 有完整 HMR,基于 WebSocket 且保留状态;manifest content script 有真 HMR,由 CRXJS 注入 loader + HMR client;dynamic content script 通过 `?script` 有真 HMR;Service worker 改动触发完整扩展自动重载;main world scripts 无 HMR,会被 CRXJS loader 跳过。
- 动态内容脚本(编程注入,不在 manifest 中):在 background 中用 `?script` 后缀导入,例如 `import contentScript from './content?script';`,然后在 `chrome.action.onClicked` 中调用 `chrome.scripting.executeScript({ target: { tabId: tab.id! }, files: [contentScript] })`。
- Main world 注入(无 HMR):用 `?script&module` 后缀导入,例如 `import mainWorldScript from './inject?script&module';`,然后调用 `chrome.scripting.executeScript({ target: { tabId }, world: 'MAIN', files: [mainWorldScript] })`。
- 配置 CRXJS 插件选项:`crx({ manifest, browser: 'chrome' | 'firefox', contentScripts: { injectCss: true, hmrTimeout: 5000 } })`。
- 开发流程:运行 `npm run dev` 输出到 `dist/` 并带 HMR;打开 `chrome://extensions`,启用 Developer mode,点击 Load unpacked,选择 `dist/` 目录;编辑代码后 popup/content scripts 通过 HMR 即时更新;Service worker 改动自动重载扩展。
- 首次加载后,后续 `npm run dev` 会话会自动重连;除非 `manifest.json` 变化,否则无需重新加载扩展。
- 生产构建:运行 `npm run build`,输出到 `dist/`;运行 `cd dist && zip -r ../extension.zip .` 打包上传 Chrome Web Store。
- 生产构建时在 Vite 配置中设置 `build: { modulePreload: false }`,避免 CWS 拒绝内联脚本。
- 处理 Tailwind CSS 在 content scripts 中的 HMR 问题:新增 Tailwind 类可能不触发 CSS 更新;重启 dev server;确保 `injectCss: true`;该问题在 v2.4.0 改进但未完全解决。
- 处理 WebSocket 连接错误 `ws://localhost:undefined/`:原因是 dev server 和 HMR 端口不匹配;显式设置相同端口,如 `server: { port: 5173, strictPort: true, hmr: { port: 5173 } }`。
- 处理 `Manifest version 2 is deprecated` 警告:确保 manifest 中设置 `manifest_version: 3`,否则会被解释为 MV2。
- 处理 content scripts 不在 `file://` URL 注入:Chrome 要求用户在 `chrome://extensions` 的扩展设置中启用 `Allow access to file URLs`;CRXJS 无法改变该设置。
- 处理 Chrome 更新后 HMR 停止工作:CRXJS 的 HMR 依赖注入 content script 连接 dev server WebSocket;Chrome 安全更新可能破坏;更新到最新 CRXJS 版本以跟进 Chrome 变化。
- 推荐项目结构:使用 `src/background/index.ts`、`src/content/index.ts` 与 `styles.css`、`src/popup/index.html`/`App.tsx`/`main.tsx`、`src/options/index.html`/`main.tsx`、`src/sidepanel/index.html`/`main.tsx`、`src/shared/messages.ts`/`storage.ts`、`public/icons/`、`manifest.ts` 或 `manifest.json`、`vite.config.ts`、`tsconfig.json`、`package.json`。
- CRXJS 会自动解析 manifest 中引用的 HTML;popup.html 可使用标准 `<script type='module' src='./main.tsx'>` 并正常工作。
- 遇到 CRXJS bug 或异常行为时,在 `github.com/crxjs/chrome-extension-tools/issues` 开 issue。
适用边界 · 注意事项
- 不适用于只需要一般 Chrome 扩展架构(消息传递、CSP、storage、permissions)的场景;应查看 `samber/cc-skills@chrome-extension` 技能。
- 如果你想要完整框架抽象、约定、文件路由、内置 messaging/storage 包装,或需要跨 Chrome/Firefox/Safari,选择 WXT。
- 如果你是 React 优先且想要最高层抽象,选择 Plasmo。