详解基于DllPlugin和DllReferencePlugin的webpack构建优化


Posted in Javascript onJune 28, 2018

一个基于vue-cli webpack2模板创建的项目.项目中使用到了vue+vue-router+axios+muse-ui+iview
现在构建一次需要的时间大概是40s左右.真心受不了.虽然在开发过程中,我们不太需要关心构建时间.但是如果在开发hybridApp时,构建的次数就会增多.

一般我们可以把项目分为三部分.

分类 说明 变动频率
vendor_library 核心库
vendor 一般项目依赖 中等
code 业务逻辑

vendor_library:比如vue,vue-router,axios 这些变动频率极低的文件可以利用 DllPlugin 和 DllReferencePlugin 进行预编译.

vendor,code在开发阶段,每次构建都需要编译.但是一旦完成该次开发任务,应该调整vendor 是否加入vendor_library.

BundleAnalyzerPlugin 的插件使用

BundleAnalyzerPlugin 是分析 Webpack 生成的包体组成并且以可视化的方式反馈给开发者的插件。

详解基于DllPlugin和DllReferencePlugin的webpack构建优化

vue已经默认集成了该插件. 如果你运行 npm run build ?report.就能看到当前项目的依赖情况.然后做出相应调整.

优化方向

按需加载

muse-ui,iview 都提供了按需加载的方式,按照文档调整即可.

分类 耗时 muse-ui iview
before 13256ms 234KB 337KB
after 43211ms 79KB 75KB

先看结果...你没看错,'优化后',时间竟然变长了...?.不过这也正常,之前的依赖直接获取的是dist目录的文件,现在需要在src目录下获取.增加了编译的过程.

但是文件大小的减少还是喜人的.当然,这取决于项目中对模块的使用程度.在我们这个项目中iview只使用了的四个控件.结果上看,显然还是按需加载比较划算.不过这个不算是时间上的优化,只是因为dll可以解决构建时间问题,使按需加载变的更好用.

DllPlugin 和 DllReferencePlugin 预编译资源模块

Dll这个概念应该是借鉴了Windows系统的dll。一个dll包,就是一个纯纯的依赖库,它本身不能运行,是用来给你的app引用的。

打包dll的时候,Webpack会将所有包含的库做一个索引,写在一个manifest文件中,而引用dll的代码(dll user)在打包的时候,只需要读取这个manifest文件,就可以了。

这么一来有几个好处:

Dll打包以后是独立存在的,只要其包含的库没有增减、升级,hash也不会变化,因此线上的dll代码不需要随着版本发布频繁更新。

App部分代码修改后,只需要编译app部分的代码,dll部分,只要包含的库没有增减、升级,就不需要重新打包。这样也大大提高了每次编译的速度。

假设你有多个项目,使用了相同的一些依赖库,它们就可以共用一个dll。

网上抄的… 其实意思就是我们可以把项目的公共模块,基本不会改动的模块.想我们刚才说的定义为vendor_library的内容,进行预编译编译.以后在项目构建过程中,vendor_library部分直接引用,就不需要再编译了.

这也是为什么按需加载可以得到更好的使用,正常构建流程,因为使用了按需加载,会导致每次的构建都比使用全量加载用时要长.而使用dll,核心库只需要编译一次,以后直接引用即可.

先来看一下改进结果:

分类 耗时
before 57192ms
after 7890ms

哈哈,有没有快到飞起!!!

DllPlugin 和 DllReferencePlugin 使用

新建webpack.dll.conf.js文件

//webpack.dll.conf.js
process.env.NODE_ENV = 'production'
const path = require('path');
var utils = require('./utils')
var vueLoaderConfig = require('./vue-loader.conf')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const webpack = require('webpack');
//vue项目默认有一个static目录.我就把导出目录放在了static/dll/目录下
const srcPath = path.join(__dirname, '../static/dll/');
//需要编译的模块
const vendors = ['vue/dist/vue.esm.js',
  'vue-router',
  'vue-localstorage',
  'material-design-icons/iconfont/material-icons.css',
  'iview/dist/styles/iview.css',
  'iview/src/components/tag/tag.vue'
  'muse-ui/src/appBar'
];
webpackConfig = {
  entry: {
    vendor: vendors
  },
  resolve: {
    extensions: ['.js', '.vue', '.json']
  },
  module: {
    loaders: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      {
        test: /iview.src.*?js$/,
        loader: 'babel-loader'
      },
      {
        test: /muse-ui.src.*?js$/,
        loader: 'babel-loader'
      },
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          use: "css-loader"
        })
      },
      {
        test: /\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          publicPath: './',
          limit: 1000,
          name: 'fonts/[name].[ext]'
        }
      }]
  },
  output: {
    path: srcPath, // 输出的路径
    filename: '[name].dll.js', // 输出的文件,将会根据entry命名为vendor.dll.js
    library: '[name]_library' // 暴露出的全局变量名
  },
  plugins: [
    new ExtractTextPlugin({
      filename: '[name].dll.css'
    }),
    new OptimizeCSSPlugin({
      cssProcessorOptions: {
        safe: true
      }
    }),
    new webpack.optimize.UglifyJsPlugin({ // uglifjs压缩
      compress: {
        warnings: false
      }
    }),
    new webpack.DllPlugin({
      path: path.join(srcPath, '[name]-mainfest.json'), // 描述依赖对应关系的json文件
      name: '[name]_library',
      context: __dirname // 执行的上下文环境,对之后DllReferencePlugin有用
    })
  ]
}
if (process.env.npm_config_report) {
  var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig;

其实这就是一个正常的构建文件.根据你的项目进行修改即可.唯一不同的是在plugins多了一个DllPlugin.他会生成一个描述依赖对应关系的json文件.

static目录如下:

|____dll
| |____fonts
| |____vendor-mainfest.json
| |____vendor.dll.css
| |____vendor.dll.js

修改模板index.html 根据你的构建结果做修改.

//head 标签
<link type="text/css" rel="stylesheet" href="./static/dll/vendor.dll.css" rel="external nofollow" >
//body 标签
<script src="./static/dll/vendor.dll.js"></script>

修改webpack.base.conf.js

plugins: [
    ...,
    new webpack.DllReferencePlugin({
      context: __dirname,
      manifest: require('../static/dll/vendor-mainfest.json') // 指向生成的json文件
    })
  ]

执行

webpack --config ./build/webpack.dll.conf.js

你也可以将该语句放入npm run 中.'build:dll:report' 是为了优化dll依赖关系,添加的另外一条命令.上文已经提过,我们可以借用BundleAnalyzerPlugin插件查看当前包的依赖情况,和包体组成情况.

//package.json
"scripts":{
  "build:dll": "webpack --config ./build/webpack.dll.conf.js",
  "build:dll:report": "npm run build:dll --report"
}

npm run build …看看这次的构建时间吧 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript椭圆旋转相册实现代码
Jan 16 Javascript
将查询条件的input、select清空
Jan 14 Javascript
使用window.prompt()实现弹出用户输入的对话框
Apr 13 Javascript
举例详解AngularJS中ngShow和ngHide的使用方法
Jun 19 Javascript
AngularJS实现一次监听多个值发生的变化
Aug 31 Javascript
Bootstrap Scrollspy源码学习
Mar 02 Javascript
javascript防篡改对象实例详解
Apr 10 Javascript
详解在express站点中使用ejs模板引擎
Sep 21 Javascript
详解mpvue实现对苹果X安全区域的适配
Jul 31 Javascript
Paypal支付不完全指北
Jun 04 Javascript
基于vue与element实现创建试卷相关功能(实例代码)
Dec 07 Vue.js
Vue.extend 登录注册模态框的实现
Dec 29 Vue.js
vue使用Element组件时v-for循环里的表单项验证方法
Jun 28 #Javascript
详解ES6中的三种异步解决方案
Jun 28 #Javascript
Auto.js自动收取自己和好友蚂蚁森林能量脚本
Jun 28 #Javascript
使用vue-router完成简单导航功能【推荐】
Jun 28 #Javascript
vue如何引入sass全局变量
Jun 28 #Javascript
小程序实现带年月选取效果的日历
Jun 27 #Javascript
浅谈Angular6的服务和依赖注入
Jun 27 #Javascript
You might like
php面向对象全攻略 (九)访问类型
2009/09/30 PHP
PHP的substr_replace将指定两位置之间的字符替换为*号
2011/05/04 PHP
PHP字符编码问题之GB2312 VS UTF-8解决方法
2011/06/23 PHP
简单实用的.net DataTable导出Execl
2013/10/28 PHP
php以fastCGI的方式运行时文件系统权限问题及解决方法
2015/05/11 PHP
详解WordPress中的头像缓存和代理中的缓存更新方法
2016/03/01 PHP
JavaScript与Div对层定位和移动获得坐标的实现代码
2010/09/08 Javascript
javascript实现可改变滚动方向的无缝滚动实例
2013/06/17 Javascript
javascript中的取反再取反~~没有意义
2014/04/06 Javascript
简介JavaScript中Math.cos()余弦方法的使用
2015/06/15 Javascript
实例详解AngularJS实现无限级联动菜单
2016/01/15 Javascript
原生js仿jquery animate动画效果
2016/07/13 Javascript
BootStrap 图片样式、辅助类样式和CSS组件的实例详解
2017/01/20 Javascript
Vue中使用方法、计算属性或观察者的方法实例详解
2018/10/31 Javascript
vue v-on:click传递动态参数的步骤
2020/09/11 Javascript
python有证书的加密解密实现方法
2014/11/19 Python
python实现网站的模拟登录
2016/01/04 Python
使用Python脚本实现批量网站存活检测遇到问题及解决方法
2016/10/11 Python
关于Python的一些学习总结
2018/05/25 Python
Python面向对象程序设计OOP深入分析【构造函数,组合类,工具类等】
2019/01/05 Python
Python数据类型之Tuple元组实例详解
2019/05/08 Python
Python使用itchat 功能分析微信好友性别和位置
2019/08/05 Python
python中的&amp;&amp;及||的实现示例
2019/08/07 Python
pytorch 模型的train模式与eval模式实例
2020/02/20 Python
python使用建议技巧分享(三)
2020/08/18 Python
详解如何使用Pytest进行自动化测试
2021/01/14 Python
canvas学习笔记之绘制简单路径
2019/01/28 HTML / CSS
特步官方商城:Xtep
2017/03/21 全球购物
澳大利亚最好的电动自行车:Leon Cycle
2020/12/19 全球购物
Collection和Collections的区别
2016/05/02 面试题
实习自我评价怎么写
2013/12/02 职场文书
环保倡议书
2014/04/14 职场文书
党的群众路线教育实践活动学习笔记范文
2014/11/06 职场文书
导游词之金鞭溪风景区
2019/09/12 职场文书
《暗黑破坏神2:重制版》本周进行第一轮A测 目前可官网进行申请报名
2021/04/07 其他游戏
python 如何执行控制台命令与操作剪切板
2021/05/20 Python