咱们清楚,在 webpack
中经过CommonsChunkPlugin
能够将 entry
的入口文件中引用屡次的文件抽离打包成一个公用文件,从而减小代码重复冗余vue
entry: { main: './src/main.js', user: './src/user.js' }, ...... new webpack.optimize.CommonsChunkPlugin({ name: "commons", filename: 'common.js', minChunks: 2, }) // 打包生成一个文件common.js ,包含main.js 和 user.js 中引用两次及以上的模块代码
那么问题来了,当使用了相似 vue-router
的代码分割+懒加载功能的时候,每一个路由对应的.vue
文件中,共同引用了屡次的模块,要怎么抽离出代码分割模块的公用模块代码出来呢?webpack
举个栗子git
// 懒加载路由文件 routes.js const Index = () => import(/* webpackChunkName: "index" */ "page/index/Index.vue"), User = () => import(/* webpackChunkName: "userIndex" */ "page/user/Index.vue"), UserDetail = () => import(/* webpackChunkName: "userDetail" */ "page/user/Detail.vue"), ...
// page/index/Index.vue 首页路由文件 <template>首页</template> <script> import pub from 'script/public.js' ... </script>
// page/index/Index.vue 用户页路由文件 <template>用户页</template> <script> import pub from 'script/public.js' ... </script>
上述使用了vue-router
懒加载打包出来的 首页路由文件index.js
和 用户页文件userIndex.js
都会包含一份 public.js
的代码,重复了。github
那么问题就是,在代码分割的代码中,怎么自动抽离公共代码? 就像CommonsChunkPlugin
的效果同样,CommonsChunkPlugin
怎么在 code-splitting
的场景上使用呢 ?web
如问题所示,存在两个使用了webpack code-splitting 和 懒加载的路由文件,路由文件都使用了公用的public.js
模块。vue-router
// page/index/Index.vue 首页路由文件 <template>首页</template> <script> import pub from 'script/public' ... </script>
// 用户页 // page/index/Index.vue 用户页路由文件 <template>用户页</template> <script> import pub from 'script/public' ... </script>
要将 public.js
公用模块抽离,有三种解决方案async
CommonsChunkPlugin
具名模块手动将全部共用的模块抽离在一个文件。
建立文件commons.js
ui
// commons.js import pub from 'public'
在webpack.config.js
的CommonsChunkPlugin
插件指定commons
的entrythis
// webpack.config.js entry:{ main: 'src/main.js', commons: 'src/commons.js' }, ... new webpack.optimize.CommonsChunkPlugin({ name: "commons", // 和 entry的commons对应, filename: 'common.bundle.js', // 抽离公共文件 minChunks: Infinity, })
这样,若是路由文件或其余模块使用到了 commons.js
中的模块,都不会重复加载代码,而是在common.bundle.js
中获取。url
CommonsChunkPlugin
设置 children
属性官方文档CommonsChunkPlugin 中 children属性解释
Move common modules into the parent chunk
With Code Splitting, multiple child chunks of an entry chunk can have common dependencies. To prevent duplication these can be moved into the parent. This reduces overall size, but does have a negative effect on the initial load time. If it is expected that users will need to download many sibling chunks, i.e. children of the entry chunk, then this should improve load time overall.
可知,设置 children 为 true 能够将code-splitting的模块的依赖模块抽离到父模块,这样作的后果就是,确实抽离公用模块,下降了代码重复,减小了代码体积。可是同时,抽离到父模块,也意味着若是有一个懒加载的路由 ShopList.vue
没有用到public.js
模块,可是实际上引入了父模块,也为这ShopList.vue
也引入了public.js
的代码。
这就须要CommonsChunkPlugin
的 async
属性。
children
与 async
左右开弓Extra async commons chunk
Similar to the above one, but instead of moving common modules into the parent (which increases initial load time) a new async-loaded additional commons chunk is used. This is automatically downloaded in parallel when the additional chunk is downloaded.
设置了async
, 会将上述懒加载的路由文件公用的模块代码,抽离打包成一个单独的文件,而且该文件是按需加载的,若是某个路由没有使用到这些公用模块,是不会加载进来的。
举个例子:
首页路由模块(访问路径/index
),引用了 public
模块
用户路由模块(访问路径/user
),引用了 public
模块
购物车模块(访问路径/shop
),没有引用 public
模块
那么,打包生成的文件大概是
main.js - 根入口文件 index.js - 首页路由文件 user.js - 用户路由文件 shop.js - 购物车路由文件 0.js - 抽离路由的公用模块文件
访问url/index
,加载的依赖文件是main.js + index.js + 0.js
访问url/user
,加载的依赖文件是main.js + user.js + 0.js
访问url/shop
,加载的依赖文件是main.js + shop.js
基本解决了 lazy load + code-splitting 状况下的公用模块抽离。
如下附上简单的webpack.config.js
配置代码
entry: { main: './src/main.js' }, ... plugins: [ ... new webpack.optimize.CommonsChunkPlugin({ name: "main", minChunks: 2, children: true, // deepChildren: true, async: true, }) ]
The CommonsChunkPlugin has been removed in webpack v4 legato. To learn how chunks are treated in the latest version, check out the SplitChunksPlugin.PS: webpack 4 已经将
CommonsChunkPlugin
废弃,解决方案仅能在webpack 3 如下使用。
commons-chunk-plugin
CommonChunkPlugin: Feature - Select statically imported modules from chunks that were created from a dynamic import (require.ensure / System.import / import(".."))