Files
vf_react/craco.config.js
zdl e61090810b Merge branch 'feature_2025/251117_pref' into feature_2025/251121_h5UI
* feature_2025/251117_pref: (159 commits)
  feat: UI调整
  feat: 将滚动事件移东到组件内部
  feat: 去掉背景组件
  feat: 拆分左侧栏、中间聊天区、右侧栏组件, Hooks 提取
  feat: 简化主组件 index.js - 使用组件组合方式重构
  feat: 创建 ChatArea 组件(含 MessageRenderer、ExecutionStepsDisplay 子组件)
  feat:拆分工具函数
  feat: 拆分BackgroundEffects 背景渐变装饰层
  feat: RightSidebar (~420 行) - 模型/工具/统计 Tab 面板(单文件)
  feat:  LeftSidebar (~280 行) - 对话历史列表 + 用户信息卡片
  feat: 修复bug
  pref:移除黑夜模式
  feat: 修复警告
  feat: 提取常量配置
  feat: 修复ts报错
  feat:  StockChartModal.tsx 替换 KLine 实现
  update pay function
  update pay function
  update pay function
  update pay function
  ...
2025-11-24 16:32:24 +08:00

317 lines
12 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const path = require('path');
const webpack = require('webpack');
const { BundleAnalyzerPlugin } = process.env.ANALYZE ? require('webpack-bundle-analyzer') : { BundleAnalyzerPlugin: null };
// 检查是否为 Mock 模式(与 src/utils/apiConfig.js 保持一致)
const isMockMode = () => process.env.REACT_APP_ENABLE_MOCK === 'true';
module.exports = {
webpack: {
configure: (webpackConfig, { env, paths }) => {
// ============== 持久化缓存配置 ==============
// 大幅提升二次构建速度(可提升 50-80%
webpackConfig.cache = {
type: 'filesystem',
cacheDirectory: path.resolve(__dirname, 'node_modules/.cache/webpack'),
buildDependencies: {
config: [__filename],
},
// 增加缓存有效性检查
name: env === 'production' ? 'production' : 'development',
compression: env === 'production' ? 'gzip' : false,
};
// ============== 生产环境优化 ==============
if (env === 'production') {
// 高级代码分割策略
webpackConfig.optimization = {
...webpackConfig.optimization,
splitChunks: {
chunks: 'all',
maxInitialRequests: 30,
minSize: 20000,
maxSize: 512000, // 限制单个 chunk 最大大小512KB与 performance.maxAssetSize 一致)
cacheGroups: {
// React 核心库单独分离
react: {
test: /[\\/]node_modules[\\/](react|react-dom|react-router-dom)[\\/]/,
name: 'react-vendor',
priority: 30,
reuseExistingChunk: true,
},
// TradingView Lightweight Charts 单独分离(避免被压缩破坏)
lightweightCharts: {
test: /[\\/]node_modules[\\/]lightweight-charts[\\/]/,
name: 'lightweight-charts',
priority: 26,
reuseExistingChunk: true,
},
// 大型图表库分离echarts, d3, apexcharts 等)
charts: {
test: /[\\/]node_modules[\\/](echarts|echarts-for-react|apexcharts|react-apexcharts|recharts|d3|d3-.*)[\\/]/,
name: 'charts-lib',
priority: 25,
reuseExistingChunk: true,
},
// Chakra UI 框架
chakraUI: {
test: /[\\/]node_modules[\\/](@chakra-ui|@emotion)[\\/]/,
name: 'chakra-ui',
priority: 23, // 从 22 改为 23避免与 antd 优先级冲突
reuseExistingChunk: true,
},
// Ant Design
antd: {
test: /[\\/]node_modules[\\/](antd|@ant-design)[\\/]/,
name: 'antd-lib',
priority: 22,
reuseExistingChunk: true,
},
// 3D 库three.js
three: {
test: /[\\/]node_modules[\\/](three|@react-three)[\\/]/,
name: 'three-lib',
priority: 20,
reuseExistingChunk: true,
},
// 日期/日历库
calendar: {
test: /[\\/]node_modules[\\/](dayjs|date-fns|@fullcalendar)[\\/]/,
name: 'calendar-lib',
priority: 18,
reuseExistingChunk: true,
},
// 其他第三方库
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10,
reuseExistingChunk: true,
},
// 公共代码
common: {
minChunks: 2,
priority: 5,
reuseExistingChunk: true,
name: 'common',
},
},
},
// 优化运行时代码
runtimeChunk: 'single',
// 使用确定性的模块 ID
moduleIds: 'deterministic',
// 最小化配置
minimize: true,
minimizer: [
...webpackConfig.optimization.minimizer,
],
};
// 配置 Terser 插件,保留 lightweight-charts 的方法名
const TerserPlugin = require('terser-webpack-plugin');
webpackConfig.optimization.minimizer = webpackConfig.optimization.minimizer.map(plugin => {
if (plugin.constructor.name === 'TerserPlugin') {
const originalOptions = plugin.options || {};
const originalTerserOptions = originalOptions.terserOptions || {};
const originalMangle = originalTerserOptions.mangle || {};
// 只保留 TerserPlugin 有效的配置项
const validOptions = {
test: originalOptions.test,
include: originalOptions.include,
exclude: originalOptions.exclude,
extractComments: originalOptions.extractComments,
parallel: originalOptions.parallel,
minify: originalOptions.minify,
terserOptions: {
...originalTerserOptions,
keep_classnames: /^(IChartApi|ISeriesApi|Re)$/, // 保留 lightweight-charts 的类名
keep_fnames: /^(createChart|addLineSeries|addSeries)$/, // 保留关键方法名
mangle: {
...originalMangle,
reserved: ['createChart', 'addLineSeries', 'addSeries', 'IChartApi', 'ISeriesApi'],
},
},
};
return new TerserPlugin(validOptions);
}
return plugin;
});
// 生产环境禁用 source map 以加快构建(可节省 40-60% 时间)
webpackConfig.devtool = false;
} else {
// 开发环境使用更快的 source map
webpackConfig.devtool = 'eval-cheap-module-source-map';
}
// ============== 模块解析优化 ==============
webpackConfig.resolve = {
...webpackConfig.resolve,
alias: {
...webpackConfig.resolve.alias,
// 根目录别名
'@': path.resolve(__dirname, 'src'),
// 功能模块别名(按字母顺序)
'@assets': path.resolve(__dirname, 'src/assets'),
'@components': path.resolve(__dirname, 'src/components'),
'@constants': path.resolve(__dirname, 'src/constants'),
'@contexts': path.resolve(__dirname, 'src/contexts'),
'@data': path.resolve(__dirname, 'src/data'),
'@hooks': path.resolve(__dirname, 'src/hooks'),
'@layouts': path.resolve(__dirname, 'src/layouts'),
'@lib': path.resolve(__dirname, 'src/lib'),
'@mocks': path.resolve(__dirname, 'src/mocks'),
'@providers': path.resolve(__dirname, 'src/providers'),
'@routes': path.resolve(__dirname, 'src/routes'),
'@services': path.resolve(__dirname, 'src/services'),
'@store': path.resolve(__dirname, 'src/store'),
'@styles': path.resolve(__dirname, 'src/styles'),
'@theme': path.resolve(__dirname, 'src/theme'),
'@utils': path.resolve(__dirname, 'src/utils'),
'@variables': path.resolve(__dirname, 'src/variables'),
'@views': path.resolve(__dirname, 'src/views'),
},
// 减少文件扩展名搜索(优先 TypeScript
extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
// 优化模块查找路径
modules: [
path.resolve(__dirname, 'src'),
'node_modules'
],
// 优化符号链接解析
symlinks: false,
};
// ============== 插件优化 ==============
// 移除 ESLint 插件以提升构建速度(可提升 20-30%
webpackConfig.plugins = webpackConfig.plugins.filter(
plugin => plugin.constructor.name !== 'ESLintWebpackPlugin'
);
// 添加打包分析工具(通过 ANALYZE=true 启用)
if (env === 'production' && process.env.ANALYZE && BundleAnalyzerPlugin) {
webpackConfig.plugins.push(
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: true,
reportFilename: 'bundle-report.html',
})
);
}
// Day.js 的语言包非常小(每个约 0.5KB),所以不需要特别忽略
// 如果需要优化,可以只导入需要的语言包
// ============== Loader 优化 ==============
const babelLoaderRule = webpackConfig.module.rules.find(
rule => rule.oneOf
);
if (babelLoaderRule && babelLoaderRule.oneOf) {
babelLoaderRule.oneOf.forEach(rule => {
// 优化 Babel Loader
if (rule.loader && rule.loader.includes('babel-loader')) {
rule.options = {
...rule.options,
cacheDirectory: true,
cacheCompression: false,
compact: env === 'production',
};
// 限制 Babel 处理范围
rule.include = path.resolve(__dirname, 'src');
rule.exclude = /node_modules/;
}
// 优化 CSS Loader
if (rule.use && Array.isArray(rule.use)) {
rule.use.forEach(loader => {
if (loader.loader && loader.loader.includes('css-loader') && loader.options) {
loader.options.sourceMap = env !== 'production';
}
});
}
});
}
// ============== 性能提示配置 ==============
webpackConfig.performance = {
hints: env === 'production' ? 'warning' : false,
maxEntrypointSize: 512000, // 512KB
maxAssetSize: 512000,
};
return webpackConfig;
},
},
// ============== Babel 配置优化 ==============
babel: {
plugins: [
// 运行时辅助函数复用
['@babel/plugin-transform-runtime', {
regenerator: true,
useESModules: true,
}],
],
loaderOptions: {
cacheDirectory: true,
cacheCompression: false,
},
},
// ============== 开发服务器配置 ==============
devServer: {
hot: true,
port: 3000,
compress: true,
client: {
overlay: false,
progress: true,
},
// 优化开发服务器性能
devMiddleware: {
writeToDisk: false,
},
// 调试日志
onListening: (devServer) => {
console.log(`[CRACO] Mock Mode: ${isMockMode() ? 'Enabled ✅' : 'Disabled ❌'}`);
console.log(`[CRACO] Proxy: ${isMockMode() ? 'Disabled (MSW intercepts)' : 'Enabled (forwarding to backend)'}`);
},
// 代理配置:将 /api 请求代理到后端服务器
// 注意Mock 模式下禁用 /api 和 /concept-api让 MSW 拦截请求
// 但 /bytedesk 始终启用(客服系统不走 Mock
proxy: {
'/bytedesk': {
target: 'https://valuefrontier.cn', // 统一使用生产环境 Nginx 代理
changeOrigin: true,
secure: false, // 开发环境禁用 HTTPS 严格验证
logLevel: 'debug',
ws: true, // 支持 WebSocket
// 不使用 pathRewrite保留 /bytedesk 前缀,让生产 Nginx 处理
},
// Mock 模式下禁用其他代理
...(isMockMode() ? {} : {
'/api': {
target: 'http://49.232.185.254:5001',
changeOrigin: true,
secure: false,
logLevel: 'debug',
},
'/concept-api': {
target: 'http://49.232.185.254:6801',
changeOrigin: true,
secure: false,
logLevel: 'debug',
pathRewrite: { '^/concept-api': '' },
},
}),
},
},
};