diff --git a/entrypoints/background.ts b/entrypoints/background.ts index 587ac3b..ffb44a1 100644 --- a/entrypoints/background.ts +++ b/entrypoints/background.ts @@ -19,11 +19,15 @@ export default defineBackground(() => { } // 注入 content script - const res = browser.scripting.executeScript({ - target: { tabId: tab.id }, - files: ['/content-scripts/content.js'], - }); - console.log('Content script injected on installed/updated:', res); + try { + const res = await browser.scripting.executeScript({ + target: { tabId: tab.id }, + files: ['/content-scripts/content.js'], + }); + console.log('Content script injected on installed/updated:', res); + } catch (error) { + console.error('Failed to inject content script:', error); + } } }); @@ -36,6 +40,7 @@ export default defineBackground(() => { sendResponse({ ok: true }); }) .catch(() => { + console.error('Failed to check status in content script'); sendResponse({ ok: false }); }); return true; @@ -49,6 +54,7 @@ export default defineBackground(() => { sendResponse({ ok: true }); }) .catch(() => { + console.error('Failed to start recording in content script'); sendResponse({ ok: false }); }); } @@ -68,6 +74,14 @@ export default defineBackground(() => { return true; }); + // 监听来自 content script 的消息 + chrome.runtime.onMessage.addListener((msg, _sender, sendResponse) => { + if (msg.type === messages.content.from.saveTrackeEvents) { + console.log('[bg] saveTrackeEvents received:', msg.payload); + sendResponse({ ok: true }); + } + }); + async function sendToActiveTab(message: { type: string; data?: unknown; @@ -80,6 +94,11 @@ export default defineBackground(() => { }); const activeTab = activeTabs[0]; const sendTo = message.activeTabId || activeTab.id; - await chrome.tabs.sendMessage(sendTo!, message); + try { + await chrome.tabs.sendMessage(sendTo!, message); + } catch (error) { + console.error('Error sending message to active tab:', error); + throw error; + } } }); diff --git a/entrypoints/content.ts b/entrypoints/content.ts index fa79904..cd78896 100644 --- a/entrypoints/content.ts +++ b/entrypoints/content.ts @@ -1,10 +1,13 @@ import '../.wxt/types/imports.d.ts'; +import { createRecorder } from '@/utils/useRecorder'; export default defineContentScript({ // matches: ['*://*.google.com/*'], matches: [''], runAt: 'document_start', main() { + const recorder = createRecorder(); + // 监听来自 background script 的消息 chrome.runtime.onMessage.addListener((msg: { type: string }, _sender, sendResponse) => { if (msg.type === messages.content.checkStatus) { @@ -16,12 +19,14 @@ export default defineContentScript({ if (msg.type === messages.content.to.startRecording) { // 开始录制的处理逻辑 console.log('[content] startRecording received'); + recorder.startRecord(messages.content.from.saveTrackeEvents); sendResponse({ ok: true }); } - + if (msg.type === messages.content.to.stopRecording) { // 停止录制的处理逻辑 console.log('[content] stopRecording received'); + recorder.stopRecord(); sendResponse({ ok: true }); } diff --git a/hooks/useRecorder.tsx b/hooks/useRecorder.tsx deleted file mode 100644 index a703b4c..0000000 --- a/hooks/useRecorder.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { useRef, useState, useCallback } from 'react'; - -export const useRecorder = () => { - // 存储停止录制函数 - const stopFnRef = useRef<(() => void) | null>(null); - const [isRecording, setIsRecording] = useState(false); - - const startRecord = useCallback(async () => { - if (isRecording) return; - - try { - // await chrome.runtime.sendMessage({ type: 'CREATE_OFFSCREEN' }); - setIsRecording(true); - - console.log('[content] rrweb started'); - } catch (error) { - console.error('Failed to start recording:', error); - setIsRecording(false); - } - }, [isRecording]); - - const stopRecord = () => { - if (!isRecording) return; - - setIsRecording(false); - - // 停止录制 - if (stopFnRef.current) { - chrome.runtime.sendMessage({ type: 'SAVE_EVENTS' }); - stopFnRef.current?.(); - - console.log('[content] rrweb stopped'); - } - }; - - return { - startRecord, - stopRecord, - isRecording, - }; -}; diff --git a/package-lock.json b/package-lock.json index dc8261d..0f7b715 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,6 +44,7 @@ "husky": "^9.1.7", "lint-staged": "^16.2.7", "prettier": "^3.8.1", + "terser": "^5.46.0", "typescript": "^5.9.3", "typescript-eslint": "^8.54.0", "wxt": "^0.20.6" @@ -1254,6 +1255,17 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmmirror.com/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", @@ -9581,6 +9593,32 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/terser": { + "version": "5.46.0", + "resolved": "https://registry.npmmirror.com/terser/-/terser-5.46.0.tgz", + "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, "node_modules/thread-stream": { "version": "3.1.0", "resolved": "https://registry.npmmirror.com/thread-stream/-/thread-stream-3.1.0.tgz", diff --git a/package.json b/package.json index 7e3c9d6..e1f2cd5 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "husky": "^9.1.7", "lint-staged": "^16.2.7", "prettier": "^3.8.1", + "terser": "^5.46.0", "typescript": "^5.9.3", "typescript-eslint": "^8.54.0", "wxt": "^0.20.6" diff --git a/utils/messages.tsx b/utils/messages.tsx index f2676c9..82a5b61 100644 --- a/utils/messages.tsx +++ b/utils/messages.tsx @@ -12,7 +12,9 @@ export const messages = { ready: 'popup:ready', }, content: { - from: {}, + from: { + saveTrackeEvents: 'content:save-tracke-events', + }, to: { startRecording: 'content:start-recording', stopRecording: 'content:stop-recording', diff --git a/utils/useRecorder.tsx b/utils/useRecorder.tsx new file mode 100644 index 0000000..334e958 --- /dev/null +++ b/utils/useRecorder.tsx @@ -0,0 +1,36 @@ +import * as rrweb from 'rrweb'; +import { listenerHandler } from '@rrweb/types'; + +export const createRecorder = () => { + let stopFn: listenerHandler | null = null; + + const startRecord = async (msg: string) => { + try { + // const handler = null; + const handler = rrweb.record({ + emit(event) { + chrome.runtime.sendMessage({ + type: msg, + payload: event, + }); + }, + }); + + stopFn = handler || null; + + console.log('[content] rrweb started'); + } catch (error) { + console.error('Failed to start recording:', error); + } + }; + + const stopRecord = () => { + if (stopFn) { + stopFn(); + stopFn = null; + console.log('[content] rrweb stopped'); + } + }; + + return { startRecord, stopRecord }; +}; diff --git a/wxt.config.ts b/wxt.config.ts index 7a1b6b9..9e041bc 100644 --- a/wxt.config.ts +++ b/wxt.config.ts @@ -31,4 +31,18 @@ export default defineConfig({ 128: 'favicon.ico', }, }, + vite: () => ({ + build: { + // 1. 切换压缩器为 terser + minify: 'terser', + + // 2. 配置 terser 强制转义所有非 ASCII 字符 + terserOptions: { + format: { + ascii_only: true, + comments: false, // 去掉注释,防止注释里有乱码 + }, + }, + }, + }), });