大多数时候,使用webpack将所有的代码打包到一起是不合适的,如:我们希望将样式单独打包使用link标签引用、很多首页不需要的资源按需加载、缓存不常变动的代码。
1、按需加载拆分
require.ensure()是一种使用 CommonJS 的形式来异步加载模块的策略。语法如下:
require.ensure(dependencies: String[], callback: function(require), chunkName: String)
第一个参数:依赖的模块
第二个参数:依赖加载成功之后的回调函数。require
对象的一个实现会作为一个参数传递给这个回调函数。因此,我们可以进一步 require()
依赖和其它模块提供下一步的执行。
第三个参数:chunk名称
a、第一个参数为空数组,requireEnsure.vue会被webpack分开打包
require.ensure([], (require) => { require('./components/requireEnsure.vue') }, 'requireEnsure')
b、pageA.js和requireEnsure1.js会被打包到一起,而且从主文件束中拆分出来。但只有 requireEnsure1.js
的内容被执行。pageA.js
的内容仅仅是可被使用,但并没有被输出。想去执行 pageA.js
,我们需要异步地引用它,如 require('./
pageA.js')
,让它的 JavaScritp 被执行。
require.ensure(['./components/pageA.js'], (require) => { require('./components/requireEnsure1.js') }, 'requireEnsure1')
c、a.js和b.js都依赖c.js,c模块被打包了两次
require.ensure(['./c'], function(require){ let a = require('./a'); console.log(a) }); require.ensure(['./c'], function(require){ let b = require('./b'); console.log(b) });
设置第三个参数chunkName,就可以避免c模块被打包为两次的情况了
require.ensure(['./c'], function(require){ let a = require('./a'); console.log(a) }, 'd'); require.ensure(['./c'], function(require){ let b = require('./b'); console.log(b) }, 'd');
ok,这样以上两个 require.ensure
拆出来的包就合并为同一个了。
require.ensure中回调函数require的文件会被单独打包,打包后的结果文件webpack会自动给这些文件命名,但这样不是很好识别,有时候我们想自己给打包后的文件取名,修改webpack的配置文件如下:
module.exports = { entry: './index.js', output: { path: __dirname + '/dist/', filename: '[name].js', publicPath: __dirname + '/dist/', // 文件路径 chunkFilename: '[name].js' // 文件名称 } }
ok,这样,打包后的文件就是我们自己取的名称了
2、拆分框架代码和业务代码
在我们开发的时候,可能会依赖一些第三方库,第三方库的代码一般比较稳定,不需要经常变动。因此我们想的是将业务代码和框架代码分开打包,这样可以充分利用浏览器缓存,不需要每次都把框架代码加载一遍。
webpack的配置如下:
module.exports = { entry: { main: './index.js', vendor: ['react', 'react-dom'] } // 其他配置 }
这样配置后,打包后就会得到main.js和vendor.js这两个文件,但是,在main.js中还是会包含react和react-dom中的代码,这是因为在index.js中引用了react和react-dom,webpack打包的时候会从入口文件开始查找依赖,并用loader来处理,所以,react和react-dom自然被打包了进去。如何才能实现不重复打包框架代码呢?这里我们需要用到webpack的一个插件CommonsChunkPlugin。
使用CommonsChunkPlugin
CommonsChunkPlugin插件的主要作用是将多个打包结果中公共的部分抽取出来。
let webpack = require('webpack'); module.exports = { entry: { main: 'index.js', vendor: ['react', 'react-dom'] }, //... plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: 'vendor' // 指定一个希望作为公共包的入口 }) ] }
再进行打包发现main.js中不存在react的代码了。
3、css代码拆分
extract-text-webpack-plugin
安装extract-text-webpack-plugin
npm i --save-dev extract-text-webpack-plugin
在webpack配置文件中加入该插件:
var ExtractTextPlugin = require('extract-text-webpack-plugin'); module.exports = function () { return { entry: './index.js', output: { path: './build', filename: 'bundle.js' }, module: { loaders: [{ test: /\.css$/, exclude: /node_modules/, // 在 loader 中使用该插件 loader: ExtractTextPlugin.extract('style-loader', 'css-loader') }] }, plugins: [ // 将其添加在插件中 new ExtractTextPlugin({ filename: 'bundle.css', disable: false, allChunks: true }) ] } }