Files
ojnext/scripts/analyze-bundle.js
yuetsh a2617a2625
Some checks failed
Deploy / deploy (push) Has been cancelled
test
2025-09-29 21:44:59 +08:00

177 lines
5.6 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

#!/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 }