pref: P0: PostHog 延迟加载 - 完成

P0: HeroPanel 懒加载 -  完成
 P0/P1: Charts/FullCalendar 懒加载 -  已通过路由懒加载隔离,无需额外处理
删除空的 CSS 文件
This commit is contained in:
zdl
2025-11-26 13:33:58 +08:00
parent 3507cfe9f7
commit 1d1d6c8169
6 changed files with 182 additions and 52 deletions

View File

@@ -27,19 +27,66 @@ import { PerformancePanel } from './components/PerformancePanel';
import { useGlobalErrorHandler } from './hooks/useGlobalErrorHandler'; import { useGlobalErrorHandler } from './hooks/useGlobalErrorHandler';
// Redux // Redux
import { initializePostHog } from './store/slices/posthogSlice'; // ⚡ PostHog 延迟加载:移除同步导入,首屏减少 ~180KB
// import { initializePostHog } from './store/slices/posthogSlice';
import { updateScreenSize } from './store/slices/deviceSlice'; import { updateScreenSize } from './store/slices/deviceSlice';
import { injectReducer } from './store';
// Utils // Utils
import { logger } from './utils/logger'; import { logger } from './utils/logger';
import { performanceMonitor } from './utils/performanceMonitor'; import { performanceMonitor } from './utils/performanceMonitor';
// PostHog 追踪 // PostHog 延迟加载:移除同步导入
import { trackEvent, trackEventAsync } from '@lib/posthog'; // import { trackEvent, trackEventAsync } from '@lib/posthog';
// Contexts // Contexts
import { useAuth } from '@contexts/AuthContext'; import { useAuth } from '@contexts/AuthContext';
// ⚡ PostHog 延迟加载模块(动态导入后缓存)
let posthogModule = null;
let posthogSliceModule = null;
/**
* ⚡ 延迟加载 PostHog 模块
* 返回 { trackEvent, trackEventAsync, initializePostHog, posthogReducer }
*/
const loadPostHogModules = async () => {
if (posthogModule && posthogSliceModule) {
return { posthogModule, posthogSliceModule };
}
try {
const [posthog, posthogSlice] = await Promise.all([
import('@lib/posthog'),
import('./store/slices/posthogSlice'),
]);
posthogModule = posthog;
posthogSliceModule = posthogSlice;
return { posthogModule, posthogSliceModule };
} catch (error) {
logger.error('App', 'PostHog 模块加载失败', error);
return null;
}
};
/**
* ⚡ 异步追踪事件(延迟加载 PostHog 后调用)
* @param {string} eventName - 事件名称
* @param {object} properties - 事件属性
*/
const trackEventLazy = async (eventName, properties = {}) => {
// 等待模块加载完成
if (!posthogModule) {
const modules = await loadPostHogModules();
if (!modules) return;
}
// 使用异步追踪,不阻塞主线程
posthogModule.trackEventAsync(eventName, properties);
};
/** /**
* AppContent - 应用核心内容 * AppContent - 应用核心内容
* 负责 PostHog 初始化和渲染路由 * 负责 PostHog 初始化和渲染路由
@@ -53,12 +100,25 @@ function AppContent() {
const pageEnterTimeRef = useRef(Date.now()); const pageEnterTimeRef = useRef(Date.now());
const currentPathRef = useRef(location.pathname); const currentPathRef = useRef(location.pathname);
// 🎯 PostHog Redux 初始化(延迟执行,不阻塞首屏) // 🎯 PostHog 延迟加载 + Redux 初始化(首屏不加载 ~180KB
useEffect(() => { useEffect(() => {
// ⚡ 延迟 2 秒初始化 PostHog确保首屏渲染不被阻塞 // ⚡ 延迟 2 秒加载 PostHog 模块,确保首屏渲染不被阻塞
const timer = setTimeout(() => { const timer = setTimeout(async () => {
dispatch(initializePostHog()); try {
logger.info('App', 'PostHog Redux 初始化已触发(延迟 2 秒)'); const modules = await loadPostHogModules();
if (!modules) return;
const { posthogSliceModule } = modules;
// 动态注入 PostHog reducer
injectReducer('posthog', posthogSliceModule.default);
// 初始化 PostHog
dispatch(posthogSliceModule.initializePostHog());
logger.info('App', 'PostHog 模块延迟加载完成Redux 初始化已触发');
} catch (error) {
logger.error('App', 'PostHog 延迟加载失败', error);
}
}, 2000); }, 2000);
return () => clearTimeout(timer); return () => clearTimeout(timer);
@@ -97,8 +157,8 @@ function AppContent() {
if (!hasVisited) { if (!hasVisited) {
const urlParams = new URLSearchParams(location.search); const urlParams = new URLSearchParams(location.search);
// ⚡ 使用异步追踪,不阻塞页面渲染 // ⚡ 使用延迟加载的异步追踪,不阻塞页面渲染
trackEventAsync('first_visit', { trackEventLazy('first_visit', {
referrer: document.referrer || 'direct', referrer: document.referrer || 'direct',
utm_source: urlParams.get('utm_source'), utm_source: urlParams.get('utm_source'),
utm_medium: urlParams.get('utm_medium'), utm_medium: urlParams.get('utm_medium'),
@@ -120,8 +180,8 @@ function AppContent() {
// 只追踪停留时间 > 1 秒的页面(过滤快速跳转) // 只追踪停留时间 > 1 秒的页面(过滤快速跳转)
if (duration > 1) { if (duration > 1) {
// ⚡ 使用异步追踪,不阻塞页面切换 // ⚡ 使用延迟加载的异步追踪,不阻塞页面切换
trackEventAsync('page_view_duration', { trackEventLazy('page_view_duration', {
path: currentPathRef.current, path: currentPathRef.current,
duration_seconds: duration, duration_seconds: duration,
is_authenticated: isAuthenticated, is_authenticated: isAuthenticated,

View File

@@ -5,9 +5,58 @@ import { useToast } from '@chakra-ui/react';
import { logger } from '@utils/logger'; import { logger } from '@utils/logger';
import { performanceMonitor } from '@utils/performanceMonitor'; import { performanceMonitor } from '@utils/performanceMonitor';
import { useNotification } from '@contexts/NotificationContext'; import { useNotification } from '@contexts/NotificationContext';
import { identifyUser, resetUser, trackEvent } from '@lib/posthog'; // ⚡ PostHog 延迟加载:移除同步导入,首屏减少 ~180KB
// import { identifyUser, resetUser, trackEvent } from '@lib/posthog';
import { SPECIAL_EVENTS } from '@lib/constants'; import { SPECIAL_EVENTS } from '@lib/constants';
// ⚡ PostHog 延迟加载模块(动态导入后缓存)
let posthogModule = null;
/**
* ⚡ 延迟加载 PostHog 模块
*/
const loadPostHogModule = async () => {
if (posthogModule) return posthogModule;
try {
posthogModule = await import('@lib/posthog');
return posthogModule;
} catch (error) {
logger.error('AuthContext', 'PostHog 模块加载失败', error);
return null;
}
};
/**
* ⚡ 延迟调用 identifyUser
*/
const identifyUserLazy = async (userId, userProperties) => {
const module = await loadPostHogModule();
if (module) {
module.identifyUser(userId, userProperties);
}
};
/**
* ⚡ 延迟调用 resetUser
*/
const resetUserLazy = async () => {
const module = await loadPostHogModule();
if (module) {
module.resetUser();
}
};
/**
* ⚡ 延迟调用 trackEvent使用异步版本
*/
const trackEventLazy = async (eventName, properties) => {
const module = await loadPostHogModule();
if (module) {
module.trackEventAsync(eventName, properties);
}
};
// 创建认证上下文 // 创建认证上下文
const AuthContext = createContext(); const AuthContext = createContext();
@@ -99,8 +148,8 @@ export const AuthProvider = ({ children }) => {
return prevUser; return prevUser;
} }
// ✅ 识别用户身份到 PostHog // ✅ 识别用户身份到 PostHog(延迟加载)
identifyUser(data.user.id, { identifyUserLazy(data.user.id, {
email: data.user.email, email: data.user.email,
username: data.user.username, username: data.user.username,
subscription_tier: data.user.subscription_tier, subscription_tier: data.user.subscription_tier,
@@ -354,8 +403,8 @@ export const AuthProvider = ({ children }) => {
credentials: 'include' credentials: 'include'
}); });
// ✅ 追踪登出事件(必须在 resetUser() 之前,否则会丢失用户身份 // ✅ 追踪登出事件(延迟加载,必须在 resetUser() 之前)
trackEvent(SPECIAL_EVENTS.USER_LOGGED_OUT, { trackEventLazy(SPECIAL_EVENTS.USER_LOGGED_OUT, {
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
user_id: user?.id || null, user_id: user?.id || null,
session_duration_minutes: user?.session_start session_duration_minutes: user?.session_start
@@ -363,8 +412,8 @@ export const AuthProvider = ({ children }) => {
: null, : null,
}); });
// ✅ 重置 PostHog 用户会话 // ✅ 重置 PostHog 用户会话(延迟加载)
resetUser(); resetUserLazy();
// 清除本地状态 // 清除本地状态
setUser(null); setUser(null);

View File

@@ -7,8 +7,8 @@ import { BrowserRouter as Router } from 'react-router-dom';
import { performanceMonitor } from './utils/performanceMonitor'; import { performanceMonitor } from './utils/performanceMonitor';
performanceMonitor.mark('app-start'); performanceMonitor.mark('app-start');
// 导入 Brainwave 样式(空文件,保留以避免错误 // ⚡ 已删除 brainwave.css项目未安装 Tailwind CSS该文件无效
import './styles/brainwave.css'; // import './styles/brainwave.css';
// 导入 Select 下拉框颜色修复样式 // 导入 Select 下拉框颜色修复样式
import './styles/select-fix.css'; import './styles/select-fix.css';

View File

@@ -1,26 +1,38 @@
// src/store/index.js // src/store/index.js
import { configureStore } from '@reduxjs/toolkit'; import { configureStore, combineReducers } from '@reduxjs/toolkit';
import communityDataReducer from './slices/communityDataSlice'; import communityDataReducer from './slices/communityDataSlice';
import posthogReducer from './slices/posthogSlice'; // ⚡ PostHog 延迟加载:移除同步导入,首屏减少 ~180KB
// import posthogReducer from './slices/posthogSlice';
// import posthogMiddleware from './middleware/posthogMiddleware';
import industryReducer from './slices/industrySlice'; import industryReducer from './slices/industrySlice';
import stockReducer from './slices/stockSlice'; import stockReducer from './slices/stockSlice';
import authModalReducer from './slices/authModalSlice'; import authModalReducer from './slices/authModalSlice';
import subscriptionReducer from './slices/subscriptionSlice'; import subscriptionReducer from './slices/subscriptionSlice';
import deviceReducer from './slices/deviceSlice'; // ✅ 设备检测状态管理 import deviceReducer from './slices/deviceSlice'; // ✅ 设备检测状态管理
import posthogMiddleware from './middleware/posthogMiddleware';
import { eventsApi } from './api/eventsApi'; // ✅ RTK Query API import { eventsApi } from './api/eventsApi'; // ✅ RTK Query API
export const store = configureStore({ // ⚡ 基础 reducers首屏必需
reducer: { const staticReducers = {
communityData: communityDataReducer, communityData: communityDataReducer,
posthog: posthogReducer, // ✅ PostHog Redux 状态管理
industry: industryReducer, // ✅ 行业分类数据管理 industry: industryReducer, // ✅ 行业分类数据管理
stock: stockReducer, // ✅ 股票和事件数据管理 stock: stockReducer, // ✅ 股票和事件数据管理
authModal: authModalReducer, // ✅ 认证弹窗状态管理 authModal: authModalReducer, // ✅ 认证弹窗状态管理
subscription: subscriptionReducer, // ✅ 订阅信息状态管理 subscription: subscriptionReducer, // ✅ 订阅信息状态管理
device: deviceReducer, // ✅ 设备检测状态管理(移动端/桌面端) device: deviceReducer, // ✅ 设备检测状态管理(移动端/桌面端)
[eventsApi.reducerPath]: eventsApi.reducer, // ✅ RTK Query 事件 API [eventsApi.reducerPath]: eventsApi.reducer, // ✅ RTK Query 事件 API
}, };
// ⚡ 动态 reducers 注册表
const asyncReducers = {};
// ⚡ 创建根 reducer 的工厂函数
const createRootReducer = () => combineReducers({
...staticReducers,
...asyncReducers,
});
export const store = configureStore({
reducer: createRootReducer(),
middleware: (getDefaultMiddleware) => middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({ getDefaultMiddleware({
serializableCheck: { serializableCheck: {
@@ -28,14 +40,27 @@ export const store = configureStore({
ignoredActions: [ ignoredActions: [
'communityData/fetchPopularKeywords/fulfilled', 'communityData/fetchPopularKeywords/fulfilled',
'communityData/fetchHotEvents/fulfilled', 'communityData/fetchHotEvents/fulfilled',
'posthog/trackEvent/fulfilled', // ✅ PostHog 事件追踪 'posthog/trackEvent/fulfilled', // ✅ PostHog 事件追踪(延迟加载后仍需)
'stock/fetchEventStocks/fulfilled', 'stock/fetchEventStocks/fulfilled',
'stock/fetchStockQuotes/fulfilled', 'stock/fetchStockQuotes/fulfilled',
], ],
}, },
}) })
.concat(posthogMiddleware) // PostHog 自动追踪中间件 // PostHog 中间件延迟加载,首屏不再需要
.concat(eventsApi.middleware), // ✅ RTK Query 中间件(自动缓存、去重、重试) .concat(eventsApi.middleware), // ✅ RTK Query 中间件(自动缓存、去重、重试)
}); });
/**
* ⚡ 动态注入 reducer用于延迟加载模块
* @param {string} key - reducer 的键名
* @param {Function} reducer - reducer 函数
*/
export const injectReducer = (key, reducer) => {
if (asyncReducers[key]) {
return; // 已注入,避免重复
}
asyncReducers[key] = reducer;
store.replaceReducer(createRootReducer());
};
export default store; export default store;

View File

@@ -1,12 +0,0 @@
/* Tailwind CSS 入口文件 */
@tailwind base;
@tailwind components;
@tailwind utilities;
/* 自定义工具类 */
@layer utilities {
/* 毛玻璃效果 */
.backdrop-blur-xl {
backdrop-filter: blur(24px);
}
}

View File

@@ -1,5 +1,5 @@
// src/views/Community/index.js // src/views/Community/index.js
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState, lazy, Suspense } from 'react';
import { useNavigate, useLocation } from 'react-router-dom'; import { useNavigate, useLocation } from 'react-router-dom';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import { import {
@@ -20,12 +20,14 @@ import {
VStack, VStack,
Text, Text,
useBreakpointValue, useBreakpointValue,
Skeleton,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
// 导入组件 // 导入组件
import DynamicNewsCard from './components/DynamicNewsCard'; import DynamicNewsCard from './components/DynamicNewsCard';
import HotEventsSection from './components/HotEventsSection'; import HotEventsSection from './components/HotEventsSection';
import HeroPanel from './components/HeroPanel'; // ⚡ HeroPanel 懒加载:包含 ECharts (~600KB),首屏不需要立即渲染
const HeroPanel = lazy(() => import('./components/HeroPanel'));
// 导入自定义 Hooks // 导入自定义 Hooks
import { useEventData } from './hooks/useEventData'; import { useEventData } from './hooks/useEventData';
@@ -272,8 +274,14 @@ const Community = () => {
</Alert> </Alert>
)} )}
{/* 顶部说明面板:产品介绍 + 沪深指数 + 热门概念词云 */} {/* 顶部说明面板(懒加载):产品介绍 + 沪深指数 + 热门概念词云 */}
<Suspense fallback={
<Box mb={6} p={4} borderRadius="xl" bg="rgba(255,255,255,0.02)">
<Skeleton height="200px" borderRadius="lg" startColor="gray.800" endColor="gray.700" />
</Box>
}>
<HeroPanel /> <HeroPanel />
</Suspense>
{/* 实时要闻·动态追踪 - 横向滚动 */} {/* 实时要闻·动态追踪 - 横向滚动 */}
<DynamicNewsCard <DynamicNewsCard