在如今ssr大行其道的场景下,市面上还是有很多有需要维护和优化的陈旧SPA项目,今天我们就研究下这些项目的优化方案之一--splitChunk分包 我们知道,SPA设计的初衷是单页面应用体验,这理念主要包括:
- 单次加载全部资源
- 页面切换无刷新
- 应用状态保持连贯
而在我们应用splitChunk分包之后:
- 按需加载导致路由切换时需要加载新 chunk
- 首次加载虽快,但后续导航可能出现延迟
- 打破了"一次性加载所有资源"的特性
看似,这两个理念有冲突,这对开发来说,都是涉及用户体验的一种抉择,当然,最终的无缝单页面体验肯定是我们追求的,所以目前有几个优化方案可以兼容两者。以下以vue2为例。
1. 基于路由分包
牺牲部分体验:
- 保持核心框架和常用组件在主包
- 按路由分离非关键页面
- 预加载后续路由资源(见下文)
2. 核心/非核心分离
// vue.config.js
module.exports = {
configureWebpack: {
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
core: {
test: /[\\/]node_modules[\\/](vue|vue-router|vuex|core-js)/,
name: 'core',
priority: 10,
chunks: 'initial'
},
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 5,
chunks: 'initial'
}
}
}
}
}
}
3. 预加载
<!-- 自动生成的preload标签 --> <link rel="preload" href="/js/chunk-about.js" as="script">
主动预加载策略:
// 路由配置中添加预加载
{
path: '/about',
component: () => import('./views/About.vue'),
meta: { preload: true } // 自定义标记
}
// 路由守卫中实现预加载
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.preload)) {
const components = to.matched.map(record => record.components.default)
components.forEach(component => {
if (typeof component === 'function') component()
})
}
next()
})
平衡点:用户体验优先
使用了上面的策略,我们的理想状态应达到:
-
首屏极快:主包控制在 100-200KB 以内
-
导航流畅:
- 关键路由预加载
- 非关键路由按需加载+骨架屏
-
缓存优化:
- 长期缓存核心包(文件名带hash)
- 共享公共依赖包
当然,如果项目实在太大,并且优化需求极高,我们还需要进阶优化,那么可以使用以下的方案
1. 按设备能力动态加载
// 根据网络条件动态加载不同资源
const isSlowNetwork = navigator.connection
? navigator.connection.effectiveType.includes('2g')
: false;
const loadVendor = isSlowNetwork
? import('./vendor-light.js')
: import('./vendor-full.js');
2. 渐进式hydration
// 对非关键组件延迟hydration
export default {
components: {
HeavyComponent: () => ({
component: import('./HeavyComponent.vue'),
delay: 2000 // 延迟2秒加载
})
}
}
3. Webpack 魔法注释优化(vue2为例)
// 组合使用webpack注释
const Home = () => import(
/* webpackChunkName: "home" */
/* webpackPrefetch: true */
/* webpackPreload: true */
'./views/Home.vue'
)
结论
分包不会真正破坏 SPA 的初衷,当合理使用时:
- 保持了单页面体验:通过预加载和智能缓存
- 优化了实际性能:比单体大包有更好的用户体验
- 平衡了开发体验:仍然保持单代码库的优势
实验下来,优化的关键是要采用预测性加载策略,这提升最大,让用户在感知上仍然是无缝的单页面体验,同时获得分包带来的性能优势。