Webpack性能优化的方式有不少种,本文之因此将 dll 单独讲解,是由于 dll 是一种最简单粗暴而且极其有效的优化方式。html
在一般的打包过程当中,你所引用的诸如:jquery、bootstrap、react、react-router、redux、antd、vue、vue-router、vuex 等等众多库也会被打包进 bundle 文件中。因为这些库的内容基本不会发生改变,每次打包加入它们无疑是一种巨大的性能浪费。vue
Dll 的技术就是在第一次时将全部引入的库打包成一个 dll.js 的文件,将本身编写的内容打包为 bundle.js 文件,这样以后的打包只用处理 bundle 部分。node
以一个 Vue 项目为例,首先建立一个名为 webpack.dll.config.js 的文件react
var path = require("path"), fs = require('fs'), webpack = require("webpack"); var vendors = [ 'vue', 'vue-router', 'vuex' ]; module.exports = { entry: { vendor: vendors }, output: { path: path.join(__dirname, "dist"), filename: "Dll.js", library: "[name]_[hash]" }, plugins: [ new webpack.DllPlugin({ path: path.join(__dirname, "dist", "manifest.json"), name: "[name]_[hash]", context: __dirname }) ] };
这个文件的做用是将 vue、vue-router 以及 vuex 合并打包为一个名为 Dll.js 的静态资源包,同时生成一个 manifest.json 文件方便对 Dll.js 中的模块进行引用。jquery
要注意的是,执行 webpack 命令是默认执行该目录下名为 webpack.config.js 或者 webpackfile.js 的文件。因此须要经过 --config 指令手动指定该文件,最后加入 -p 指令将 Dll.js 压缩。webpack
$ webpack --config webpack.dll.config.js -p
这样,在项目根目录下就会多增长一个 dist 文件夹,其中有压缩以后的 Dll.js 与 manifest.json 文件。git
manifest.json 文件内容以下,给各个模块赋予 id 以便引用。github
{ "name": "vendor_2beb750db72b1cda4321", "content": { "./node_modules/process/browser.js": { "id": 0, "meta": {} }, "./node_modules/vue-router/dist/vue-router.esm.js": { "id": 1, "meta": { "harmonyModule": true }, "exports": [ "default" ] }, "./node_modules/vue/dist/vue.runtime.esm.js": { "id": 2, "meta": { "harmonyModule": true }, "exports": [ "default" ] }, //.......
最后在 webpack.config.js 中添加引用。在 plugins 属性中添加 DllReferencePlugin 插件,并指明 manifest.json 文件的引用路径。web
//... plugins: [ new webpack.DllReferencePlugin({ context: __dirname, manifest: require('./dist/manifest.json') }) ]
在确保成功执行 webpack.dll.config.js 文件后,执行 webpack -p 进行项目打包。vue-router
能够看到打包在 Dll 文件中的文件都被 delegated(委派) ,而不是直接打进 bundle 文件中。
这样咱们就将全部的资源完成打包,生成的 dist 目录以下:
不过 dist 文件夹要想做为一个完整的工程还少一个 html 文件,我建立了一个名为 pack.js 的文件,使用 nodejs 的 fileSystem 对 html 文件进行修改并拷贝。
pack.js
var fs = require('fs'); fs.readFile('./index.html', 'utf8', (err, data) => { if (!err) { var dataStr = data.toString(), timestamp = (new Date()).getTime(); dataStr = dataStr .replace('bundle.js', 'bundle.js?v='+timestamp) .replace('<!-- dll -->', '<script src="./dist/Dll.js?v='+ timestamp +'"></script>'); fs.writeFile('./dist/index.html', dataStr, (error) => { if (!error) { console.log('HTML file copy successfully'); } else { console.log(error); } }); } else { console.log(err); } });
咱们须要在模块的入口 html 中添加 <!-- dll --> 的占位字符,pack.js 的做用就是将 html 文件拷贝一份到 dist 目录下,同时将 <!-- dll --> 替换为引用 Dll.js 的 script 标签,并在引用文件后添加时间戳。
<!-- .... --> <body> <div id="demo" class="container"></div> <!-- dll --> <script src="./bundle.js"></script> </body> </html>
在执行 webpack -p 打包后,输入下面命令运行 pack.js,就会在 dist 目录下生成 html 文件。
$ node pack.js
内容以下:
<!-- .... --> <body> <div id="demo" class="container"></div> <script src="./dist/Dll.js?v=1488250309725"></script> <script src="./bundle.js?v=1488250309725"></script> </body> </html>
这样 dist 文件夹就做为一个完整的、不须要任何手动操做、已经压缩混淆后的项目能够直接进行线上的部署。
实际项目模板参考地址以下。因为笔者做为 React 与 Vue 的双持开发者,因此建立了两个模板,以便以后经过 yomen(yo) 之类的进行脚手架工具化。
https://github.com/Darylxyx/generator-yx-react
https://github.com/Darylxyx/generator-yx-vue
感谢你的浏览,但愿能有所帮助。