diff --git a/src/App.js b/src/App.js
index 5667aa3e..88f8b773 100755
--- a/src/App.js
+++ b/src/App.js
@@ -27,19 +27,66 @@ import { PerformancePanel } from './components/PerformancePanel';
import { useGlobalErrorHandler } from './hooks/useGlobalErrorHandler';
// Redux
-import { initializePostHog } from './store/slices/posthogSlice';
+// ⚡ PostHog 延迟加载:移除同步导入,首屏减少 ~180KB
+// import { initializePostHog } from './store/slices/posthogSlice';
import { updateScreenSize } from './store/slices/deviceSlice';
+import { injectReducer } from './store';
// Utils
import { logger } from './utils/logger';
import { performanceMonitor } from './utils/performanceMonitor';
-// PostHog 追踪
-import { trackEvent, trackEventAsync } from '@lib/posthog';
+// ⚡ PostHog 延迟加载:移除同步导入
+// import { trackEvent, trackEventAsync } from '@lib/posthog';
// Contexts
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 - 应用核心内容
* 负责 PostHog 初始化和渲染路由
@@ -53,12 +100,25 @@ function AppContent() {
const pageEnterTimeRef = useRef(Date.now());
const currentPathRef = useRef(location.pathname);
- // 🎯 PostHog Redux 初始化(延迟执行,不阻塞首屏)
+ // 🎯 ⚡ PostHog 延迟加载 + Redux 初始化(首屏不加载 ~180KB)
useEffect(() => {
- // ⚡ 延迟 2 秒初始化 PostHog,确保首屏渲染不被阻塞
- const timer = setTimeout(() => {
- dispatch(initializePostHog());
- logger.info('App', 'PostHog Redux 初始化已触发(延迟 2 秒)');
+ // ⚡ 延迟 2 秒加载 PostHog 模块,确保首屏渲染不被阻塞
+ const timer = setTimeout(async () => {
+ try {
+ 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);
return () => clearTimeout(timer);
@@ -97,8 +157,8 @@ function AppContent() {
if (!hasVisited) {
const urlParams = new URLSearchParams(location.search);
- // ⚡ 使用异步追踪,不阻塞页面渲染
- trackEventAsync('first_visit', {
+ // ⚡ 使用延迟加载的异步追踪,不阻塞页面渲染
+ trackEventLazy('first_visit', {
referrer: document.referrer || 'direct',
utm_source: urlParams.get('utm_source'),
utm_medium: urlParams.get('utm_medium'),
@@ -120,8 +180,8 @@ function AppContent() {
// 只追踪停留时间 > 1 秒的页面(过滤快速跳转)
if (duration > 1) {
- // ⚡ 使用异步追踪,不阻塞页面切换
- trackEventAsync('page_view_duration', {
+ // ⚡ 使用延迟加载的异步追踪,不阻塞页面切换
+ trackEventLazy('page_view_duration', {
path: currentPathRef.current,
duration_seconds: duration,
is_authenticated: isAuthenticated,
diff --git a/src/contexts/AuthContext.js b/src/contexts/AuthContext.js
index 50633641..6ed80ced 100755
--- a/src/contexts/AuthContext.js
+++ b/src/contexts/AuthContext.js
@@ -5,9 +5,58 @@ import { useToast } from '@chakra-ui/react';
import { logger } from '@utils/logger';
import { performanceMonitor } from '@utils/performanceMonitor';
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';
+// ⚡ 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();
@@ -99,8 +148,8 @@ export const AuthProvider = ({ children }) => {
return prevUser;
}
- // ✅ 识别用户身份到 PostHog
- identifyUser(data.user.id, {
+ // ✅ 识别用户身份到 PostHog(延迟加载)
+ identifyUserLazy(data.user.id, {
email: data.user.email,
username: data.user.username,
subscription_tier: data.user.subscription_tier,
@@ -354,8 +403,8 @@ export const AuthProvider = ({ children }) => {
credentials: 'include'
});
- // ✅ 追踪登出事件(必须在 resetUser() 之前,否则会丢失用户身份)
- trackEvent(SPECIAL_EVENTS.USER_LOGGED_OUT, {
+ // ✅ 追踪登出事件(延迟加载,必须在 resetUser() 之前)
+ trackEventLazy(SPECIAL_EVENTS.USER_LOGGED_OUT, {
timestamp: new Date().toISOString(),
user_id: user?.id || null,
session_duration_minutes: user?.session_start
@@ -363,8 +412,8 @@ export const AuthProvider = ({ children }) => {
: null,
});
- // ✅ 重置 PostHog 用户会话
- resetUser();
+ // ✅ 重置 PostHog 用户会话(延迟加载)
+ resetUserLazy();
// 清除本地状态
setUser(null);
diff --git a/src/index.js b/src/index.js
index f6c49045..84dd3555 100755
--- a/src/index.js
+++ b/src/index.js
@@ -7,8 +7,8 @@ import { BrowserRouter as Router } from 'react-router-dom';
import { performanceMonitor } from './utils/performanceMonitor';
performanceMonitor.mark('app-start');
-// 导入 Brainwave 样式(空文件,保留以避免错误)
-import './styles/brainwave.css';
+// ⚡ 已删除 brainwave.css(项目未安装 Tailwind CSS,该文件无效)
+// import './styles/brainwave.css';
// 导入 Select 下拉框颜色修复样式
import './styles/select-fix.css';
diff --git a/src/store/index.js b/src/store/index.js
index cbdaebb6..191439a2 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -1,26 +1,38 @@
// src/store/index.js
-import { configureStore } from '@reduxjs/toolkit';
+import { configureStore, combineReducers } from '@reduxjs/toolkit';
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 stockReducer from './slices/stockSlice';
import authModalReducer from './slices/authModalSlice';
import subscriptionReducer from './slices/subscriptionSlice';
import deviceReducer from './slices/deviceSlice'; // ✅ 设备检测状态管理
-import posthogMiddleware from './middleware/posthogMiddleware';
import { eventsApi } from './api/eventsApi'; // ✅ RTK Query API
+// ⚡ 基础 reducers(首屏必需)
+const staticReducers = {
+ communityData: communityDataReducer,
+ industry: industryReducer, // ✅ 行业分类数据管理
+ stock: stockReducer, // ✅ 股票和事件数据管理
+ authModal: authModalReducer, // ✅ 认证弹窗状态管理
+ subscription: subscriptionReducer, // ✅ 订阅信息状态管理
+ device: deviceReducer, // ✅ 设备检测状态管理(移动端/桌面端)
+ [eventsApi.reducerPath]: eventsApi.reducer, // ✅ RTK Query 事件 API
+};
+
+// ⚡ 动态 reducers 注册表
+const asyncReducers = {};
+
+// ⚡ 创建根 reducer 的工厂函数
+const createRootReducer = () => combineReducers({
+ ...staticReducers,
+ ...asyncReducers,
+});
+
export const store = configureStore({
- reducer: {
- communityData: communityDataReducer,
- posthog: posthogReducer, // ✅ PostHog Redux 状态管理
- industry: industryReducer, // ✅ 行业分类数据管理
- stock: stockReducer, // ✅ 股票和事件数据管理
- authModal: authModalReducer, // ✅ 认证弹窗状态管理
- subscription: subscriptionReducer, // ✅ 订阅信息状态管理
- device: deviceReducer, // ✅ 设备检测状态管理(移动端/桌面端)
- [eventsApi.reducerPath]: eventsApi.reducer, // ✅ RTK Query 事件 API
- },
+ reducer: createRootReducer(),
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
@@ -28,14 +40,27 @@ export const store = configureStore({
ignoredActions: [
'communityData/fetchPopularKeywords/fulfilled',
'communityData/fetchHotEvents/fulfilled',
- 'posthog/trackEvent/fulfilled', // ✅ PostHog 事件追踪
+ 'posthog/trackEvent/fulfilled', // ✅ PostHog 事件追踪(延迟加载后仍需)
'stock/fetchEventStocks/fulfilled',
'stock/fetchStockQuotes/fulfilled',
],
},
})
- .concat(posthogMiddleware) // ✅ PostHog 自动追踪中间件
+ // ⚡ PostHog 中间件延迟加载,首屏不再需要
.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;
diff --git a/src/styles/brainwave.css b/src/styles/brainwave.css
deleted file mode 100644
index 4821c5d2..00000000
--- a/src/styles/brainwave.css
+++ /dev/null
@@ -1,12 +0,0 @@
-/* Tailwind CSS 入口文件 */
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
-
-/* 自定义工具类 */
-@layer utilities {
- /* 毛玻璃效果 */
- .backdrop-blur-xl {
- backdrop-filter: blur(24px);
- }
-}
diff --git a/src/views/Community/index.js b/src/views/Community/index.js
index 72f92d6d..f7e01818 100644
--- a/src/views/Community/index.js
+++ b/src/views/Community/index.js
@@ -1,5 +1,5 @@
// 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 { useSelector, useDispatch } from 'react-redux';
import {
@@ -20,12 +20,14 @@ import {
VStack,
Text,
useBreakpointValue,
+ Skeleton,
} from '@chakra-ui/react';
// 导入组件
import DynamicNewsCard from './components/DynamicNewsCard';
import HotEventsSection from './components/HotEventsSection';
-import HeroPanel from './components/HeroPanel';
+// ⚡ HeroPanel 懒加载:包含 ECharts (~600KB),首屏不需要立即渲染
+const HeroPanel = lazy(() => import('./components/HeroPanel'));
// 导入自定义 Hooks
import { useEventData } from './hooks/useEventData';
@@ -272,8 +274,14 @@ const Community = () => {
)}
- {/* 顶部说明面板:产品介绍 + 沪深指数 + 热门概念词云 */}
-
+ {/* ⚡ 顶部说明面板(懒加载):产品介绍 + 沪深指数 + 热门概念词云 */}
+
+
+
+ }>
+
+
{/* 实时要闻·动态追踪 - 横向滚动 */}