new webpack.optimize.CommonsChunkPlugin('common.js')
这种做法默认会把所有入口节点的公共代码提取出来, 生成一个common.js 2、有选择的提取公共代码 new webpack.optimize.CommonsChunkPlugin('common.js',['entry1','entry2']); 只提取entry1节点和entry2中的共用部分模块, 生成一个common.js 3、将entry下所有的模块的公共部分(可指定引用次数)提取到一个通用的chunk中 new webpack.optimize.CommonsChunkPlugin({ name: 'vendors', minChunks: function (module, count) { return ( module.resource && /.js$/.test(module.resource) && module.resource.indexOf( path.join(__dirname, '../node_modules') ) === 0 ) } }); 提取所有node_modules中的模块至vendors中,也可以指定minChunks中的最小引用数; 4、抽取enry中的一些lib抽取到vendors中 entry = { vendors: ['fetch', 'loadash'] }; new webpack.optimize.CommonsChunkPlugin({ name: "vendors", minChunks: Infinity });添加一个entry名叫为vendors,并把vendors设置为所需要的资源库,CommonsChunk会自动提取指定库至vendors中。
方案二:通过externals配置来提取常用库
在实际项目开发过程中,我们并不需要实时调试各种库的源码,这时候就可以考虑使用external选项了。 简单来说external就是把我们的依赖资源声明为一个外部依赖,然后通过script外链脚本引入。这也是我们早期页面开发中资源引入的一种翻版,只是通过配置后可以告知webapck遇到此类变量名时就可以不用解析和编译至模块的内部文件中,而改用从外部变量中读取,这样能极大的提升编译速度,同时也能更好的利用CDN来实现缓存。 1、在页面中加入需要引入的lib地址如下:
2 在webpack.config.js中加入external配置项:
3 非常重要的是一定要在output选项中加入如下一句话:
output:{
libraryTarget:"umd"
}
由于通过external提取过的js模块是不会被记录到webapck的chunk信息中,通过libraryTarget可告知我们构建出来的业务模块,当读到了externals中的key时,需要以umd的方式去获取资源名,否则会有出现找不到module的情况。 方案三、利用DllPlugin和DllReferencePlugin预编译资源模块 简单来说DllPlugin的作用是预先编译一些模块,而DllReferencePlugin则是把这些预先编译好的模块引用起来。这边需要注意的是DllPlugin必须要在DllReferencePlugin执行前先执行一次,dll这个概念应该也是借鉴了windows程序开发中的dll文件的设计理念。相对于externals,dllPlugin有如下几点优势:dll预编译出来的模块可以作为静态资源链接库可被重复使用,尤其适合多个项目之间的资源共享,如同一个站点pc和手机版等;dll资源能有效地解决资源循环依赖的问题,部分依赖库如:react-addons-css-transition-group这种原先从react核心库中抽取的资源包,整个代码只有一句话: module.exports = require('react/lib/ReactCSSTransitionGroup');
却因为重新指向了react/lib中,这也会导致在通过externals引入的资源只能识别react,寻址解析react/lib则会出现无法被正确索引的情况。由于externals的配置项需要对每个依赖库进行逐个定制,所以每次增加一个组件都需要手动修改,略微繁琐,而通过dllPlugin则能完全通过配置读取,减少维护的成本; 1、配置dllPlugin对应资源表并编译文件 那么externals该如何使用呢,其实只需要增加一个配置文件:webpack.dll.config.js: const webpack = require('webpack'); const path = require('path'); const isDebug = process.env.NODE_ENV === 'development'; const outputPath = isDebug ? path.join(__dirname, '../common/debug') : path.join(__dirname, '../common/dist'); const fileName = '[name].js'; // 资源依赖包,提前编译 const lib = [ 'react', 'react-dom', 'react-router', 'history', 'react-addons-pure-render-mixin', 'react-addons-css-transition-group', 'redux', 'react-redux', 'react-router-redux', 'redux-actions', 'redux-thunk', 'immutable', 'whatwg-fetch', 'byted-people-react-select', 'byted-people-reqwest' ]; const plugin = [ new webpack.DllPlugin({ /** * path * 定义 manifest 文件生成的位置 * [name]的部分由entry的名字替换 */ path: path.join(outputPath, 'manifest.json'), /** * name * dll bundle 输出到那个全局变量上 * 和 output.library 一样即可。 */ name: '[name]', context: __dirname }), new webpack.optimize.OccurenceOrderPlugin() ]; if (!isDebug) { plugin.push( new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production') }), new webpack.optimize.UglifyJsPlugin({ mangle: { except: ['$', 'exports', 'require'] }, compress: { warnings: false }, output: { comments: false } }) ) } module.exports = { devtool: '#source-map', entry: { lib: lib }, output: { path: outputPath, filename: fileName, /** * output.library * 将会定义为 window.${output.library} * 在这次的例子中,将会定义为`window.vendor_library` */ library: '[name]', libraryTarget: 'umd', umdNamedDefine: true }, plugins: plugin }; 然后执行命令: $ NODE_ENV=development webpack --config webpack.dll.lib.js --progress $ NODE_ENV=production webpack --config webpack.dll.lib.js --progress
2、dllPlugin的静态资源引入 lib.js和manifest.json存在一一对应的关系,所以我们在调用的过程也许遵循这个原则,如当前处于开发阶段,对应我们可以引入common/debug文件夹下的lib.js和manifest.json,切换到生产环境的时候则需要引入common/dist下的资源进行对应操作,这里考虑到手动切换和维护的成本,我们推荐使用add-asset-html-webpack-plugin进行依赖资源的注入,可得到如下结果: <head> <script src="/static/common/lib.js"></script> </head> 在webpack.config.js文件中增加如下代码: const isDebug = (process.env.NODE_ENV === 'development'); const libPath = isDebug ? '../dll/lib/manifest.json' : '../dll/dist/lib/manifest.json'; // 将mainfest.json添加到webpack的构建中 module.export = { plugins: [ new webpack.DllReferencePlugin({ context: __dirname, manifest: require(libPath), }) ] }
多个工程之间如果需要使用共同的lib资源,也只需要引入对应的lib.js和manifest.js即可,plugin配置中也支持多个webpack.DllReferencePlugin同时引入使用,如下: module.export = { plugins: [ new webpack.DllReferencePlugin({ context: __dirname, manifest: require(libPath), }), new webpack.DllReferencePlugin({ context: __dirname, manifest: require(ChartsPath), }) ] }
方案四 使用Happypack加速你的代码构建 众所周知,webpack中为了方便各种资源和类型的加载,设计了以loader加载器的形式读取资源,但是受限于node的编程模型影响,所有的loader虽然以async的形式来并发调用,但是还是运行在单个 node的进程以及在同一个事件循环中,这就直接导致了当我们需要同时读取多个loader文件资源时,比如babel-loader需要transform各种jsx,es6的资源文件。在这种同步计算同时需要大量耗费cpu运算的过程中,node的单进程模型就无优势了,那么happypack就针对解决此类问题而生。 开启happypack的线程池 happypack的处理思路是将原有的webpack对loader的执行过程从单一进程的形式扩展多进程模式,原本的流程保持不变,这样可以在不修改原有配置的基础上来完成对编译过程的优化,具体配置如下: var HappyPack = require('happypack'); var happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length }); module: { loaders: [ { test: /.js[x]?$/, // loader: 'babel-loader?presets[]=es2015&presets[]=react' loader: 'happypack/loader?id=happybabel' } ] }, plugins: [ new HappyPack({ id: 'happybabel', loaders: ['babel-loader'], threadPool: happyThreadPool, cache: true, verbose: true }) ]
以上内容通过参考其他类似文章以及结合自身的所学汇总而成,不是很全面后期学到新的知识会继续补全,不断学习希望自己能够在前端这条路上越走越远!!!!