Compare commits
4 Commits
a3a82794ca
...
feature_20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a446f71c04 | ||
|
|
e02cbcd9b7 | ||
|
|
9bb9eab922 | ||
|
|
3d7b0045b7 |
110
.husky/pre-commit
Executable file
110
.husky/pre-commit
Executable file
@@ -0,0 +1,110 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Git Pre-commit Hook
|
||||||
|
# ============================================
|
||||||
|
# 规则:
|
||||||
|
# 1. src 目录下新增的代码文件必须使用 TypeScript (.ts/.tsx)
|
||||||
|
# 2. 修改的代码不能使用 fetch,应使用 axios
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
# 颜色定义
|
||||||
|
RED='\033[0;31m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
has_error=0
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "🔍 正在检查代码规范..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# 规则 1: 新文件必须使用 TypeScript
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
# 获取新增的文件(只检查 src 目录下的代码文件)
|
||||||
|
new_js_files=$(git diff --cached --name-only --diff-filter=A | grep -E '^src/.*\.(js|jsx)$' || true)
|
||||||
|
|
||||||
|
if [ -n "$new_js_files" ]; then
|
||||||
|
echo "${RED}❌ 错误: 发现新增的 JavaScript 文件${NC}"
|
||||||
|
echo "${YELLOW} 新文件必须使用 TypeScript (.ts/.tsx)${NC}"
|
||||||
|
echo ""
|
||||||
|
echo " 以下文件需要改为 TypeScript:"
|
||||||
|
echo "$new_js_files" | while read file; do
|
||||||
|
echo " - $file"
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
echo " 💡 提示: 请将文件扩展名改为 .ts 或 .tsx"
|
||||||
|
echo ""
|
||||||
|
has_error=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# 规则 2: 禁止使用 fetch,应使用 axios
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
# 获取所有暂存的文件(新增 + 修改)
|
||||||
|
staged_files=$(git diff --cached --name-only --diff-filter=AM | grep -E '^src/.*\.(js|jsx|ts|tsx)$' || true)
|
||||||
|
|
||||||
|
if [ -n "$staged_files" ]; then
|
||||||
|
# 检查暂存内容中是否包含 fetch 调用
|
||||||
|
# 使用 git diff --cached 检查实际修改的内容
|
||||||
|
fetch_found=""
|
||||||
|
|
||||||
|
for file in $staged_files; do
|
||||||
|
# 检查该文件暂存的更改中是否有 fetch 调用
|
||||||
|
# 排除注释和字符串中的 fetch
|
||||||
|
# 匹配: fetch(, await fetch, .fetch(
|
||||||
|
fetch_matches=$(git diff --cached -U0 "$file" 2>/dev/null | grep -E '^\+.*[^a-zA-Z_]fetch\s*\(' | grep -v '^\+\s*//' || true)
|
||||||
|
|
||||||
|
if [ -n "$fetch_matches" ]; then
|
||||||
|
fetch_found="$fetch_found
|
||||||
|
$file"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -n "$fetch_found" ]; then
|
||||||
|
echo "${RED}❌ 错误: 检测到使用了 fetch API${NC}"
|
||||||
|
echo "${YELLOW} 请使用 axios 进行 HTTP 请求${NC}"
|
||||||
|
echo ""
|
||||||
|
echo " 以下文件包含 fetch 调用:"
|
||||||
|
echo "$fetch_found" | while read file; do
|
||||||
|
if [ -n "$file" ]; then
|
||||||
|
echo " - $file"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
echo " 💡 修改建议:"
|
||||||
|
echo " ${GREEN}// 替换前${NC}"
|
||||||
|
echo " fetch('/api/data').then(res => res.json())"
|
||||||
|
echo ""
|
||||||
|
echo " ${GREEN}// 替换后${NC}"
|
||||||
|
echo " import axios from 'axios';"
|
||||||
|
echo " axios.get('/api/data').then(res => res.data)"
|
||||||
|
echo ""
|
||||||
|
has_error=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# 检查结果
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
if [ $has_error -eq 1 ]; then
|
||||||
|
echo "${RED}========================================${NC}"
|
||||||
|
echo "${RED}提交被阻止,请修复以上问题后重试${NC}"
|
||||||
|
echo "${RED}========================================${NC}"
|
||||||
|
echo ""
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "${GREEN}✅ 代码规范检查通过${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 运行 lint-staged(如果配置了)
|
||||||
|
# 可选:在 package.json 中添加 "lint-staged" 配置来启用代码格式化
|
||||||
|
# if [ -f "package.json" ] && grep -q '"lint-staged"' package.json; then
|
||||||
|
# npx lint-staged
|
||||||
|
# fi
|
||||||
@@ -131,12 +131,14 @@
|
|||||||
"eslint-plugin-prettier": "3.4.0",
|
"eslint-plugin-prettier": "3.4.0",
|
||||||
"gulp": "4.0.2",
|
"gulp": "4.0.2",
|
||||||
"gulp-append-prepend": "1.0.9",
|
"gulp-append-prepend": "1.0.9",
|
||||||
|
"husky": "^9.1.7",
|
||||||
"imagemin": "^9.0.1",
|
"imagemin": "^9.0.1",
|
||||||
"imagemin-mozjpeg": "^10.0.0",
|
"imagemin-mozjpeg": "^10.0.0",
|
||||||
"imagemin-pngquant": "^10.0.0",
|
"imagemin-pngquant": "^10.0.0",
|
||||||
"kill-port": "^2.0.1",
|
"kill-port": "^2.0.1",
|
||||||
"less": "^4.4.2",
|
"less": "^4.4.2",
|
||||||
"less-loader": "^12.3.0",
|
"less-loader": "^12.3.0",
|
||||||
|
"lint-staged": "^16.2.7",
|
||||||
"msw": "^2.11.5",
|
"msw": "^2.11.5",
|
||||||
"prettier": "2.2.1",
|
"prettier": "2.2.1",
|
||||||
"react-error-overlay": "6.0.9",
|
"react-error-overlay": "6.0.9",
|
||||||
|
|||||||
@@ -661,6 +661,12 @@ export const NotificationProvider = ({ children }) => {
|
|||||||
|
|
||||||
// ========== 连接到 Socket 服务(⚡ 异步初始化,不阻塞首屏) ==========
|
// ========== 连接到 Socket 服务(⚡ 异步初始化,不阻塞首屏) ==========
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
// ⚡ Mock 模式下跳过 Socket 连接(避免连接生产服务器失败的错误)
|
||||||
|
if (process.env.REACT_APP_ENABLE_MOCK === 'true') {
|
||||||
|
logger.debug('NotificationContext', 'Mock 模式,跳过 Socket 连接');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// ⚡ 防止 React Strict Mode 导致的重复初始化
|
// ⚡ 防止 React Strict Mode 导致的重复初始化
|
||||||
if (socketInitialized) {
|
if (socketInitialized) {
|
||||||
logger.debug('NotificationContext', 'Socket 已初始化,跳过重复执行(Strict Mode 保护)');
|
logger.debug('NotificationContext', 'Socket 已初始化,跳过重复执行(Strict Mode 保护)');
|
||||||
|
|||||||
11
src/index.js
11
src/index.js
@@ -5,6 +5,17 @@ import { BrowserRouter as Router } from 'react-router-dom';
|
|||||||
|
|
||||||
// ⚡ 性能监控:在应用启动时尽早标记
|
// ⚡ 性能监控:在应用启动时尽早标记
|
||||||
import { performanceMonitor } from './utils/performanceMonitor';
|
import { performanceMonitor } from './utils/performanceMonitor';
|
||||||
|
|
||||||
|
// T0: HTML 加载完成时间点
|
||||||
|
if (document.readyState === 'complete') {
|
||||||
|
performanceMonitor.mark('html-loaded');
|
||||||
|
} else {
|
||||||
|
window.addEventListener('load', () => {
|
||||||
|
performanceMonitor.mark('html-loaded');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// T1: React 开始初始化
|
||||||
performanceMonitor.mark('app-start');
|
performanceMonitor.mark('app-start');
|
||||||
|
|
||||||
// ⚡ 已删除 brainwave.css(项目未安装 Tailwind CSS,该文件无效)
|
// ⚡ 已删除 brainwave.css(项目未安装 Tailwind CSS,该文件无效)
|
||||||
|
|||||||
@@ -1,16 +1,28 @@
|
|||||||
// src/mocks/handlers/bytedesk.js
|
// src/mocks/handlers/bytedesk.js
|
||||||
/**
|
/**
|
||||||
* Bytedesk 客服 Widget MSW Handler
|
* Bytedesk 客服 Widget MSW Handler
|
||||||
* 使用 passthrough 让请求通过到真实服务器,消除 MSW 警告
|
* Mock 模式下返回模拟数据
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { http, passthrough } from 'msw';
|
import { http, HttpResponse, passthrough } from 'msw';
|
||||||
|
|
||||||
export const bytedeskHandlers = [
|
export const bytedeskHandlers = [
|
||||||
// Bytedesk API 请求 - 直接 passthrough
|
// 未读消息数量
|
||||||
// 匹配 /bytedesk/* 路径(通过代理访问后端)
|
http.get('/bytedesk/visitor/api/v1/message/unread/count', () => {
|
||||||
|
return HttpResponse.json({
|
||||||
|
code: 200,
|
||||||
|
message: 'success',
|
||||||
|
data: { count: 0 },
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
|
||||||
|
// 其他 Bytedesk API - 返回通用成功响应
|
||||||
http.all('/bytedesk/*', () => {
|
http.all('/bytedesk/*', () => {
|
||||||
return passthrough();
|
return HttpResponse.json({
|
||||||
|
code: 200,
|
||||||
|
message: 'success',
|
||||||
|
data: null,
|
||||||
|
});
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// Bytedesk 外部 CDN/服务请求
|
// Bytedesk 外部 CDN/服务请求
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
// 性能监控工具 - 统计白屏时间和性能指标
|
// 性能监控工具 - 统计白屏时间和性能指标
|
||||||
|
|
||||||
import { logger } from './logger';
|
import { logger } from './logger';
|
||||||
|
import { reportPerformanceMetrics } from '../lib/posthog';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 性能指标接口
|
* 性能指标接口
|
||||||
@@ -208,6 +209,9 @@ class PerformanceMonitor {
|
|||||||
// 性能分析建议
|
// 性能分析建议
|
||||||
this.analyzePerformance();
|
this.analyzePerformance();
|
||||||
|
|
||||||
|
// 上报性能指标到 PostHog
|
||||||
|
reportPerformanceMetrics(this.metrics);
|
||||||
|
|
||||||
return this.metrics;
|
return this.metrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user