非常好!我们现在将 **TypeScript** 深度集成到基于 `Vue 3 + Vite + Chrome 扩展(Manifest V3)+ Element Plus` 的项目中,确保整个工程具备:
- 类型安全
- `.ts` 文件作为入口支持(如 `background.ts`, `content.ts`)
- Vue 组件中的 `<script setup lang="ts">` 支持
- 对 `chrome.*` API 的类型提示
- 自动化构建与热更新(HMR)
---
## ✅ 第一步:初始化并配置 TypeScript
### 1. 安装 TypeScript
```bash
npm install -D typescript
```
### 2. 创建 `tsconfig.json`
```json
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
"baseUrl": ".",
"allowJs": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"strict": true,
"strictNullChecks": true,
"noImplicitAny": true,
"strictBindCallApply": true,
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true,
"moduleResolution": "node",
"paths": {
"@/*": ["src/*"]
},
"types": [
"chrome" // 启用 chrome API 类型定义
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"vite.config.ts",
"env.d.ts"
],
"references": [
{ "path": "./tsconfig.node.json" }
]
}
```
> 💡 注意:`"types": ["chrome"]` 是关键,它启用 Chrome 扩展 API 的类型提示。
---
### 3. 创建 `tsconfig.node.json`(用于 Vite 配置文件的类型检查)
```json
// tsconfig.node.json
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"strict": true
},
"include": ["vite.config.ts"]
}
```
---
## ✅ 第二步:安装必要的类型声明包
Chrome 的类型不是内置的,需要安装:
```bash
npm install -D @types/chrome
```
> ⚠️ 注意:某些版本可能不稳定。推荐使用社区维护良好的:
>
> ```bash
> npm install -D @types/chrome@ts4.8
> ```
>
> 或者使用 [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/chrome) 的最新版。
如果你发现 `chrome.sidePanel` 报错不存在,可以手动扩展类型:
### 可选:创建 `env.d.ts` 补全缺失 API
```ts
// src/env.d.ts
/// <reference types="chrome" />
declare namespace chrome {
namespace sidePanel {
export function setOptions(options: {
path?: string
enabled?: boolean
}): Promise<void>
export function setOpenOptions(options: { tabId?: number; opened: boolean }): Promise<void>
export function getOptions(options: { tabId?: number }): Promise<{ path?: string; enabled?: boolean }>
}
}
```
这样 TS 就不会报错 `Property 'sidePanel' does not exist on type 'typeof chrome'`。
---
## ✅ 第三步:启用 `.vue` 文件中的 TypeScript 支持
确保你已经安装了 Vue 3 和 Volar 工具(VSCode 用户):
```bash
npm install -D vue@^3.4
```
并在 `.vue` 文件中使用:
```vue
<!-- src/components/Highlighter.vue -->
<script setup lang="ts">
defineProps<{
text: string
keyword: string
}>()
</script>
<template>
<span v-html="text.replace(new RegExp(keyword, 'gi'), '<mark>$&</mark>')" />
</template>
```
✅ VSCode + Volar 插件会提供完整的类型推导和语法高亮。
---
## ✅ 第四步:为各模块添加类型安全代码示例
### 示例 1:`src/background/background.ts`(带类型)
```ts
// src/background/background.ts
import type { Runtime } from 'webextension-polyfill'
// 监听安装事件
chrome.runtime.onInstalled.addListener(async (details: Runtime.OnInstalledDetailsType) => {
console.log('[Background] Extension installed:', details)
// 设置侧边栏默认页面
await chrome.sidePanel.setOptions({
path: 'sidepanel.html',
enabled: true
})
})
// 控制侧边栏在合适页面启用
chrome.tabs.onUpdated.addListener(async (tabId: number, changeInfo, tab) => {
if (changeInfo.status !== 'complete') return
if (!tab.url) return
const url = new URL(tab.url)
if (['http:', 'https:'].includes(url.protocol)) {
await chrome.sidePanel.setOptions({ tabId, enabled: true })
}
})
```
> ✅ 自动获得 `chrome.*` 的类型提示,包括参数、返回值、错误处理等。
---
### 示例 2:`src/content/content.ts`(发送消息 + 类型)
```ts
// src/content/content.ts
interface SelectionMessage {
type: 'TEXT_SELECTED'
text: string
url: string
title: string
timestamp: number
}
document.addEventListener('selectionchange', () => {
const selection = window.getSelection()?.toString().trim()
if (!selection) return
const msg: SelectionMessage = {
type: 'TEXT_SELECTED',
text: selection,
url: location.href,
title: document.title,
timestamp: Date.now()
}
// 类型安全地发送消息
chrome.runtime.sendMessage(msg)
// 存储历史记录
chrome.storage.local.get<{ history?: string[] }>(['history'], (result) => {
const list = result.history || []
list.unshift(`${selection.slice(0, 50)}...`)
if (list.length > 10) list.pop()
chrome.storage.local.set({ history: list })
})
})
```
---
### 示例 3:`src/utils/message.ts`(封装通信工具)
```ts
// src/utils/message.ts
export type MessageType = 'TEXT_SELECTED' | 'ANALYZE_REQUEST' | 'SHOW_PANEL'
export interface BaseMessage {
type: MessageType
}
export interface TextSelectedMessage extends BaseMessage {
type: 'TEXT_SELECTED'
text: string
url: string
title: string
}
export function sendMessage(msg: TextSelectedMessage): Promise<void> {
return new Promise((resolve, reject) => {
chrome.runtime.sendMessage(msg, () => {
if (chrome.runtime.lastError) {
reject(chrome.runtime.lastError)
} else {
resolve()
}
})
})
}
```
然后在组件中导入使用:
```ts
import { sendMessage, TextSelectedMessage } from '@/utils/message'
```
---
## ✅ 第五步:确保 `vite.config.ts` 支持 TypeScript
```ts
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { crx } from '@crxjs/vite-plugin'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import manifest from './public/manifest.json'
export default defineConfig({
plugins: [
vue(),
crx({ manifest }),
AutoImport({
resolvers: [ElementPlusResolver()],
imports: ['vue', 'vue-router'],
dts: 'src/auto-imports.d.ts'
}),
Components({
resolvers: [ElementPlusResolver()],
dts: 'src/components.d.ts'
})
],
resolve: {
alias: {
'@': '/src'
}
}
})
```
> ✅ 此文件本身就是 `.ts`,Vite 原生支持。
---
## ✅ 第六步:验证开发体验
启动项目:
```bash
npm run dev
```
你应该能看到:
- 修改 `.ts` 文件 → 实时 HMR 更新
- 在 `chrome.*` 调用上有完整类型提示(如 `chrome.storage.local.get`)
- `.vue` 文件中 `<script setup lang="ts">` 类型检查正常
- 构建时报错即停,避免运行时错误
---
## ✅ 最终项目结构(含 TypeScript)
```
my-chrome-ext/
├── src/
│ ├── components/
│ │ └── Highlighter.vue
│ ├── pages/
│ │ ├── SidePanelPage.vue
│ │ └── PopupPage.vue
│ ├── content/
│ │ └── content.ts # ✅ 类型安全的内容脚本
│ ├── background/
│ │ └── background.ts # ✅ Service Worker with TS
│ ├── utils/
│ │ └── message.ts # ✅ 自定义类型
│ ├── types/
│ │ └── index.d.ts
│ ├── env.d.ts # ✅ 补充 chrome API 类型
│ └── main.ts # ✅ 入口 TS
├── public/
│ ├── manifest.json
│ └── sidepanel.html
├── vite.config.ts
├── tsconfig.json # ✅ 主要配置
├── tsconfig.node.json
└── package.json
```
---
## ✅ 总结:TypeScript 带来的优势
| 优点 | 说明 |
|------|------|
| 🛡️ 类型安全 | 减少 `undefined is not a function` 错误 |
| 💡 智能提示 | VSCode 提供 `chrome.tabs.create` 参数提示 |
| 🔍 易于重构 | 重命名变量、接口变更更安全 |
| 🧩 团队协作 | 接口契约清晰,新人上手快 |
| 🚫 编译期报错 | 提前发现问题,而非发布后崩溃 |
---