跟 spec-kit 学如何写一个 Chrome 自动复制插件

3 阅读24分钟

技术研究文档

创建日期: 2026-01-14
功能: 智能文本自动复制插件
技术栈: Vue.js 3 + Vite + TypeScript


研究概述

本文档记录了在实施计划前进行的技术研究和决策过程,解决了技术选型、最佳实践和潜在风险。


1. Vue.js 在 Chrome 插件中的应用

决策

在 Chrome 插件的 Content Script 中使用 Vue.js 3 实现 UI 组件和状态管理。

研究过程

问题: Vue.js 是否适合用于 Chrome 插件开发?会不会增加不必要的复杂度?

调研结果:

  1. 体积优势: Vue 3 运行时版本(不含编译器)压缩后约 50KB,对于插件来说可接受
  2. 性能优势: Composition API 提供了更好的 Tree-shaking 支持,可以减少最终包体积
  3. 开发效率: 响应式系统和组件化大幅简化状态管理和 UI 开发
  4. 成熟案例: 许多成功的 Chrome 插件使用 Vue.js(如 Grammarly、ColorZilla)

具体应用:

  • Content Script: 使用 Vue 3 运行时创建 Toast 通知组件
  • 状态管理: 使用 Composition API 的 refcomputed 管理选择状态和定时器状态
  • 无需 Vuex/Pinia: 功能简单,Composition API 足够

理由

Vue.js 提供的开发效率提升和代码可维护性远大于约 50KB 的体积增加。插件的核心逻辑(选择监听、文本处理)仍使用纯 TypeScript,Vue 仅用于 UI 层,符合模块化设计原则。

替代方案

  • 原生 JavaScript + Web Components: 需要手写响应式系统,开发效率低
  • React: 体积更大(约 130KB),且对 TypeScript 支持不如 Vue 直接
  • Svelte: 体积最小但生态不如 Vue 成熟,对 Chrome 插件支持较少

2. Vite 构建 Chrome 插件的配置方案

决策

使用 Vite 作为构建工具,配置特定的插件构建模式。

研究过程

问题: Vite 默认针对 Web 应用,如何配置以支持 Chrome 插件?

关键配置点:

  1. 禁用代码分割: Chrome 插件要求单文件入口

    build: {
      rollupOptions: {
        output: {
          manualChunks: undefined // 禁用分块
        }
      }
    }
    
  2. Content Script 入口: 配置独立的入口文件

    build: {
      rollupOptions: {
        input: {
          'content-script': resolve(__dirname, 'src/content-script.ts')
        }
      }
    }
    
  3. 构建目标: 设置为现代浏览器

    build: {
      target: 'chrome88', // 匹配 manifest 的最低版本
      cssCodeSplit: false
    }
    
  4. Manifest V3 生成: 使用插件自动生成或手动维护

    • 手动维护 manifest.json(推荐,更灵活)
    • 使用 @crxjs/vite-plugin(自动化但配置复杂)

最佳实践:

  • 开发模式: 使用 Vite dev server + Chrome 插件热重载
  • 生产构建: 单入口文件 + 最小化体积
  • Source Map: 仅在开发模式启用

理由

Vite 的开发体验显著优于 Webpack,配置更简洁。虽然需要特殊配置,但社区已有成熟方案(CRXJS、vite-plugin-web-extension)。

替代方案

  • Webpack: 配置复杂,构建速度慢,但对插件支持最成熟
  • Rollup: 轻量但需要手动配置很多细节
  • Parcel: 零配置但对插件支持不足

3. Chrome Clipboard API 的使用方式

决策

使用 navigator.clipboard.writeText() API,配合 Manifest V3 的 clipboardWrite 权限。

研究过程

问题: Content Script 中如何安全地访问剪贴板?

Clipboard API 演进:

  1. Legacy API (document.execCommand('copy')):

    • 已废弃,但兼容性最好
    • 需要创建临时 textarea 元素
    • 不支持异步操作
  2. Modern API (navigator.clipboard):

    • 异步 API,返回 Promise
    • 需要 HTTPS 或 localhost(插件自动满足)
    • Chrome 88+ 支持

权限要求:

// manifest.json
{
  "permissions": ["clipboardWrite"],
  "host_permissions": ["<all_urls>"]
}

Content Script 中的使用:

// 无需用户手势即可使用(有 clipboardWrite 权限)
async function copyToClipboard(text: string): Promise<boolean> {
  try {
    await navigator.clipboard.writeText(text);
    return true;
  } catch (error) {
    console.error('复制失败:', error);
    // 降级到 execCommand
    return fallbackCopy(text);
  }
}

// 降级方案
function fallbackCopy(text: string): boolean {
  const textarea = document.createElement('textarea');
  textarea.value = text;
  textarea.style.position = 'fixed';
  textarea.style.opacity = '0';
  document.body.appendChild(textarea);
  textarea.select();
  const success = document.execCommand('copy');
  document.body.removeChild(textarea);
  return success;
}

理由

Modern Clipboard API 是官方推荐的方式,代码更简洁。提供 execCommand 降级方案确保在极端情况下也能工作。

替代方案

  • 仅使用 execCommand: 可靠但已废弃
  • 使用第三方库(如 clipboard.js): 违反最小依赖原则

4. 文本清理的正则表达式方案

决策

使用原生 JavaScript 字符串方法结合正则表达式实现文本清理。

研究过程

需求:

  1. 去除首尾的空格、制表符、换行符
  2. 去除首尾的单引号(')和双引号("
  3. 处理嵌套引号(如 "'text'"text
  4. 保留文本中间的空格和引号

实现方案:

export function cleanText(text: string): string {
  let cleaned = text;
  
  // 1. 去除首尾空白字符
  cleaned = trimWhitespace(cleaned);
  
  // 2. 递归去除首尾引号(处理嵌套)
  cleaned = removeQuotes(cleaned);
  
  // 3. 再次去除空白(引号内可能有空格)
  cleaned = trimWhitespace(cleaned);
  
  return cleaned;
}

function trimWhitespace(text: string): string {
  // 使用正则去除所有类型的空白字符
  return text.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
}

function removeQuotes(text: string): string {
  // 循环去除首尾引号,直到没有引号或文本为空
  let result = text;
  let prevLength = -1;
  
  while (result.length > 0 && result.length !== prevLength) {
    prevLength = result.length;
    // 去除首尾的单引号或双引号
    result = result.replace(/^["']|["']$/g, '');
  }
  
  return result;
}

测试用例:

cleanText('  hello  ')           // → 'hello'
cleanText('"hello"')              // → 'hello'
cleanText("'hello'")              // → 'hello'
cleanText('"\'hello\'"')          // → 'hello'
cleanText('  "  hello  "  ')      // → 'hello'
cleanText('hello world')          // → 'hello world' (保留中间空格)
cleanText('say "hello" world')    // → 'say "hello" world' (保留中间引号)

理由

原生方法性能最优,无需引入第三方库。循环去除引号确保处理嵌套情况。正则表达式简洁高效。

替代方案

  • 使用 trim() + 字符串操作: 代码冗长且难以处理嵌套
  • 使用解析库: 过度设计且违反最小依赖原则

5. Vue 组件在 Content Script 中的挂载方式

决策

动态创建 Shadow DOM 容器,在其中挂载 Vue 应用,避免样式污染。

研究过程

问题: 如何在网页中注入 Vue 组件而不与页面样式冲突?

挂载方案对比:

方案优点缺点
直接挂载到 body简单容易被页面样式覆盖
iframe完全隔离定位困难,性能差
Shadow DOM样式隔离,性能好需要手动处理样式继承

Shadow DOM 实现:

// src/composables/useFeedback.ts
import { createApp } from 'vue';
import Toast from '@/components/Toast.vue';

export function useFeedback() {
  let shadowRoot: ShadowRoot | null = null;
  
  function createShadowContainer() {
    // 创建容器元素
    const container = document.createElement('div');
    container.id = 'auto-copy-feedback-root';
    
    // 创建 Shadow DOM
    shadowRoot = container.attachShadow({ mode: 'open' });
    
    // 创建挂载点
    const mountPoint = document.createElement('div');
    shadowRoot.appendChild(mountPoint);
    
    // 注入样式(需要在 Shadow DOM 中重新注入)
    const style = document.createElement('style');
    style.textContent = getComponentStyles(); // 提取组件样式
    shadowRoot.appendChild(style);
    
    // 挂载到页面
    document.body.appendChild(container);
    
    return mountPoint;
  }
  
  function show(message: string) {
    const mountPoint = shadowRoot
      ? shadowRoot.querySelector('div')
      : createShadowContainer();
    
    const app = createApp(Toast, { message });
    app.mount(mountPoint!);
    
    // 1.5 秒后卸载
    setTimeout(() => {
      app.unmount();
    }, 1500);
  }
  
  return { show };
}

样式隔离策略:

  1. 使用 Shadow DOM 的 mode: 'open'
  2. 在 Shadow DOM 内注入组件样式
  3. 使用极高的 z-index(9999999
  4. 避免使用全局选择器

理由

Shadow DOM 提供了完美的样式隔离,同时保持良好的性能。Vue 3 对 Shadow DOM 支持良好。

替代方案

  • CSS Modules + BEM: 仍可能被页面 !important 覆盖
  • CSS-in-JS: 增加依赖且性能较差

6. 定时器精确计时方案

决策

使用 performance.now() 而非 Date.now() 进行时间测量,确保精确到毫秒。

研究过程

问题: 如何确保 2 秒定时器的精确性(误差 ±50ms)?

时间 API 对比:

API精度特点
Date.now()毫秒受系统时钟影响,可能跳变
performance.now()微秒单调递增,不受系统时钟影响
setTimeout毫秒受浏览器节流影响

实现方案:

export function useTimerManager() {
  let timerId: number | null = null;
  let startTime: number = 0;
  const DURATION = 2000; // 2 秒
  
  function startTimer(callback: () => void) {
    startTime = performance.now();
    
    timerId = window.setTimeout(() => {
      const elapsed = performance.now() - startTime;
      console.log(`定时器触发,实际耗时: ${elapsed}ms`);
      
      // 只有在误差范围内才执行
      if (Math.abs(elapsed - DURATION) < 100) {
        callback();
      }
      
      timerId = null;
    }, DURATION);
  }
  
  function resetTimer(callback: () => void) {
    cancelTimer();
    startTimer(callback);
  }
  
  function cancelTimer() {
    if (timerId !== null) {
      clearTimeout(timerId);
      timerId = null;
    }
  }
  
  return { startTimer, resetTimer, cancelTimer };
}

应对浏览器节流:

  • 使用 requestAnimationFrame 辅助检测(页面不可见时可能被节流)
  • 在回调中验证实际耗时
  • 文档中说明已知限制(页面休眠时可能不准确)

理由

performance.now() 是高精度计时的标准方式,不受系统时钟影响。结合误差检测确保准确性。

替代方案

  • Date.now(): 精度较低且可能受系统时钟调整影响
  • Web Workers: 过度设计且增加复杂度

7. TypeScript 严格模式配置

决策

启用 TypeScript 的 strict 模式,确保类型安全。

配置项说明

{
  "compilerOptions": {
    "strict": true,              // 启用所有严格检查
    "noImplicitAny": true,       // 禁止隐式 any
    "strictNullChecks": true,    // 严格的 null 检查
    "strictFunctionTypes": true, // 严格的函数类型检查
    "noUnusedLocals": true,      // 未使用的局部变量报错
    "noUnusedParameters": true,  // 未使用的参数报错
  }
}

Chrome API 类型支持:

npm install --save-dev @types/chrome

自定义类型定义:

// src/types/index.ts

export interface SelectionState {
  text: string;
  range: Range | null;
  timestamp: number;
  isStable: boolean;
}

export interface TimerState {
  timerId: number | null;
  startTime: number;
  duration: number;
  isActive: boolean;
}

export interface FeedbackOptions {
  message: string;
  duration?: number;
  position?: { x: number; y: number };
}

理由

严格模式可以在编译时发现更多潜在错误,提升代码质量。对于小型项目,严格模式的配置成本可接受。


8. 性能优化策略

决策

采用防抖(debounce)优化选择事件监听,避免频繁触发。

研究过程

问题: 用户快速拖拽选择时,selectionchange 事件会频繁触发,影响性能。

防抖实现:

function debounce<T extends (...args: any[]) => void>(
  fn: T,
  delay: number
): (...args: Parameters<T>) => void {
  let timerId: number | null = null;
  
  return function (...args: Parameters<T>) {
    if (timerId !== null) {
      clearTimeout(timerId);
    }
    
    timerId = window.setTimeout(() => {
      fn(...args);
      timerId = null;
    }, delay);
  };
}

// 使用
const debouncedHandler = debounce((selection: SelectionState) => {
  // 处理选择变更
}, 100); // 100ms 防抖

document.addEventListener('selectionchange', () => {
  const selection = window.getSelection();
  if (selection && selection.toString()) {
    debouncedHandler({
      text: selection.toString(),
      range: selection.getRangeAt(0),
      timestamp: performance.now(),
      isStable: false,
    });
  }
});

其他优化:

  1. 事件委托: 只在 document 上监听一次
  2. 懒加载: Toast 组件按需创建和销毁
  3. 内存管理: 及时清理定时器和事件监听器

理由

防抖可以显著减少不必要的计算,同时不影响用户体验。100ms 的延迟用户感知不到。


9. 测试策略最佳实践

决策

采用 Vitest + @vue/test-utils + Playwright 三层测试策略。

测试层次

1. 单元测试(Vitest):

  • 测试纯函数(textProcessor)
  • 测试 Composables(useSelectionMonitor、useTimerManager)
  • 测试 Vue 组件(Toast)

2. 集成测试(Vitest + Happy-DOM):

  • 测试模块间交互
  • 模拟浏览器环境

3. E2E 测试(Playwright):

  • 测试完整用户流程
  • 在真实 Chrome 环境中测试

Mock 策略:

// tests/utils/mocks.ts

// Mock Clipboard API
export function mockClipboard() {
  Object.assign(navigator, {
    clipboard: {
      writeText: vi.fn().mockResolvedValue(undefined),
    },
  });
}

// Mock Selection API
export function mockSelection(text: string) {
  const selection = {
    toString: () => text,
    getRangeAt: () => ({
      startContainer: document.body,
      endContainer: document.body,
    }),
  };
  
  vi.spyOn(window, 'getSelection').mockReturnValue(selection as any);
}

// Mock Performance API
export function mockPerformance() {
  let now = 0;
  vi.spyOn(performance, 'now').mockImplementation(() => {
    return now;
  });
  return {
    advance: (ms: number) => { now += ms; },
  };
}

理由

分层测试确保不同粒度的质量保障。Vitest 与 Vite 深度集成,速度快。Playwright 提供真实浏览器测试。


10. 发布流程与 Chrome Web Store 要求

决策

使用手动发布流程,遵循 Chrome Web Store 的审核要求。

Chrome Web Store 要求

1. Manifest V3 必须项:

{
  "manifest_version": 3,
  "name": "Auto Copy - 智能文本自动复制",
  "version": "1.0.0",
  "description": "选中文本 2 秒后自动复制,智能清理空格和引号",
  "permissions": ["clipboardWrite"],
  "host_permissions": ["<all_urls>"],
  "content_scripts": [{
    "matches": ["<all_urls>"],
    "js": ["content-script.js"]
  }],
  "icons": {
    "16": "icons/icon-16.png",
    "48": "icons/icon-48.png",
    "128": "icons/icon-128.png"
  }
}

2. 图标要求:

  • 16x16、48x48、128x128 像素
  • PNG 格式,透明背景
  • 简洁清晰的设计

3. 隐私政策:

  • 如果使用用户数据,必须提供隐私政策链接
  • 本插件无需隐私政策(不收集数据)

4. 截图要求:

  • 至少 1 张,最多 5 张
  • 尺寸 1280x800 或 640x400
  • 展示插件功能

5. 审核周期:

  • 首次提交: 通常 3-5 个工作日
  • 更新提交: 通常 1-2 个工作日

发布流程

# 1. 构建生产版本
npm run build

# 2. 检查构建产物
ls -lh dist/

# 3. 在 Chrome 中本地测试
# chrome://extensions/ -> 加载已解压的扩展程序 -> 选择 dist 目录

# 4. 打包为 zip
cd dist && zip -r ../chrome-auto-copy-v1.0.0.zip . && cd ..

# 5. 上传到 Chrome Web Store
# https://chrome.google.com/webstore/devconsole/

理由

手动流程更可控,避免自动化工具的潜在问题。遵循官方要求确保审核通过。


总结

关键技术决策回顾

决策点选择核心理由
前端框架Vue.js 3开发效率高,体积可控,Composition API 适合模块化
构建工具Vite开发体验好,构建速度快,TypeScript 原生支持
剪贴板 APInavigator.clipboard现代 API,异步支持,提供降级方案
文本清理原生正则性能最优,无需依赖
样式隔离Shadow DOM完美隔离,性能好
计时方案performance.now()高精度,不受系统时钟影响
类型系统TypeScript strict提前发现错误,提升质量
性能优化防抖 + 懒加载减少不必要计算,降低内存占用
测试策略Vitest + Playwright快速 + 真实浏览器测试

风险缓解

所有识别的风险均已制定缓解措施:

  • CSP 阻止 → 文档说明 + 用户反馈
  • Vue 冲突 → 独立作用域 + Shadow DOM
  • 体积过大 → Tree-shaking + 运行时版本
  • 兼容性 → 明确版本要求 + 降级方案

后续行动

本研究文档的所有决策已整合到实施计划中。可以开始 Phase 1(项目初始化)的开发工作。


本研究文档遵循项目宪章的最小依赖和模块化设计原则。

快速入门指南

功能: 智能文本自动复制插件
技术栈: Vue.js 3 + Vite + TypeScript
目标: 帮助开发者快速上手项目开发


📋 前置要求

必需工具

  • Node.js: >= 18.0.0
  • npm: >= 9.0.0(或 pnpm >= 8.0.0)
  • Chrome: >= 88(用于测试)
  • Git: >= 2.30.0
  • 代码编辑器: VS Code(推荐)+ Volar 插件

推荐 VS Code 插件

{
  "recommendations": [
    "Vue.volar",
    "Vue.vscode-typescript-vue-plugin",
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode"
  ]
}

🚀 快速开始(5 分钟)

1. 克隆项目

git clone <repository-url>
cd chrome-auto-copy

2. 安装依赖

npm install

3. 启动开发服务器

npm run dev

4. 在 Chrome 中加载插件

  1. 打开 Chrome 浏览器
  2. 访问 chrome://extensions/
  3. 开启右上角"开发者模式"
  4. 点击"加载已解压的扩展程序"
  5. 选择项目的 dist 目录

5. 测试插件

  1. 打开任意网页
  2. 选中一段文本
  3. 保持选择 2 秒
  4. 看到"已复制"提示即成功

📁 项目结构

chrome-auto-copy/
├── public/                      # 静态资源
│   └── icons/                   # 插件图标
│       ├── icon-16.png
│       ├── icon-48.png
│       └── icon-128.png
├── src/
│   ├── components/              # Vue 组件
│   │   └── Toast.vue            # 反馈提示组件
│   ├── composables/             # Vue Composables(核心逻辑)
│   │   ├── useSelectionMonitor.ts   # 选择监听
│   │   ├── useTimerManager.ts       # 定时器管理
│   │   ├── useClipboard.ts          # 剪贴板操作
│   │   └── useFeedback.ts           # 反馈 UI 管理
│   ├── utils/                   # 工具函数
│   │   └── textProcessor.ts     # 文本处理
│   ├── types/                   # TypeScript 类型定义
│   │   └── index.ts
│   ├── content-script.ts        # Content Script 入口
│   └── main.ts                  # 应用主入口
├── tests/                       # 测试文件
│   ├── unit/                    # 单元测试
│   └── integration/             # 集成测试
├── specs/                       # 功能规范文档
│   └── 001-chrome-auto-copy/
│       ├── spec.md              # 功能规范
│       ├── plan.md              # 实施计划
│       ├── research.md          # 技术研究
│       ├── data-model.md        # 数据模型
│       └── contracts/           # API 合约
├── manifest.json                # Chrome 插件配置
├── vite.config.ts               # Vite 配置
├── tsconfig.json                # TypeScript 配置
├── .eslintrc.js                 # ESLint 配置
├── .prettierrc.js               # Prettier 配置
├── vitest.config.ts             # Vitest 配置
├── package.json
└── README.md

🔧 开发命令

常用命令

# 开发模式(热重载)
npm run dev

# 生产构建
npm run build

# 代码检查
npm run lint

# 自动修复代码格式
npm run lint:fix

# 代码格式化
npm run format

# 运行单元测试
npm run test

# 运行测试(监听模式)
npm run test:watch

# 查看测试覆盖率
npm run test:coverage

# 类型检查
npm run type-check

一键完整检查

# 运行所有检查(lint + 格式 + 类型 + 测试)
npm run check-all

🧩 核心模块说明

1. SelectionMonitor(选择监听)

文件: src/composables/useSelectionMonitor.ts
功能: 监听网页中的文本选择事件

核心 API:

const { currentSelection, startMonitoring, onSelectionChange } = useSelectionMonitor();

// 开始监听
startMonitoring();

// 注册回调
onSelectionChange((state) => {
  console.log('选中的文本:', state.text);
});

2. TimerManager(定时器管理)

文件: src/composables/useTimerManager.ts
功能: 管理 2 秒等待定时器

核心 API:

const { startTimer, resetTimer, cancelTimer } = useTimerManager();

// 启动 2 秒定时器
startTimer(2000, () => {
  console.log('2 秒到了,执行操作');
});

// 重置定时器
resetTimer(() => {
  console.log('重新计时 2 秒');
});

3. TextProcessor(文本处理)

文件: src/utils/textProcessor.ts
功能: 清理文本(去除首尾空格和引号)

核心 API:

import { cleanText, isEmpty } from '@/utils/textProcessor';

// 清理文本
const cleaned = cleanText('  "Hello World"  ');
console.log(cleaned); // 'Hello World'

// 检查是否为空
if (isEmpty(text)) {
  console.log('文本为空');
}

4. ClipboardManager(剪贴板操作)

文件: src/composables/useClipboard.ts
功能: 复制文本到剪贴板

核心 API:

const { copy, isSupported } = useClipboard();

// 复制文本
const success = await copy('Hello World');
if (success) {
  console.log('复制成功');
}

5. FeedbackUI(用户反馈)

文件: src/composables/useFeedback.ts + src/components/Toast.vue
功能: 显示"已复制"等反馈提示

核心 API:

const { show } = useFeedback();

// 显示成功提示
show({
  message: '已复制',
  type: 'success',
  duration: 1500,
});

📝 开发工作流

新功能开发流程

  1. 创建功能分支

    git checkout -b feature/your-feature-name
    
  2. 编写代码

    • 在对应模块目录添加/修改代码
    • 遵循 TypeScript 严格模式
    • 使用 Vue 3 Composition API
  3. 编写测试

    # 在 tests/unit/ 目录创建对应测试文件
    # 确保测试覆盖率 > 80%
    npm run test
    
  4. 代码检查

    npm run lint
    npm run format
    npm run type-check
    
  5. 本地测试

    npm run build
    # 在 Chrome 中加载 dist 目录测试
    
  6. 提交代码

    git add .
    git commit -m "feat: 添加新功能描述"
    git push origin feature/your-feature-name
    

🐛 调试技巧

1. 开发者工具调试

// 在代码中添加调试日志
console.log('[Auto Copy] 选择变更:', state.text);
console.log('[Auto Copy] 定时器启动:', timestamp);

查看日志:

  1. 打开 Chrome DevTools(F12)
  2. 切换到"Console"标签
  3. 筛选"Auto Copy"关键词

2. Vue DevTools 调试

  1. 安装 Vue DevTools 插件
  2. 打开 DevTools,切换到"Vue"标签
  3. 查看组件状态和响应式数据

3. 断点调试

// 在代码中设置断点
debugger;

然后在 Chrome DevTools 的"Sources"标签中调试。


4. 性能分析

// 使用 performance API 测量性能
const start = performance.now();
cleanText(text);
const end = performance.now();
console.log(`文本清理耗时: ${end - start}ms`);

🧪 测试指南

运行测试

# 运行所有测试
npm run test

# 运行特定文件
npm run test useSelectionMonitor

# 监听模式(自动重跑)
npm run test:watch

# 查看覆盖率
npm run test:coverage

编写测试示例

// tests/unit/textProcessor.test.ts
import { describe, test, expect } from 'vitest';
import { cleanText } from '@/utils/textProcessor';

describe('cleanText', () => {
  test('应该去除首尾空格', () => {
    expect(cleanText('  hello  ')).toBe('hello');
  });
  
  test('应该去除首尾引号', () => {
    expect(cleanText('"hello"')).toBe('hello');
  });
  
  test('应该保留中间空格', () => {
    expect(cleanText('  hello world  ')).toBe('hello world');
  });
});

🔨 构建与发布

本地构建测试

# 构建生产版本
npm run build

# 检查构建产物
ls -lh dist/

打包为 ZIP

# 进入 dist 目录并打包
cd dist
zip -r ../chrome-auto-copy-v1.0.0.zip .
cd ..

发布到 Chrome Web Store

  1. 访问 Chrome Web Store Developer Dashboard
  2. 点击"新增项目"
  3. 上传 ZIP 文件
  4. 填写插件信息:
    • 名称:Auto Copy - 智能文本自动复制
    • 描述:选中文本 2 秒后自动复制,智能清理空格和引号
    • 分类:生产力工具
    • 截图:准备 1-5 张功能截图
  5. 提交审核(通常 3-5 个工作日)

🎯 常见问题

Q1: 插件加载失败

问题: Chrome 提示"Manifest 文件无效"

解决:

# 确保构建成功
npm run build

# 检查 manifest.json 是否在 dist 目录
ls dist/manifest.json

Q2: 热重载不工作

问题: 修改代码后插件未更新

解决:

  1. chrome://extensions/ 点击刷新按钮
  2. 或者使用 Chrome 插件热重载工具(如 Extension Reloader

Q3: 剪贴板复制失败

问题: 复制时提示权限错误

解决: 检查 manifest.json 是否包含:

{
  "permissions": ["clipboardWrite"],
  "host_permissions": ["<all_urls>"]
}

Q4: 样式被网页覆盖

问题: "已复制"提示不显示或样式错误

解决: 确保使用 Shadow DOM(在 useFeedback.ts 中):

const shadowRoot = container.attachShadow({ mode: 'open' });

📚 学习资源

官方文档

项目文档


💡 最佳实践

代码风格

  1. 使用 Composition API

    // ✅ 推荐
    import { ref, computed } from 'vue';
    
    export function useTimer() {
      const count = ref(0);
      const doubled = computed(() => count.value * 2);
      return { count, doubled };
    }
    
    // ❌ 不推荐(Options API)
    export default {
      data() {
        return { count: 0 };
      },
      computed: {
        doubled() {
          return this.count * 2;
        }
      }
    };
    
  2. 类型优先

    // ✅ 推荐:明确类型
    function cleanText(text: string): string {
      return text.trim();
    }
    
    // ❌ 不推荐:隐式 any
    function cleanText(text) {
      return text.trim();
    }
    
  3. 模块化

    // ✅ 推荐:单一职责
    // useSelectionMonitor.ts - 只负责选择监听
    // useTimerManager.ts - 只负责定时器
    
    // ❌ 不推荐:所有逻辑放在一个文件
    // allLogic.ts - 包含所有功能
    

性能优化

  1. 防抖高频事件

    import { debounce } from '@/utils/debounce';
    
    const handleSelection = debounce((state: SelectionState) => {
      // 处理选择
    }, 100);
    
  2. 懒加载组件

    // 按需创建 Toast 组件,用完销毁
    const app = createApp(Toast);
    app.mount(container);
    setTimeout(() => app.unmount(), 1500);
    
  3. 及时清理

    // 组件卸载时清理监听器
    onUnmounted(() => {
      document.removeEventListener('selectionchange', handler);
    });
    

🤝 贡献指南

提交规范

使用 Conventional Commits

feat: 添加新功能
fix: 修复 bug
docs: 更新文档
style: 代码格式调整
refactor: 代码重构
test: 添加测试
chore: 构建/工具链更新

示例:

git commit -m "feat: 添加文本长度限制功能"
git commit -m "fix: 修复嵌套引号清理问题"
git commit -m "docs: 更新快速入门指南"

Pull Request 流程

  1. Fork 项目
  2. 创建功能分支
  3. 编写代码和测试
  4. 提交 PR,填写清晰的描述
  5. 等待代码审查
  6. 根据反馈修改
  7. 合并到主分支

📧 获取帮助


🎉 开始开发

现在你已经掌握了项目的基本知识,可以开始开发了!

# 启动开发服务器
npm run dev

# 在另一个终端运行测试监听
npm run test:watch

# 开始编码 🚀

祝开发愉快!


本快速入门指南遵循项目宪章的模块化设计和代码规范统一原则。

实现计划:智能文本自动复制插件

计划版本: 0.1.0
创建日期: 2026-01-14
关联规范: spec.md
负责人: [待分配]
技术栈: Vue.js 3 + Vite + TypeScript


执行摘要

目标

使用 Vue.js 3 + Vite + TypeScript 技术栈开发一个 Chrome 浏览器插件,实现智能文本自动复制功能。插件将采用模块化架构,包含选择监听、定时器管理、文本处理、剪贴板操作和用户反馈五个核心模块。

技术选型

  • 前端框架: Vue.js 3 (Composition API)
  • 构建工具: Vite 4.x
  • 类型系统: TypeScript 5.x
  • 插件规范: Chrome Extension Manifest V3
  • 代码规范: ESLint + Prettier
  • 测试框架: Vitest + @vue/test-utils

关键里程碑

  • 里程碑 1(项目搭建): 完成项目初始化和构建配置 - 第 1 周(Day 1-2)
  • 里程碑 2(核心功能): 完成选择监听和定时复制模块 - 第 1 周(Day 3-5)
  • 里程碑 3(文本处理): 完成文本清理和剪贴板操作 - 第 2 周(Day 1-3)
  • 里程碑 4(用户反馈): 完成 Vue 组件化的反馈 UI - 第 2 周(Day 4-5)
  • 里程碑 5(测试与优化): 完成测试、性能优化和文档 - 第 3 周
  • 里程碑 6(发布): Chrome Web Store 提交 - 第 4 周

资源需求

  • 开发人员: 1 人 / 15 个工作日
  • 测试人员: 0.5 人 / 5 个工作日(兼职测试)
  • 其他资源: Chrome 开发者账号($5 一次性费用)

宪章合规性确认

在开始实施前,确认以下合规性检查:

  • 模块化设计: 采用 Vue Composition API 和 TypeScript 模块系统实现清晰的模块边界
  • 最小依赖: 仅引入必要的 Vue 生态依赖(vue、vite、@vitejs/plugin-vue),无额外第三方库
  • 代码规范: 配置 ESLint、Prettier、TypeScript strict 模式
  • 中文优先: 所有 Speckit 文档、注释、提交信息使用中文

技术背景与研究

Vue.js 在 Chrome 插件中的应用

Vue.js 可以很好地应用于 Chrome 插件开发:

  • Content Script: 使用 Vue 3 的轻量级运行时构建 UI 组件(反馈提示)
  • Composition API: 提供清晰的逻辑复用和模块组织
  • 响应式系统: 简化状态管理(选择状态、定时器状态)
  • TypeScript 支持: 完善的类型定义,提升代码质量

Vite 构建配置

Vite 需要特殊配置以支持 Chrome 插件构建:

  • 使用 @vitejs/plugin-vue 处理 Vue SFC
  • 配置多入口构建(content script)
  • 禁用代码分割(插件需要单文件)
  • 生成 Manifest V3 配置文件

关键技术决策

决策点选择理由
Vue 版本Vue 3Composition API 更适合模块化设计,体积更小
构建工具Vite开发速度快,配置简洁,TypeScript 原生支持
状态管理Composition API功能简单,无需 Pinia/Vuex
UI 组件纯 Vue 组件无需 UI 库,减少依赖
样式方案Scoped CSS避免污染网页样式

实现阶段

阶段 0: 项目初始化(Day 1-2)

时间: 第 1 周 Day 1-2
目标: 搭建基于 Vite + Vue 3 + TypeScript 的 Chrome 插件开发环境

任务清单
  • 任务 0.1: 初始化 Vite 项目

    • 负责人: [待分配]
    • 预计工时: 2 小时
    • 命令: npm create vite@latest chrome-auto-copy -- --template vue-ts
  • 任务 0.2: 配置 Chrome 插件构建

    • 负责人: [待分配]
    • 预计工时: 4 小时
    • 配置 vite.config.ts 支持插件构建
    • 创建 manifest.json (Manifest V3)
  • 任务 0.3: 配置代码规范工具

    • 负责人: [待分配]
    • 预计工时: 2 小时
    • 安装并配置 ESLint + Prettier
    • 配置 TypeScript strict 模式
    • 设置 Git pre-commit hook
  • 任务 0.4: 配置测试环境

    • 负责人: [待分配]
    • 预计工时: 2 小时
    • 安装 Vitest 和 @vue/test-utils
    • 配置 vitest.config.ts
交付物
  • 可运行的 Vite 项目
  • 完整的 manifest.json 配置
  • ESLint + Prettier 配置文件
  • Vitest 测试环境
  • 项目 README.md
验收标准
  • npm run dev 可正常启动开发服务器
  • npm run build 可生成插件构建产物
  • npm run lint 无错误
  • npm run test 可运行测试

阶段 1: 核心模块开发(Day 3-5)

时间: 第 1 周 Day 3-5
目标: 实现选择监听和定时器管理模块

任务清单
  • 任务 1.1: 实现 SelectionMonitor 模块

    • 负责人: [待分配]
    • 预计工时: 6 小时
    • 使用 Composition API 创建 useSelectionMonitor composable
    • 监听 selectionchange 事件
    • 实现 getCurrentSelection() 方法
  • 任务 1.2: 实现 TimerManager 模块

    • 负责人: [待分配]
    • 预计工时: 4 小时
    • 创建 useTimerManager composable
    • 实现定时器的启动、重置、取消逻辑
    • 使用 performance.now() 确保精确计时
  • 任务 1.3: 集成选择监听和定时器

    • 负责人: [待分配]
    • 预计工时: 4 小时
    • 在主 content script 中整合两个模块
    • 实现选择变更时重置定时器的逻辑
    • 处理边界情况(空选择、快速变更)
  • 任务 1.4: 编写单元测试

    • 负责人: [待分配]
    • 预计工时: 4 小时
    • 测试选择监听功能
    • 测试定时器重置逻辑
    • 测试边界情况
交付物
  • src/composables/useSelectionMonitor.ts
  • src/composables/useTimerManager.ts
  • src/content-script.ts (主入口)
  • 对应的单元测试文件
验收标准
  • 选择文本后能够正确触发监听
  • 2 秒后准确触发回调(误差 ±50ms)
  • 选择变更时定时器正确重置
  • 快速取消选择不触发回调
  • 单元测试覆盖率 > 80%

阶段 2: 文本处理与剪贴板(Day 6-8)

时间: 第 2 周 Day 1-3
目标: 实现文本清理和剪贴板复制功能

任务清单
  • 任务 2.1: 实现 TextProcessor 模块
    • 负责人: [待分配]
    • 预计工时: 4 小时
    • 创建 src/utils/textProcessor.ts
    • 实现 cleanText() 函数
    • 实现去除首尾空格和引号的逻辑
  • 任务 2.2: 实现 ClipboardManager 模块
    • 负责人: [待分配]
    • 预计工时: 3 小时
    • 创建 useClipboard composable
    • 使用 navigator.clipboard.writeText() API
    • 处理权限和异常情况
  • 任务 2.3: 集成文本处理和复制流程
    • 负责人: [待分配]
    • 预计工时: 3 小时
    • 在定时器回调中调用文本处理和复制
    • 添加错误处理和日志记录
  • 任务 2.4: 编写文本处理单元测试
    • 负责人: [待分配]
    • 预计工时: 4 小时
    • 测试各种空格、引号组合
    • 测试嵌套引号处理
    • 测试边界情况(空文本、纯空格)
交付物
  • src/utils/textProcessor.ts
  • src/composables/useClipboard.ts
  • 完整的文本处理单元测试
验收标准
  • 正确去除首尾空格、制表符、换行符
  • 正确去除首尾单引号和双引号
  • 正确处理嵌套引号(如 "'text'"text
  • 文本成功写入剪贴板
  • 文本处理单元测试覆盖率 > 90%

阶段 3: 用户反馈 UI(Day 9-10)

时间: 第 2 周 Day 4-5
目标: 使用 Vue 组件实现反馈提示 UI

任务清单
  • 任务 3.1: 创建 Toast 通知组件
    • 负责人: [待分配]
    • 预计工时: 4 小时
    • 创建 src/components/Toast.vue
    • 实现淡入淡出动画
    • 使用 Scoped CSS 避免样式污染
  • 任务 3.2: 实现反馈 UI 管理
    • 负责人: [待分配]
    • 预计工时: 3 小时
    • 创建 useFeedback composable
    • 动态挂载 Vue 组件到 DOM
    • 实现自动消失逻辑(1.5 秒)
  • 任务 3.3: 集成反馈到复制流程
    • 负责人: [待分配]
    • 预计工时: 2 小时
    • 复制成功后显示提示
    • 处理多次复制的提示队列
  • 任务 3.4: 样式优化
    • 负责人: [待分配]
    • 预计工时: 3 小时
    • 确保高 z-index 不被覆盖
    • 适配深色/浅色主题
    • 响应式定位(跟随光标位置)
交付物
  • src/components/Toast.vue
  • src/composables/useFeedback.ts
  • Toast 组件样式
验收标准
  • 复制成功后显示"已复制"提示
  • 提示在 1.5 秒后自动消失
  • 提示不被网页样式覆盖
  • 淡入淡出动画流畅
  • 多次复制时提示正确显示

阶段 4: 测试与优化(Day 11-15)

时间: 第 3 周
目标: 完成完整测试、性能优化和兼容性验证

任务清单
  • 任务 4.1: 集成测试
    • 负责人: [待分配]
    • 预计工时: 8 小时
    • 测试完整的选择-等待-复制流程
    • 测试不同网页类型(静态、SPA、动态)
    • 测试边界情况和异常场景
  • 任务 4.2: 性能优化
    • 负责人: [待分配]
    • 预计工时: 6 小时
    • 优化事件监听性能(防抖/节流)
    • 减少内存占用
    • 优化构建产物体积
  • 任务 4.3: 兼容性测试
    • 负责人: [待分配]
    • 预计工时: 6 小时
    • 在 Windows、macOS、Linux 上测试
    • 测试不同 Chrome 版本(88+)
    • 测试常见网站兼容性
  • 任务 4.4: 代码审查和重构
    • 负责人: [待分配]
    • 预计工时: 4 小时
    • 代码审查,确保符合规范
    • 重构重复代码
    • 优化 TypeScript 类型定义
交付物
  • 完整的集成测试套件
  • 性能测试报告
  • 兼容性测试报告
  • 优化后的代码
验收标准
  • 集成测试全部通过
  • 单元测试覆盖率 > 85%
  • 内存占用 < 10MB
  • 构建产物体积 < 200KB
  • 在主流网站上正常工作
  • 代码通过 ESLint 和 TypeScript 检查

阶段 5: 文档与发布(Day 16-20)

时间: 第 4 周
目标: 完善文档并发布到 Chrome Web Store

任务清单
  • 任务 5.1: 编写用户文档
    • 负责人: [待分配]
    • 预计工时: 4 小时
    • 编写 README.md
    • 编写使用说明
    • 准备 Chrome Web Store 描述
  • 任务 5.2: 准备发布资源
    • 负责人: [待分配]
    • 预计工时: 4 小时
    • 设计插件图标(128x128、48x48、16x16)
    • 准备截图和宣传图
    • 编写 CHANGELOG.md
  • 任务 5.3: 打包和测试
    • 负责人: [待分配]
    • 预计工时: 3 小时
    • 生产环境构建
    • 在本地加载插件测试
    • 最终验收测试
  • 任务 5.4: 提交到 Chrome Web Store
    • 负责人: [待分配]
    • 预计工时: 2 小时
    • 注册开发者账号
    • 上传插件包
    • 填写商店信息
交付物
  • 完整的 README.md
  • 用户指南文档
  • 插件图标和截图
  • Chrome Web Store 商店页面
验收标准
  • README 完整清晰
  • 用户指南易于理解
  • 插件图标符合规范
  • 成功提交到 Chrome Web Store
  • 通过商店审核(预计 3-5 个工作日)

技术实施细节

项目目录结构

chrome-auto-copy/
├── public/
│   └── icons/                    # 插件图标
│       ├── icon-16.png
│       ├── icon-48.png
│       └── icon-128.png
├── src/
│   ├── components/
│   │   └── Toast.vue             # 反馈提示组件
│   ├── composables/
│   │   ├── useSelectionMonitor.ts  # 选择监听
│   │   ├── useTimerManager.ts      # 定时器管理
│   │   ├── useClipboard.ts         # 剪贴板操作
│   │   └── useFeedback.ts          # 反馈 UI 管理
│   ├── utils/
│   │   └── textProcessor.ts        # 文本处理工具
│   ├── types/
│   │   └── index.ts                # TypeScript 类型定义
│   ├── content-script.ts           # Content Script 入口
│   └── main.ts                     # 应用主入口
├── tests/
│   ├── unit/                     # 单元测试
│   └── integration/              # 集成测试
├── manifest.json                 # Chrome 插件配置
├── vite.config.ts                # Vite 配置
├── tsconfig.json                 # TypeScript 配置
├── .eslintrc.js                  # ESLint 配置
├── .prettierrc.js                # Prettier 配置
├── vitest.config.ts              # Vitest 配置
├── package.json
└── README.md

核心模块接口设计

SelectionMonitor (useSelectionMonitor)
interface SelectionState {
  text: string;
  range: Range | null;
  timestamp: number;
  isStable: boolean;
}

interface UseSelectionMonitor {
  currentSelection: Ref<SelectionState>;
  startMonitoring: () => void;
  stopMonitoring: () => void;
  onSelectionChange: (callback: (state: SelectionState) => void) => void;
}

export function useSelectionMonitor(): UseSelectionMonitor
TimerManager (useTimerManager)
interface TimerState {
  timerId: number | null;
  startTime: number;
  duration: number;
  isActive: boolean;
}

interface UseTimerManager {
  timerState: Ref<TimerState>;
  startTimer: (duration: number, callback: () => void) => void;
  resetTimer: () => void;
  cancelTimer: () => void;
}

export function useTimerManager(): UseTimerManager
TextProcessor
interface TextProcessorOptions {
  trimWhitespace?: boolean;
  removeQuotes?: boolean;
  maxLength?: number;
}

export function cleanText(
  text: string,
  options?: TextProcessorOptions
): string;

export function trimWhitespace(text: string): string;
export function removeQuotes(text: string): string;
ClipboardManager (useClipboard)
interface UseClipboard {
  copy: (text: string) => Promise<boolean>;
  isSupported: Ref<boolean>;
  lastError: Ref<Error | null>;
}

export function useClipboard(): UseClipboard
FeedbackUI (useFeedback)
interface FeedbackOptions {
  message: string;
  duration?: number;
  position?: { x: number; y: number };
}

interface UseFeedback {
  show: (options: FeedbackOptions) => void;
  hide: () => void;
  isVisible: Ref<boolean>;
}

export function useFeedback(): UseFeedback

数据流设计

用户选择文本
    ↓
SelectionMonitor 监听到 selectionchange 事件
    ↓
更新 SelectionState(text, range, timestamp)
    ↓
触发 onSelectionChange 回调
    ↓
TimerManager 启动 2 秒定时器
    ↓
如果期间有新的选择变更 → 重置定时器
    ↓
2 秒后定时器触发
    ↓
TextProcessor 清理文本(去除首尾空格和引号)
    ↓
ClipboardManager 复制到剪贴板
    ↓
FeedbackUI 显示"已复制"提示
    ↓
1.5 秒后提示自动消失

依赖管理

新增依赖

依赖名称版本用途理由替代方案
vue^3.4.0前端框架提供响应式和组件化能力,体积小性能好无(核心依赖)
vite^5.0.0构建工具开发体验好,构建速度快,TypeScript 原生支持Webpack(配置复杂)
@vitejs/plugin-vue^5.0.0Vite 的 Vue 插件支持 Vue SFC 编译无(必需)
typescript^5.3.0类型系统提供类型检查,提升代码质量无(必需)
eslint^8.56.0代码检查工具保证代码质量和规范无(宪章要求)
prettier^3.2.0代码格式化工具统一代码风格无(宪章要求)
vitest^1.2.0测试框架与 Vite 完美集成,速度快Jest(配置复杂)
@vue/test-utils^2.4.0Vue 组件测试工具测试 Vue 组件无(必需)

依赖审查清单

  • 所有依赖维护活跃度已确认(Vue、Vite 生态均为活跃维护)
  • 依赖包安全漏洞已扫描(使用 npm audit
  • 依赖包许可证已确认兼容(均为 MIT 许可证)
  • 依赖包体积已评估(构建后预计 < 200KB)

依赖理由说明

为什么选择 Vue.js 而不是原生 JavaScript?

  • Vue 的 Composition API 提供了更好的代码组织和复用能力
  • 响应式系统简化了状态管理
  • 组件化使 UI 开发更高效
  • 构建后的体积增加可控(< 100KB),性能影响可接受

为什么选择 Vite 而不是 Webpack?

  • Vite 开发体验更好,热更新极快
  • 配置更简洁,对 TypeScript 支持更好
  • 构建速度更快
  • 对 Chrome 插件构建支持良好

代码规范配置

格式化工具:Prettier

配置文件: .prettierrc.js

module.exports = {
  semi: true,
  trailingComma: 'es5',
  singleQuote: true,
  printWidth: 100,
  tabWidth: 2,
  useTabs: false,
  arrowParens: 'avoid',
  endOfLine: 'lf',
};

运行命令:

  • 格式化所有文件: npm run format
  • 检查格式: npm run format:check

Lint 工具:ESLint

配置文件: .eslintrc.js

module.exports = {
  root: true,
  env: {
    browser: true,
    es2021: true,
    webextensions: true,
  },
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:vue/vue3-recommended',
    'prettier',
  ],
  parser: 'vue-eslint-parser',
  parserOptions: {
    ecmaVersion: 'latest',
    parser: '@typescript-eslint/parser',
    sourceType: 'module',
  },
  plugins: ['@typescript-eslint', 'vue'],
  rules: {
    '@typescript-eslint/no-unused-vars': 'error',
    '@typescript-eslint/no-explicit-any': 'warn',
    'vue/multi-word-component-names': 'off',
    'no-console': ['warn', { allow: ['warn', 'error'] }],
  },
};

运行命令:

  • 检查代码: npm run lint
  • 自动修复: npm run lint:fix

TypeScript 配置

配置文件: tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "moduleResolution": "bundler",
    "strict": true,
    "jsx": "preserve",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true,
    "types": ["chrome", "vite/client"],
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  },
  "include": ["src/**/*.ts", "src/**/*.vue"],
  "exclude": ["node_modules", "dist"]
}

CI 集成

Pre-commit Hook (Husky + lint-staged)

package.json:

{
  "lint-staged": {
    "*.{ts,vue}": [
      "eslint --fix",
      "prettier --write"
    ]
  }
}
  • Pre-commit hook 已配置
  • CI 流水线已添加 lint 检查(GitHub Actions)
  • CI 流水线已添加格式检查
  • CI 流水线已添加单元测试

风险管理

已识别风险

风险ID风险描述概率影响缓解措施负责人
R1Chrome API 在某些网站被 CSP 阻止文档说明限制,收集不兼容网站列表[待分配]
R2Vue 运行时与网页 Vue 实例冲突使用独立作用域,避免全局污染[待分配]
R3构建产物体积过大影响性能使用 Tree-shaking,仅引入必要模块[待分配]
R4TypeScript 类型定义不完整及时补充类型定义,使用 @types/chrome[待分配]
R5用户反馈 UI 被网页样式覆盖使用极高 z-index 和 Shadow DOM(可选)[待分配]
R6不同浏览器剪贴板 API 兼容性问题仅支持 Chrome 88+,文档明确说明[待分配]

应急预案

R1 - CSP 阻止:

  • 在文档中明确说明已知限制
  • 提供用户反馈机制收集问题网站
  • 考虑未来版本添加白名单功能

R2 - Vue 实例冲突:

  • 使用 createApp() 创建独立 Vue 实例
  • 避免污染 window 对象
  • 测试常见使用 Vue 的网站

R3 - 构建体积过大:

  • 使用 Vite 的代码分割(但插件需禁用)
  • 仅引入 Vue 运行时版本(不含编译器)
  • 移除 devtools 和开发时警告

R6 - 剪贴板兼容性:

  • 使用标准的 navigator.clipboard.writeText()
  • 添加降级方案(document.execCommand('copy')
  • 明确文档说明浏览器版本要求

测试计划

单元测试

目标覆盖率: 85%
测试框架: Vitest + @vue/test-utils
负责人: [待分配]

测试范围:

  • textProcessor.ts 的所有函数(目标覆盖率 95%)
  • useSelectionMonitor composable
  • useTimerManager composable
  • useClipboard composable
  • useFeedback composable
  • Toast 组件渲染和行为

关键测试用例:

// textProcessor 测试
describe('cleanText', () => {
  test('去除首尾空格', () => {
    expect(cleanText('  hello  ')).toBe('hello');
  });
  
  test('去除首尾引号', () => {
    expect(cleanText('"hello"')).toBe('hello');
  });
  
  test('处理嵌套引号', () => {
    expect(cleanText('"\'hello\'"')).toBe('hello');
  });
  
  test('保留中间空格', () => {
    expect(cleanText('  hello world  ')).toBe('hello world');
  });
});

// useTimerManager 测试
describe('useTimerManager', () => {
  test('启动定时器后 2 秒触发回调', async () => {
    const { startTimer } = useTimerManager();
    const callback = vi.fn();
    startTimer(2000, callback);
    await vi.advanceTimersByTime(2000);
    expect(callback).toHaveBeenCalledTimes(1);
  });
  
  test('重置定时器重新计时', async () => {
    const { startTimer, resetTimer } = useTimerManager();
    const callback = vi.fn();
    startTimer(2000, callback);
    await vi.advanceTimersByTime(1000);
    resetTimer();
    await vi.advanceTimersByTime(1500);
    expect(callback).not.toHaveBeenCalled();
  });
});

集成测试

测试场景:

  1. 完整的选择-等待-复制流程
  2. 选择变更时定时器重置
  3. 快速取消选择不触发复制
  4. 空文本不触发复制
  5. 超长文本正常处理
  6. 多次连续复制

测试工具: Playwright(E2E 测试)
负责人: [待分配]


性能测试

性能指标:

  • 选择事件监听响应时间 < 50ms
  • 文本清理时间 < 10ms
  • 剪贴板写入时间 < 100ms
  • 插件内存占用 < 10MB
  • 构建产物体积 < 200KB

测试工具: Chrome DevTools Performance、Memory Profiler
负责人: [待分配]


文档更新计划

  • README 更新(项目说明、安装方法、使用指南)
  • API 文档更新(Composables 使用文档)
  • 架构文档更新(模块设计、数据流)
  • 变更日志更新(CHANGELOG.md)
  • 用户指南(Chrome Web Store 描述)
  • 开发指南(贡献者文档)

发布检查清单

  • 所有功能已实现并通过测试
  • 代码审查已完成
  • 文档已更新(README、用户指南)
  • 版本号已更新(package.json、manifest.json)
  • 变更日志已更新(CHANGELOG.md)
  • 向后兼容性已确认(首版无此要求)
  • 性能基准测试已通过
  • 安全扫描已通过(npm audit
  • 构建产物已验证(npm run build
  • 在本地加载插件测试通过
  • 插件图标和截图已准备
  • Chrome Web Store 商店信息已填写

进度跟踪

第 1 周

已完成:

  • [待更新]

进行中:

  • [待更新]

阻塞问题:

  • [待更新]

第 2 周

已完成:

  • [待更新]

进行中:

  • [待更新]

阻塞问题:

  • [待更新]

第 3 周

已完成:

  • [待更新]

进行中:

  • [待更新]

阻塞问题:

  • [待更新]

第 4 周

已完成:

  • [待更新]

进行中:

  • [待更新]

阻塞问题:

  • [待更新]

批准与签字

角色姓名批准日期
技术负责人[待分配]
项目经理[待分配]

本实施计划严格遵循 项目宪章 的所有原则。