构建产物分析技巧
构建产物分析的必要性
Vite.js的构建过程会生成一系列静态资源,理解这些产物的结构和优化方式直接影响应用性能。构建产物分析能帮助开发者发现冗余代码、未使用的依赖以及潜在的优化点。通过分析工具和技术手段,可以精确控制输出结果,提升应用加载速度和运行效率。
构建产物的基本结构
Vite.js默认构建产物通常包含以下目录结构:
dist/
├── assets/
│ ├── index.[hash].js
│ ├── vendor.[hash].js
│ └── [name].[hash].css
├── index.html
└── vite-manifest.json
assets
目录存放经过哈希处理的静态资源,index.html
是入口文件,vite-manifest.json
记录了资源映射关系。例如:
// vite-manifest.json
{
"src/main.js": {
"file": "assets/index.abc123.js",
"src": "src/main.js",
"isEntry": true
}
}
使用rollup-plugin-visualizer分析
安装可视化分析插件:
npm install --save-dev rollup-plugin-visualizer
在vite.config.js
中配置:
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
visualizer({
open: true,
gzipSize: true,
brotliSize: true
})
]
})
构建后会生成交互式图表,展示各模块体积占比。红色区域通常表示需要优化的重点模块。
源代码映射分析
启用sourcemap可以精确追踪代码来源:
// vite.config.js
export default defineConfig({
build: {
sourcemap: true
}
})
在Chrome DevTools的Sources面板中,通过webpack-internal://
协议可以查看原始源代码与生成代码的映射关系。
依赖项体积优化
使用@rollup/plugin-analyzer
分析具体依赖:
import analyze from '@rollup/plugin-analyzer'
export default defineConfig({
plugins: [
analyze({
limit: 20, // 只显示前20大模块
filter: module => /node_modules/.test(module.id)
})
]
})
控制台会输出类似结果:
src/components/HeavyComponent.vue: 45.21KB (12.3%)
node_modules/lodash-es: 38.75KB (10.5%)
动态导入分割策略
通过动态导入自动分割代码块:
// 优化前
import HeavyComponent from './HeavyComponent.vue'
// 优化后
const HeavyComponent = () => import('./HeavyComponent.vue')
在vite.config.js
中配置分割策略:
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
lodash: ['lodash-es'],
chartjs: ['chart.js']
}
}
}
}
})
CSS代码分析
使用critters
插件提取关键CSS:
import critters from 'vite-plugin-critters'
export default defineConfig({
plugins: [
critters({
preload: 'swap',
pruneSource: true
})
]
})
分析CSS覆盖率:
- 在Chrome DevTools的Coverage面板记录
- 刷新页面查看未使用的CSS比例
- 红色标记的规则表示未使用
预构建依赖检查
检查预构建的依赖项:
// vite.config.js
export default defineConfig({
optimizeDeps: {
include: ['lodash-es/debounce'],
exclude: ['jquery']
}
})
通过node_modules/.vite
目录查看预构建结果,或运行:
npx vite --force --debug
构建耗时分析
添加时间测量插件:
export default defineConfig({
plugins: [{
name: 'timing',
configResolved(config) {
const start = Date.now()
config.plugins.push({
name: 'timing-end',
closeBundle() {
console.log(`构建耗时: ${Date.now() - start}ms`)
}
})
}
}]
})
产物哈希策略比较
不同哈希策略对缓存的影响:
export default defineConfig({
build: {
rollupOptions: {
output: {
// 文件哈希策略
entryFileNames: `[name].[hash].js`,
chunkFileNames: `[name].[hash].js`,
assetFileNames: `[name].[hash].[ext]`
}
}
}
})
对比实验:
- 修改单个组件文件 - 只有对应chunk哈希变化
- 修改依赖项 - vendor哈希变化
- 修改配置文件 - 所有entry哈希变化
树摇效果验证
验证Tree-shaking实际效果:
// utils.js
export function used() { /*...*/ }
export function unused() { /*...*/ }
// main.js
import { used } from './utils'
构建后检查产物中是否存在unused
函数。添加/*#__PURE__*/
标记帮助摇树优化:
export const foo = /*#__PURE__*/ createComplexObject()
服务端渲染产物分析
SSR构建的特殊配置:
export default defineConfig({
build: {
ssr: true,
rollupOptions: {
input: 'src/entry-server.js',
output: {
format: 'cjs'
}
}
}
})
分析SSR包时需要关注:
- Node.js原生模块使用情况
- 服务端特有的依赖项
- 客户端-服务端代码同步问题
自定义分析报告生成
编写自定义分析脚本:
// analyze.js
import fs from 'fs'
import { resolve } from 'path'
const stats = JSON.parse(
fs.readFileSync(resolve('./dist/stats.json'))
)
function findLargeFiles(threshold = 1024 * 50) {
return stats.assets
.filter(asset => asset.size > threshold)
.sort((a, b) => b.size - a.size)
}
console.log('大于50KB的资源:', findLargeFiles())
添加到package.json:
{
"scripts": {
"analyze": "vite build && node analyze.js"
}
}
构建缓存分析
检查缓存命中率:
# 清除缓存
rm -rf node_modules/.vite
# 首次构建
time vite build
# 二次构建
time vite build
比较两次构建时间差异。缓存文件位于:
node_modules/.vite
- 预构建缓存node_modules/.cache
- 其他工具缓存
多环境构建对比
比较不同环境的产物差异:
// vite.config.js
export default defineConfig(({ mode }) => {
return {
build: {
minify: mode === 'production',
sourcemap: mode !== 'production'
}
}
})
生成差异报告:
diff -r dist-development dist-production | grep -vE '\.map$|\.html$'
第三方插件影响评估
评估插件对构建的影响:
- 基准测试无插件构建
- 逐个添加插件并记录:
- 构建时间变化
- 产物体积变化
- 资源数量变化
// 测量插件影响
const withPlugins = [
vue(),
vueJsx(),
legacy()
]
export default defineConfig(async () => {
const configs = await Promise.all(
withPlugins.map(async (plugin, i) => {
const start = Date.now()
await build({
plugins: withPlugins.slice(0, i + 1)
})
return {
plugin: plugin.name,
time: Date.now() - start
}
})
)
console.table(configs)
})
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:TypeScript相关错误处理
下一篇:代码优化技巧