feat: 添加 husky 和 lint-staged 支持,配置 prettier 进行代码格式化

This commit is contained in:
雨霖铃
2026-01-28 20:26:48 +08:00
parent 4edb2f1a47
commit 710bffd2f8
10 changed files with 338 additions and 112 deletions
+1
View File
@@ -0,0 +1 @@
npx lint-staged
+12
View File
@@ -0,0 +1,12 @@
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"jsxSingleQuote": false,
"trailingComma": "all",
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "lf"
}
+32 -46
View File
@@ -1,5 +1,4 @@
import { useState, useCallback } from 'react'; import { useEffect, useState, useCallback } from 'react';
import { copyToClipboard } from '@/utils/chromeUtils';
const CopyButton = ({ const CopyButton = ({
text = '要复制的文本', text = '要复制的文本',
@@ -7,14 +6,13 @@ const CopyButton = ({
className = 'action-btn', className = 'action-btn',
successMessage = '复制成功!', successMessage = '复制成功!',
errorMessage = '复制失败,请手动复制。', errorMessage = '复制失败,请手动复制。',
onCopyOverride = null,
}) => { }) => {
const [status, setStatus] = useState('idle'); // 'idle' | 'copying' | 'success' | 'error' const [status, setStatus] = useState('idle'); // 'idle' | 'copying' | 'success' | 'error'
useEffect(() => { useEffect(() => {
let timer; let timer: number;
if (status === 'success' || status === 'error') { if (status === 'success' || status === 'error') {
timer = setTimeout(() => { timer = window.setTimeout(() => {
setStatus('idle'); setStatus('idle');
}, 2000); }, 2000);
} }
@@ -30,29 +28,15 @@ const CopyButton = ({
const safeText = String(text); const safeText = String(text);
// 优先使用传入的复制函数 if (navigator.clipboard && navigator.clipboard.writeText) {
if (onCopyOverride) { try {
return await onCopyOverride(safeText); await navigator.clipboard.writeText(safeText);
}
const textArea = document.createElement("textarea");
textArea.value = safeText;
// 确保元素存在但不可见,且不影响布局
textArea.style.position = "fixed";
textArea.style.left = "-9999px";
textArea.style.top = "0";
textArea.style.opacity = "0";
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
const successful = document.execCommand('copy');
document.body.removeChild(textArea);
// 使用通用的复制函数
return true; return true;
} catch (err) {
console.error('使用 Clipboard API 复制失败:', err);
return false;
}
}
}; };
const handleClick = useCallback(async () => { const handleClick = useCallback(async () => {
@@ -65,35 +49,37 @@ const CopyButton = ({
console.error('复制时出错:', error); console.error('复制时出错:', error);
setStatus('error'); setStatus('error');
} }
}, [text, onCopyOverride]); }, [text]);
// 根据状态计算当前显示的文本 // 根据状态计算当前显示的文本
const currentText = status === 'success' ? successMessage const currentText =
: status === 'error' ? errorMessage status === 'success' ? successMessage : status === 'error' ? errorMessage : buttonText;
: buttonText;
// 根据状态计算样式 (建议使用 CSS Module 或 Tailwind,这里为了演示保留内联) // 动态样式:只在非默认状态下覆盖颜色,平时让 className 控制
const getBackgroundColor = () => { const getStyle = () => {
switch (status) { const baseStyle = {
case 'success': return '#4CAF50'; transition: 'all 0.3s ease',
case 'error': return '#f44336'; cursor: 'pointer', // 确保有手型光标
default: return '#4CAF50'; // 让 CSS 类控制默认颜色 // 这里去掉了 padding/border/radius 的硬编码,建议在 CSS 类中定义
// 除非你想强制覆盖
};
if (status === 'success') {
return { ...baseStyle, backgroundColor: '#4CAF50', color: 'white' };
} }
if (status === 'error') {
return { ...baseStyle, backgroundColor: '#f44336', color: 'white' };
}
return baseStyle;
}; };
return ( return (
<button <button
onClick={handleClick} onClick={handleClick}
className={`${className} ${status} copy-button`} className={`${className} ${status} copy-button`}
style={{ style={getStyle()}
backgroundColor: getBackgroundColor(), disabled={status === 'copying'}
color: status !== 'idle' ? 'white' : undefined,
transition: 'all 0.3s ease',
padding: '8px 16px',
border: 'none',
borderRadius: '8px',
cursor: 'pointer',
}}
> >
{currentText} {currentText}
</button> </button>
-27
View File
@@ -1,30 +1,3 @@
export default defineBackground(() => { export default defineBackground(() => {
console.log('Hello background!', { id: browser.runtime.id }); console.log('Hello background!', { id: browser.runtime.id });
console.log('Background script loaded');
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log('收到消息:', request);
if (request.action === 'copy') {
console.log('开始复制文本:', request.text);
navigator.clipboard
.writeText(request.text)
.then(() => {
console.log('复制成功');
sendResponse({ success: true });
})
.catch((err) => {
console.error('复制失败:', err);
sendResponse({ success: false, error: err.message });
});
return true; // 保持消息端口开放以支持异步响应
}
// 对于未知的操作,也返回响应
sendResponse({ success: false, error: '未知操作' });
return false;
});
}); });
+6 -6
View File
@@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title> <title>Document</title>
</head> </head>
<body> <body>
Hello Options Page Hello Options Page
</body> </body>
</html> </html>
+207
View File
@@ -33,6 +33,9 @@
"@types/react": "^19.2.7", "@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"@wxt-dev/module-react": "^1.1.5", "@wxt-dev/module-react": "^1.1.5",
"husky": "^9.1.7",
"lint-staged": "^16.2.7",
"prettier": "^3.8.1",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"wxt": "^0.20.6" "wxt": "^0.20.6"
} }
@@ -3634,6 +3637,22 @@
"url": "https://github.com/fb55/entities?sponsor=1" "url": "https://github.com/fb55/entities?sponsor=1"
} }
}, },
"node_modules/husky": {
"version": "9.1.7",
"resolved": "https://registry.npmmirror.com/husky/-/husky-9.1.7.tgz",
"integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==",
"dev": true,
"license": "MIT",
"bin": {
"husky": "bin.js"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/typicode"
}
},
"node_modules/immediate": { "node_modules/immediate": {
"version": "3.0.6", "version": "3.0.6",
"resolved": "https://registry.npmmirror.com/immediate/-/immediate-3.0.6.tgz", "resolved": "https://registry.npmmirror.com/immediate/-/immediate-3.0.6.tgz",
@@ -4198,6 +4217,139 @@
} }
} }
}, },
"node_modules/lint-staged": {
"version": "16.2.7",
"resolved": "https://registry.npmmirror.com/lint-staged/-/lint-staged-16.2.7.tgz",
"integrity": "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==",
"dev": true,
"license": "MIT",
"dependencies": {
"commander": "^14.0.2",
"listr2": "^9.0.5",
"micromatch": "^4.0.8",
"nano-spawn": "^2.0.0",
"pidtree": "^0.6.0",
"string-argv": "^0.3.2",
"yaml": "^2.8.1"
},
"bin": {
"lint-staged": "bin/lint-staged.js"
},
"engines": {
"node": ">=20.17"
},
"funding": {
"url": "https://opencollective.com/lint-staged"
}
},
"node_modules/lint-staged/node_modules/cli-truncate": {
"version": "5.1.1",
"resolved": "https://registry.npmmirror.com/cli-truncate/-/cli-truncate-5.1.1.tgz",
"integrity": "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==",
"dev": true,
"license": "MIT",
"dependencies": {
"slice-ansi": "^7.1.0",
"string-width": "^8.0.0"
},
"engines": {
"node": ">=20"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/lint-staged/node_modules/commander": {
"version": "14.0.2",
"resolved": "https://registry.npmmirror.com/commander/-/commander-14.0.2.tgz",
"integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=20"
}
},
"node_modules/lint-staged/node_modules/is-fullwidth-code-point": {
"version": "5.1.0",
"resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz",
"integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"get-east-asian-width": "^1.3.1"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/lint-staged/node_modules/listr2": {
"version": "9.0.5",
"resolved": "https://registry.npmmirror.com/listr2/-/listr2-9.0.5.tgz",
"integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==",
"dev": true,
"license": "MIT",
"dependencies": {
"cli-truncate": "^5.0.0",
"colorette": "^2.0.20",
"eventemitter3": "^5.0.1",
"log-update": "^6.1.0",
"rfdc": "^1.4.1",
"wrap-ansi": "^9.0.0"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/lint-staged/node_modules/nano-spawn": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/nano-spawn/-/nano-spawn-2.0.0.tgz",
"integrity": "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=20.17"
},
"funding": {
"url": "https://github.com/sindresorhus/nano-spawn?sponsor=1"
}
},
"node_modules/lint-staged/node_modules/slice-ansi": {
"version": "7.1.2",
"resolved": "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-7.1.2.tgz",
"integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^6.2.1",
"is-fullwidth-code-point": "^5.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
}
},
"node_modules/lint-staged/node_modules/string-width": {
"version": "8.1.0",
"resolved": "https://registry.npmmirror.com/string-width/-/string-width-8.1.0.tgz",
"integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==",
"dev": true,
"license": "MIT",
"dependencies": {
"get-east-asian-width": "^1.3.0",
"strip-ansi": "^7.1.0"
},
"engines": {
"node": ">=20"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/listr2": { "node_modules/listr2": {
"version": "8.3.3", "version": "8.3.3",
"resolved": "https://registry.npmmirror.com/listr2/-/listr2-8.3.3.tgz", "resolved": "https://registry.npmmirror.com/listr2/-/listr2-8.3.3.tgz",
@@ -5278,6 +5430,19 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/pidtree": {
"version": "0.6.0",
"resolved": "https://registry.npmmirror.com/pidtree/-/pidtree-0.6.0.tgz",
"integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==",
"dev": true,
"license": "MIT",
"bin": {
"pidtree": "bin/pidtree.js"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/pino": { "node_modules/pino": {
"version": "9.7.0", "version": "9.7.0",
"resolved": "https://registry.npmmirror.com/pino/-/pino-9.7.0.tgz", "resolved": "https://registry.npmmirror.com/pino/-/pino-9.7.0.tgz",
@@ -5358,6 +5523,22 @@
"node": "^10 || ^12 || >=14" "node": "^10 || ^12 || >=14"
} }
}, },
"node_modules/prettier": {
"version": "3.8.1",
"resolved": "https://registry.npmmirror.com/prettier/-/prettier-3.8.1.tgz",
"integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
"dev": true,
"license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/pretty-format": { "node_modules/pretty-format": {
"version": "27.5.1", "version": "27.5.1",
"resolved": "https://registry.npmmirror.com/pretty-format/-/pretty-format-27.5.1.tgz", "resolved": "https://registry.npmmirror.com/pretty-format/-/pretty-format-27.5.1.tgz",
@@ -6251,6 +6432,16 @@
"safe-buffer": "~5.1.0" "safe-buffer": "~5.1.0"
} }
}, },
"node_modules/string-argv": {
"version": "0.3.2",
"resolved": "https://registry.npmmirror.com/string-argv/-/string-argv-0.3.2.tgz",
"integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.6.19"
}
},
"node_modules/string-width": { "node_modules/string-width": {
"version": "7.2.0", "version": "7.2.0",
"resolved": "https://registry.npmmirror.com/string-width/-/string-width-7.2.0.tgz", "resolved": "https://registry.npmmirror.com/string-width/-/string-width-7.2.0.tgz",
@@ -7160,6 +7351,22 @@
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/yaml": {
"version": "2.8.2",
"resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.8.2.tgz",
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
"dev": true,
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
},
"engines": {
"node": ">= 14.6"
},
"funding": {
"url": "https://github.com/sponsors/eemeli"
}
},
"node_modules/yargs": { "node_modules/yargs": {
"version": "17.7.2", "version": "17.7.2",
"resolved": "https://registry.npmmirror.com/yargs/-/yargs-17.7.2.tgz", "resolved": "https://registry.npmmirror.com/yargs/-/yargs-17.7.2.tgz",
+12 -3
View File
@@ -4,6 +4,11 @@
"private": true, "private": true,
"version": "0.0.0", "version": "0.0.0",
"type": "module", "type": "module",
"lint-staged": {
"*.{js,jsx,ts,tsx,json,css,scss,md}": [
"prettier --write"
]
},
"scripts": { "scripts": {
"dev": "wxt", "dev": "wxt",
"dev:firefox": "wxt -b firefox", "dev:firefox": "wxt -b firefox",
@@ -12,11 +17,10 @@
"zip": "wxt zip", "zip": "wxt zip",
"zip:firefox": "wxt zip -b firefox", "zip:firefox": "wxt zip -b firefox",
"compile": "tsc --noEmit", "compile": "tsc --noEmit",
"postinstall": "wxt prepare" "postinstall": "wxt prepare",
"prepare": "husky"
}, },
"dependencies": { "dependencies": {
"react": "^19.2.3",
"react-dom": "^19.2.3",
"@rrweb/all": "^2.0.0-alpha.18", "@rrweb/all": "^2.0.0-alpha.18",
"@rrweb/rrweb-plugin-console-record": "^2.0.0-alpha.18", "@rrweb/rrweb-plugin-console-record": "^2.0.0-alpha.18",
"@rrweb/rrweb-plugin-console-replay": "^2.0.0-alpha.18", "@rrweb/rrweb-plugin-console-replay": "^2.0.0-alpha.18",
@@ -27,6 +31,8 @@
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"dexie": "^4.2.1", "dexie": "^4.2.1",
"dexie-react-hooks": "^4.2.0", "dexie-react-hooks": "^4.2.0",
"react": "^19.2.3",
"react-dom": "^19.2.3",
"react-markdown": "^6.0.3", "react-markdown": "^6.0.3",
"react-router-dom": "^6.30.2", "react-router-dom": "^6.30.2",
"remark-gfm": "^1.0.0", "remark-gfm": "^1.0.0",
@@ -39,6 +45,9 @@
"@types/react": "^19.2.7", "@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"@wxt-dev/module-react": "^1.1.5", "@wxt-dev/module-react": "^1.1.5",
"husky": "^9.1.7",
"lint-staged": "^16.2.7",
"prettier": "^3.8.1",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"wxt": "^0.20.6" "wxt": "^0.20.6"
} }
+12 -11
View File
@@ -1,13 +1,13 @@
import React from 'react'; import React from 'react';
// import {sendRecordCommand} from '../services/bridge' // import {sendRecordCommand} from '../services/bridge'
// import {storage} from "../services/storage"; // import {storage} from "../services/storage";
import {useRecorder} from "../hooks/useRecorder"; import { useRecorder } from '../hooks/useRecorder';
import {downloadHtml} from '../utils/recordUtils'; import { downloadHtml } from '../utils/recordUtils';
const RecordeReplayPage = () => { const RecordeReplayPage = () => {
// const [isRecording, setIsRecording] = useState(false); // const [isRecording, setIsRecording] = useState(false);
const {startRecord, stopRecord, getEvents, isRecording} = useRecorder(); const { startRecord, stopRecord, getEvents, isRecording } = useRecorder();
const handleStart = async () => { const handleStart = async () => {
try { try {
@@ -20,9 +20,9 @@ const RecordeReplayPage = () => {
// await storage.set({isRecording: true, recordingStartTime: Date.now()}); // await storage.set({isRecording: true, recordingStartTime: Date.now()});
// console.log('events', events); // console.log('events', events);
} catch (e) { } catch (e) {
console.error("Error starting recording:", e); console.error('Error starting recording:', e);
}
} }
};
const handleStop = async () => { const handleStop = async () => {
try { try {
@@ -35,24 +35,25 @@ const RecordeReplayPage = () => {
downloadHtml(getEvents()); downloadHtml(getEvents());
// console.log('events', getEvents()); // console.log('events', getEvents());
} catch (e) { } catch (e) {
console.error("Error stopping recording:", e) console.error('Error stopping recording:', e);
} }
}; };
return ( return (
<div style={{width: "300px", padding: "16px"}}> <div style={{ width: '300px', padding: '16px' }}>
<h3>RRWeb Recorder</h3> <h3>RRWeb Recorder</h3>
{/* 3. 选择标签页逻辑:默认为当前页,如果需要跨页,需先列出 chrome.tabs.query */} {/* 3. 选择标签页逻辑:默认为当前页,如果需要跨页,需先列出 chrome.tabs.query */}
<div style={{display: "flex", gap: "10px", marginBottom: "20px"}}> <div style={{ display: 'flex', gap: '10px', marginBottom: '20px' }}>
{!isRecording ? ( {!isRecording ? (
<button onClick={handleStart} className={"action-btn"}> <button onClick={handleStart} className={'action-btn'}>
</button> </button>
) : ( ) : (
<button className={"action-btn stop-btn"} <button className={'action-btn stop-btn'} onClick={handleStop}>
onClick={handleStop}></button>
</button>
)} )}
</div> </div>
</div> </div>
+10 -10
View File
@@ -1,15 +1,15 @@
import {TimestampToDatetime} from "../components/TimestampToDatetime"; import { TimestampToDatetime } from '../components/TimestampToDatetime';
import {DatetimeToTimestamp} from "../components/DatetimeToTimestamp"; import { DatetimeToTimestamp } from '../components/DatetimeToTimestamp';
import {TimestampExecution} from "../components/TimestampExecution"; import { TimestampExecution } from '../components/TimestampExecution';
const TimestampPage = () => { const TimestampPage = () => {
return (
return (<div className="timestamp-utils"> <div className="timestamp-utils">
<TimestampExecution/> <TimestampExecution />
<TimestampToDatetime/> <TimestampToDatetime />
<DatetimeToTimestamp/> <DatetimeToTimestamp />
</div>); </div>
);
}; };
export default TimestampPage; export default TimestampPage;
+38 -1
View File
@@ -1,7 +1,44 @@
{ {
"extends": "./.wxt/tsconfig.json", "extends": "./.wxt/tsconfig.json",
"compilerOptions": { "compilerOptions": {
/* --- --- */
"allowImportingTsExtensions": true, "allowImportingTsExtensions": true,
"jsx": "react-jsx" "jsx": "react-jsx",
/* --- 1. () --- */
// 开启所有严格检查,包括 noImplicitAny。
// 这能帮你捕获 "timer" 隐式 any 等错误,强制你写出更高质量的代码。
"strict": true,
/* --- 2. --- */
// 声明了但没使用的变量报错(防止代码冗余)
"noUnusedLocals": true,
// 函数参数没使用报错
"noUnusedParameters": true,
// switch 语句没有 break 时报错
"noFallthroughCasesInSwitch": true,
/* --- 3. --- */
// 设置基础目录,方便解析相对路径
"baseUrl": ".",
// 确保包含 DOM 类型(解决 setTimeout、document 等报错)
"lib": ["DOM", "DOM.Iterable", "ESNext"],
// 编译目标设置为最新,WXT 底层 Vite 会处理降级兼容
"target": "ESNext",
/* --- 4. () --- */
// 如果你的 @/utils/... 爆红,可以手动添加这个映射。
// WXT 通常会自动处理,但在这里显式声明有助于 VS Code 智能提示。
"paths": {
"@/*": ["./entrypoints/*", "./components/*", "./utils/*", "./assets/*"]
} }
},
// 确保包含你的源代码目录
"include": [
"entrypoints/**/*",
"components/**/*",
"utils/**/*",
"assets/**/*",
".wxt/types/**/*.ts"
]
} }