feat: 优化构建速度和包大小

This commit is contained in:
zdl
2025-10-13 16:01:17 +08:00
parent 0792a57e6f
commit fae8ef10b1
4 changed files with 447 additions and 6 deletions

223
craco.config.js Normal file
View File

@@ -0,0 +1,223 @@
const path = require('path');
const webpack = require('webpack');
const { BundleAnalyzerPlugin } = process.env.ANALYZE ? require('webpack-bundle-analyzer') : { BundleAnalyzerPlugin: null };
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: 244000, // 限制单个 chunk 最大大小(约 244KB
cacheGroups: {
// React 核心库单独分离
react: {
test: /[\\/]node_modules[\\/](react|react-dom|react-router-dom)[\\/]/,
name: 'react-vendor',
priority: 30,
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: 22,
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[\\/](moment|date-fns|@fullcalendar|react-big-calendar)[\\/]/,
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,
};
// 生产环境禁用 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'),
'@components': path.resolve(__dirname, 'src/components'),
'@views': path.resolve(__dirname, 'src/views'),
'@assets': path.resolve(__dirname, 'src/assets'),
'@contexts': path.resolve(__dirname, 'src/contexts'),
},
// 减少文件扩展名搜索
extensions: ['.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',
})
);
}
// 忽略 moment 的语言包(如果项目使用了 moment
webpackConfig.plugins.push(
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/locale$/,
contextRegExp: /moment$/,
})
);
// ============== 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,
},
},
};