test
Some checks failed
Deploy / deploy (push) Has been cancelled

This commit is contained in:
2025-09-29 21:44:59 +08:00
parent ad7ea92769
commit a2617a2625
7 changed files with 716 additions and 188 deletions

176
scripts/analyze-bundle.js Normal file
View File

@@ -0,0 +1,176 @@
#!/usr/bin/env node
/**
* Bundle 分析脚本
* 用于分析 Naive UI 组件的打包情况和优化建议
*/
import { execSync } from 'child_process'
import { readFileSync, writeFileSync } from 'fs'
import { resolve } from 'path'
const DIST_PATH = resolve(process.cwd(), 'dist')
const ANALYSIS_OUTPUT = resolve(process.cwd(), 'bundle-analysis.json')
/**
* 分析打包结果
*/
function analyzeBundleSize() {
console.log('🔍 开始分析打包结果...')
try {
// 构建生产版本
console.log('📦 构建生产版本...')
execSync('npm run build', { stdio: 'inherit' })
// 获取文件大小信息
const result = execSync(`find ${DIST_PATH} -name "*.js" -o -name "*.css" | xargs ls -la`,
{ encoding: 'utf-8' })
const files = result.split('\n')
.filter(line => line.trim())
.map(line => {
const parts = line.split(/\s+/)
const size = parseInt(parts[4])
const name = parts[parts.length - 1].replace(DIST_PATH + '/', '')
return { name, size, sizeKB: Math.round(size / 1024 * 100) / 100 }
})
.filter(file => file.size > 0)
.sort((a, b) => b.size - a.size)
// 分析 Naive UI 相关文件
const naiveUIFiles = files.filter(file =>
file.name.includes('naive-ui') ||
file.name.includes('naive')
)
const totalSize = files.reduce((sum, file) => sum + file.size, 0)
const naiveUISize = naiveUIFiles.reduce((sum, file) => sum + file.size, 0)
const analysis = {
timestamp: new Date().toISOString(),
totalFiles: files.length,
totalSizeKB: Math.round(totalSize / 1024 * 100) / 100,
naiveUIFiles: naiveUIFiles.length,
naiveUISizeKB: Math.round(naiveUISize / 1024 * 100) / 100,
naiveUIPercentage: Math.round(naiveUISize / totalSize * 100 * 100) / 100,
files: files.slice(0, 20), // 只保留前20个最大的文件
naiveUIFiles: naiveUIFiles,
recommendations: generateRecommendations(files, naiveUIFiles, totalSize)
}
// 保存分析结果
writeFileSync(ANALYSIS_OUTPUT, JSON.stringify(analysis, null, 2))
// 输出分析报告
printAnalysisReport(analysis)
} catch (error) {
console.error('❌ 分析失败:', error.message)
process.exit(1)
}
}
/**
* 生成优化建议
*/
function generateRecommendations(allFiles, naiveUIFiles, totalSize) {
const recommendations = []
// 检查是否有过大的单个文件
const largeFiles = allFiles.filter(file => file.size > 500 * 1024) // 大于500KB
if (largeFiles.length > 0) {
recommendations.push({
type: 'warning',
title: '发现大文件',
description: `${largeFiles.length} 个文件超过 500KB建议进一步拆分`,
files: largeFiles.map(f => f.name)
})
}
// 检查 Naive UI 占比
const naiveUIPercentage = naiveUIFiles.reduce((sum, file) => sum + file.size, 0) / totalSize * 100
if (naiveUIPercentage > 30) {
recommendations.push({
type: 'info',
title: 'Naive UI 占比较高',
description: `Naive UI 组件占总包体积的 ${Math.round(naiveUIPercentage)}%,可以考虑更精细的按需引入`,
suggestion: '使用 tree-shaking 或更细粒度的组件拆分'
})
}
// 检查是否有重复的组件
const duplicatePattern = /naive-ui.*\.(js|css)$/
const duplicates = allFiles.filter(file => duplicatePattern.test(file.name))
if (duplicates.length > 5) {
recommendations.push({
type: 'warning',
title: '可能存在组件重复',
description: '发现多个 Naive UI 相关文件,可能存在重复打包',
suggestion: '检查 webpack 配置中的 splitChunks 设置'
})
}
// 检查 CSS 文件大小
const cssFiles = allFiles.filter(file => file.name.endsWith('.css'))
const largeCSSFiles = cssFiles.filter(file => file.size > 100 * 1024) // 大于100KB
if (largeCSSFiles.length > 0) {
recommendations.push({
type: 'info',
title: 'CSS 文件较大',
description: '发现较大的 CSS 文件,可以考虑按需加载样式',
files: largeCSSFiles.map(f => f.name)
})
}
return recommendations
}
/**
* 打印分析报告
*/
function printAnalysisReport(analysis) {
console.log('\n📊 Bundle 分析报告')
console.log('='.repeat(50))
console.log(`📁 总文件数: ${analysis.totalFiles}`)
console.log(`📦 总大小: ${analysis.totalSizeKB} KB`)
console.log(`🎨 Naive UI 文件数: ${analysis.naiveUIFiles.length}`)
console.log(`🎨 Naive UI 大小: ${analysis.naiveUISizeKB} KB (${analysis.naiveUIPercentage}%)`)
console.log('\n📋 最大的文件:')
analysis.files.slice(0, 10).forEach((file, index) => {
console.log(`${index + 1}. ${file.name}: ${file.sizeKB} KB`)
})
if (analysis.naiveUIFiles.length > 0) {
console.log('\n🎨 Naive UI 相关文件:')
analysis.naiveUIFiles.forEach((file, index) => {
console.log(`${index + 1}. ${file.name}: ${file.sizeKB} KB`)
})
}
if (analysis.recommendations.length > 0) {
console.log('\n💡 优化建议:')
analysis.recommendations.forEach((rec, index) => {
const icon = rec.type === 'warning' ? '⚠️' : ''
console.log(`${icon} ${index + 1}. ${rec.title}`)
console.log(` ${rec.description}`)
if (rec.suggestion) {
console.log(` 建议: ${rec.suggestion}`)
}
if (rec.files) {
console.log(` 文件: ${rec.files.join(', ')}`)
}
console.log('')
})
}
console.log(`\n💾 详细分析结果已保存到: ${ANALYSIS_OUTPUT}`)
}
// 运行分析
if (import.meta.url === `file://${process.argv[1]}`) {
analyzeBundleSize()
}
export { analyzeBundleSize }