一. 什么是Code Splitting?
在最开始使用Webpack的时候, 都是将所有的js文件全部打包到一个build.js
文件中(文件名取决与在webpack.config.js
文件中output.filename
), 但是在大型项目中, build.js
可能过大, 导致页面加载时间过长. 这个时候就需要code splitting
, code splitting
就是将文件分割成块(chunk)
, 我们可以定义一些分割点(split point)
, 根据这些分割点对文件进行分块, 并实现按需加载.
二. Code Splitting的作用?
-
第三方类库单独打包:
由于第三方类库的内容基本不会改变, 可以将其与业务代码分离出来, 这样就可以最大化的利用浏览器的缓存机制, 减少请求. -
按需加载:
Webpack支持定义分割点, 通过require.ensure
进行按需加载.
三. 如何进行Code Splitting?
下面的代码是基于vue-cli
的webpack-simple
模板生成的演示文档
//cmd
vue init webpack-simple code_spliting_demo
复制代码
(一) 第三方类库单独打包
我们假设项目中引入了jquery.js
和respond.js
, 那么我们可以在webpack.config.js
中配置多入口来进行将这两个第三方类库单独打包.
-
在
webpack.config.js
进行配置//webpack.config.js //在entry中添加相应第三方类库 entry: { bundle: './src/main.js', vendor: ['./src/lib/jquery-1.10.2.min.js', './src/lib/respond.min.js'] } //在plugins中添加CommonChunkPlugin plugins:[ new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.bundle.js' }) ] 复制代码
-
执行
npm run build
, 此时dist
目录下生成了两个文件, 分别是build.js
和vendor.bundle.js
npm run build后的生成文件 -
在
index.html
中引入, 注意:vendor.bundle.js
优先于build.js
引入//index.html <script src="/dist/vendor.bundle.js"></script> <script src="/dist/build.js"></script> 复制代码
(二) 按需加载
我们可以在router
中进行配置, 实现组件的按需加载, 在一些单个组件文件较大的时候, 采用按需加载能够减少build.js
的体积, 优化加载速度(如果组件的体积较小, 那么采用按需加载会增加额外的http请求
, 反倒增加了加载时间)
-
这里, 我们增加3个组件,分别是
A.vue
,B.vue
,C.vue
//A.vue <template> <h1>这里是A.vue组件</h1> </template> //B.vue <template> <h1>这里是B.vue组件</h1> </template> //C.vue <template> <h1>这里是C.vue组件</h1> </template> 复制代码
-
在路由中进行配置 (注意:这里是为了方便, 是在
app.js
中添加的路由, 在实际的项目中, 路由应该单独抽取出来)//app.js import Vue from 'vue' import App from './App.vue' import VueRouter from 'vue-router' Vue.use(VueRouter) //AMD规范的异步载入 const ComA = resolve => require(['./components/A.vue' ], resolve); const ComB = resolve => require(['./components/B.vue' ], resolve); const ComC = resolve => require(['./components/C.vue' ], resolve); const router = new VueRouter({ routes: [ { name: 'component-A', path: '/a', component: ComA }, { name: 'component-B', path: '/b', component: ComB }, { name: 'component-C', path: '/c', component: ComC } ] }) new Vue({ el: '#app', router: router, render: h => h(App) }) 复制代码
-
在
webpack.config.js
中进行配置output.chunkFilename
,
//webpack.config.js
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js',
//添加chundkFilename
chunkFilename: '[name].[chunkhash:5].chunk.js'
}
复制代码
-
执行
npm run build
, 此时dist
目录下生成了5个文件, 多出的3个文件,就是对应的A.vue
,B.vue
,C.vue
这三个组件npm run build后生成的文件
CMD规范的异步载入
刚才在路由引入的时候, 使用的是AMD规范
的异步载入. webpack
提供了require.ensure()
这个方法实现CMD规范
的异步载入. 这同样也是webpack
推荐的载入方式.想深入了解ensure
, 请点击《webpack代码分离 ensure 看了还不懂,你打我》
- 下面的代码是使用
require.ensure()
方法对路由进行配置
//app.js
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
//AMD风格的异步加载
// const ComA = resolve => require(['./components/A.vue' ], resolve);
// const ComB = resolve => require(['./components/B.vue' ], resolve);
// const ComC = resolve => require(['./components/C.vue' ], resolve);
//CMD风格的异步加载
const ComA = resolve => require.ensure([], () => resolve(require('./components/A.vue')));
const ComB = resolve => require.ensure([], () => resolve(require('./components/B.vue')));
const ComC = resolve => require.ensure([], () => resolve(require('./components/C.vue')));
const router = new VueRouter({
routes: [
{
name: 'component-A',
path: '/a',
component: ComA
},
{
name: 'component-B',
path: '/b',
component: ComB
},
{
name: 'component-C',
path: '/c',
component: ComC
}
]
})
new Vue({
el: '#app',
router: router,
render: h => h(App)
})
复制代码
- 执行
npm run build
后,dist
目录下同样生成5个文件npm run build后生成的文件
-
按需加载效果演示:按需加载效果演示