const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer') const webpack = require('webpack') const path = require('path') const fs = require('fs') // 获取webpack配置 const webpackConfig = require('../webpack.config.js') // 添加分析插件 const analyzeConfig = { ...webpackConfig, plugins: [ ...webpackConfig.plugins, new BundleAnalyzerPlugin({ analyzerMode: 'static', reportFilename: 'bundle-report.html', openAnalyzer: true, generateStatsFile: true, statsFilename: 'bundle-stats.json', statsOptions: null, logLevel: 'info' }) ] } // 运行分析 console.log('🔍 开始分析打包结果...') webpack(analyzeConfig, (err, stats) => { if (err) { console.error('❌ 分析失败:', err) return } if (stats.hasErrors()) { console.error('❌ 构建过程中出现错误:') stats.compilation.errors.forEach(error => { console.error(error) }) return } console.log('✅ 分析完成!') console.log('📊 报告文件已生成:') console.log(' - bundle-report.html (可视化报告)') console.log(' - bundle-stats.json (详细统计)') // 生成简单的性能报告 const statsData = stats.toJson() const report = generatePerformanceReport(statsData) fs.writeFileSync( path.join(__dirname, '../performance-report.md'), report, 'utf8' ) console.log(' - performance-report.md (性能报告)') }) function generatePerformanceReport(stats) { const assets = stats.assets || [] const chunks = stats.chunks || [] const modules = stats.modules || [] // 按类型分组资源 const assetsByType = { js: assets.filter(asset => asset.name.endsWith('.js')), css: assets.filter(asset => asset.name.endsWith('.css')), images: assets.filter(asset => /\.(png|jpg|jpeg|gif|svg|webp)$/.test(asset.name)), fonts: assets.filter(asset => /\.(woff|woff2|eot|ttf|otf)$/.test(asset.name)), other: assets.filter(asset => !asset.name.endsWith('.js') && !asset.name.endsWith('.css') && !/\.(png|jpg|jpeg|gif|svg|webp|woff|woff2|eot|ttf|otf)$/.test(asset.name) ) } // 计算总大小 const totalSize = assets.reduce((sum, asset) => sum + asset.size, 0) const jsSize = assetsByType.js.reduce((sum, asset) => sum + asset.size, 0) const cssSize = assetsByType.css.reduce((sum, asset) => sum + asset.size, 0) // 生成报告 const report = `# 性能分析报告 ## 📊 构建统计 - **总文件数**: ${assets.length} - **总大小**: ${formatBytes(totalSize)} - **JS文件**: ${assetsByType.js.length} 个,${formatBytes(jsSize)} - **CSS文件**: ${assetsByType.css.length} 个,${formatBytes(cssSize)} - **图片文件**: ${assetsByType.images.length} 个 - **字体文件**: ${assetsByType.fonts.length} 个 - **其他文件**: ${assetsByType.other.length} 个 ## 🎯 主要JS文件 ${assetsByType.js .sort((a, b) => b.size - a.size) .slice(0, 10) .map(asset => `- **${asset.name}**: ${formatBytes(asset.size)}`) .join('\n')} ## 🎨 CSS文件 ${assetsByType.css .sort((a, b) => b.size - a.size) .map(asset => `- **${asset.name}**: ${formatBytes(asset.size)}`) .join('\n')} ## 📦 Chunk分析 ${chunks .sort((a, b) => b.size - a.size) .slice(0, 10) .map(chunk => `- **${chunk.names.join(', ')}**: ${formatBytes(chunk.size)}`) .join('\n')} ## 🔍 大文件警告 ${assets .filter(asset => asset.size > 1024 * 1024) // 1MB以上 .sort((a, b) => b.size - a.size) .map(asset => `- ⚠️ **${asset.name}**: ${formatBytes(asset.size)} (建议优化)`) .join('\n') || '✅ 没有超过1MB的文件'} ## 📈 性能建议 ### 🚀 已实施的优化 - ✅ 代码分割 (${chunks.length} 个chunk) - ✅ 资源压缩 - ✅ 缓存策略 - ✅ 预加载关键资源 ### 🎯 进一步优化建议 ${generateOptimizationSuggestions(assets, chunks)} --- *报告生成时间: ${new Date().toLocaleString()}* ` return report } function generateOptimizationSuggestions(assets, chunks) { const suggestions = [] // 检查大文件 const largeFiles = assets.filter(asset => asset.size > 500 * 1024) // 500KB以上 if (largeFiles.length > 0) { suggestions.push('- 考虑进一步分割大文件或使用动态导入') } // 检查chunk数量 if (chunks.length > 20) { suggestions.push('- Chunk数量较多,考虑合并相关功能') } // 检查图片优化 const images = assets.filter(asset => /\.(png|jpg|jpeg|gif|svg)$/.test(asset.name)) const largeImages = images.filter(asset => asset.size > 100 * 1024) // 100KB以上 if (largeImages.length > 0) { suggestions.push('- 优化大图片,考虑使用WebP格式') } if (suggestions.length === 0) { suggestions.push('- 当前配置已经相当优化!') } return suggestions.join('\n') } function formatBytes(bytes) { if (bytes === 0) return '0 Bytes' const k = 1024 const sizes = ['Bytes', 'KB', 'MB', 'GB'] const i = Math.floor(Math.log(bytes) / Math.log(k)) return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i] }