19、webpack优化(4)——DllPlugin动态链接库

DllPlugin

场景需求举例

我们在打包一个react的项目的时候,会把react和react-dom这两个库打包起来。而这两个库很大且基本不会变,所以如果每次打包都要打包这两个第三方包的话,浪费时间,消耗性能。所以,我们一般会采取如下操作:

将react和react-dom单独打包好,然后动态链接引入即可。如果第二次打包,那么发现react和react-dom已经被打包好了,那么就不需要再打包了,这样就大大提升了性能。

实现

  1. 在src下新建test.js
 module.exports = 'yh';
  1. 新建webpack.config.react.js用于单独打包react和react-dom
 let path = require('path');

 module.exports = {
  mode:'development',
  entry:{
   test:'./src/test.js'
  },
  output:{
   filename:'[name].js',
   path:path.resolve(__dirname,'dist')
  }
 }
  1. 执行npx webpack --config webpack.config.react.js,得到dist/test.js。
 /******/ (function(modules) { // webpackBootstrap
 /******/  var installedModules = {};
 /******/
 /******/  function __webpack_require__(moduleId) {
 /******/
 /******/   if(installedModules[moduleId]) {
 /******/    return installedModules[moduleId].exports;
 /******/   }
 /******/   var module = installedModules[moduleId] = {
 /******/    i: moduleId,
 /******/    l: false,
 /******/    exports: {}
 /******/   };
 /******/
 /******/   modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
 /******/
 /******/   module.l = true;

 /******/   return module.exports;
 /******/  }
 /******/
 /******/  __webpack_require__.m = modules;
 /******/
 /******/  __webpack_require__.c = installedModules;
 /******/
 /******/  __webpack_require__.d = function(exports, name, getter) {
 /******/   if(!__webpack_require__.o(exports, name)) {
 /******/    Object.defineProperty(exports, name, { enumerable: true, get: getter });
 /******/   }
 /******/  };
 /******/
 /******/  __webpack_require__.r = function(exports) {
 /******/   if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
 /******/    Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
 /******/   }
 /******/   Object.defineProperty(exports, '__esModule', { value: true });
 /******/  };
 /******/
 /******/  __webpack_require__.t = function(value, mode) {
 /******/   if(mode & 1) value = __webpack_require__(value);
 /******/   if(mode & 8) return value;
 /******/   if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
 /******/   var ns = Object.create(null);
 /******/   __webpack_require__.r(ns);
 /******/   Object.defineProperty(ns, 'default', { enumerable: true, value: value });
 /******/   if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
 /******/   return ns;
 /******/  };
 /******/
 /******/  __webpack_require__.n = function(module) {
 /******/   var getter = module && module.__esModule ?
 /******/    function getDefault() { return module['default']; } :
 /******/    function getModuleExports() { return module; };
 /******/   __webpack_require__.d(getter, 'a', getter);
 /******/   return getter;
 /******/  };
 /******/
 /******/  __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
 /******/
 /******/  __webpack_require__.p = "";
 /******/
 /******/  return __webpack_require__(__webpack_require__.s = "./src/test.js");
 /******/ })
 /******/ ({

 /***/ "./src/test.js":
 /***/ (function(module, exports) {

 eval("module.exports = 'yh';\n\n//# sourceURL=webpack:///./src/test.js?");

 /***/ })

 /******/ });
  1. 我们原本打包这个test.js是为了得到module.exports的内容’yh’,但是事实上,打包后的test.js并没有把这个值返回出来让一个变量去接收,所以我们也就无法去使用这个值。这时候,如果我们var一个a去接收,那么就可以把这个结果打印出来,如下(下面的代码只需要看第一行跟最后一行):
 var a = (function(modules) { // webpackBootstrap
 /******/  var installedModules = {};
 /******/
 /******/  function __webpack_require__(moduleId) {
 /******/
 /******/   if(installedModules[moduleId]) {
 /******/    return installedModules[moduleId].exports;
 /******/   }
 /******/   var module = installedModules[moduleId] = {
 /******/    i: moduleId,
 /******/    l: false,
 /******/    exports: {}
 /******/   };
 /******/
 /******/   modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
 /******/
 /******/   module.l = true;

 /******/   return module.exports;
 /******/  }
 /******/
 /******/  __webpack_require__.m = modules;
 /******/
 /******/  __webpack_require__.c = installedModules;
 /******/
 /******/  __webpack_require__.d = function(exports, name, getter) {
 /******/   if(!__webpack_require__.o(exports, name)) {
 /******/    Object.defineProperty(exports, name, { enumerable: true, get: getter });
 /******/   }
 /******/  };
 /******/
 /******/  __webpack_require__.r = function(exports) {
 /******/   if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
 /******/    Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
 /******/   }
 /******/   Object.defineProperty(exports, '__esModule', { value: true });
 /******/  };
 /******/
 /******/  __webpack_require__.t = function(value, mode) {
 /******/   if(mode & 1) value = __webpack_require__(value);
 /******/   if(mode & 8) return value;
 /******/   if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
 /******/   var ns = Object.create(null);
 /******/   __webpack_require__.r(ns);
 /******/   Object.defineProperty(ns, 'default', { enumerable: true, value: value });
 /******/   if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
 /******/   return ns;
 /******/  };
 /******/
 /******/  __webpack_require__.n = function(module) {
 /******/   var getter = module && module.__esModule ?
 /******/    function getDefault() { return module['default']; } :
 /******/    function getModuleExports() { return module; };
 /******/   __webpack_require__.d(getter, 'a', getter);
 /******/   return getter;
 /******/  };
 /******/
 /******/  __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
 /******/
 /******/  __webpack_require__.p = "";
 /******/
 /******/  return __webpack_require__(__webpack_require__.s = "./src/test.js");
 /******/ })
 /******/ ({

 /***/ "./src/test.js":
 /***/ (function(module, exports) {

 eval("module.exports = 'yh';\n\n//# sourceURL=webpack:///./src/test.js?");

 /***/ })

 /******/ });

 console.log(a);
  1. 如果我们每次都这么做的话,那就太麻烦了,所以我们可以给每次输出的时候添加下配置:
 let path = require('path');

 module.exports = {
  mode:'development',
  entry:{
   test:'./src/test.js'
  },
  output:{
   filename:'[name].js',
   path:path.resolve(__dirname,'dist'),
   library:'ab',//这样打包后的结果就被变量ab接收
   libraryTarget:'var',//commonjs、umd、var、this等等,默认var,这样就相当于var ab = 打包后的结果
  }
 }
  1. 上面是以test.js为例来打包,那么如果我们打包的是react,就应该写成如下:
 let path = require('path');
 module.exports = {
  mode:'development',
  entry:{
   react:['react','react-dom']
  },
  output:{
   filename:'_dll_[name].js',//产生的文件名_dll_react.js 
   path:path.resolve(__dirname,'dist'),
   library:'_dll_[name]',//_dll_react
   // libraryTarget:'var',
  }
 }
  1. 这时候我们还需要利用一个插件去生成一个清单,每次打包的时候,先去查找下清单里是否已经存在这个依赖,如果已经存在,则不打包,如果还没存在,则需要打包。
  • 生成清单需要使用webpack的内置插件webpack.DllPlugin()
 let path = require('path');
 let webpack = require('webpack');
 module.exports = {
  mode:'development',
  entry:{
   react:['react','react-dom']
  },
  output:{
   filename:'_dll_[name].js',//产生的文件名_dll_react.js 
   path:path.resolve(__dirname,'dist'),
   library:'_dll_[name]',//_dll_react
   // libraryTarget:'var',
  },
  plugins:[
   new webpack.DllPlugin({
    name:'_dll_[name]',//这个name要与output中的library同名
    path:path.resolve(__dirname,'dist','manifest.json')
   })
  ]
 }
  1. 这样打包出来的话,会在dist生成两个文件,一个是_dll_react.js,一个是清单manifest.json

  2. 然后在index.html去引用这个打包后的文件

 <!DOCTYPE html>
 <html>
 <head>
  <title></title>
 </head>
 <body>
  <div id="root"></div>
  <script type="text/javascript" src="/_dll_react.js"></script>
 </body>
 </html>
  1. 但是现在,我们引用react或react-dom的时候,我们需要判断是否在清单里,这时候,我们就需要在我们正式的webpack.config.js里进行配置
  • 需要使用到webpack内置插件new webpack.DllReferencePlugin
 let path = require('path');
 let webpack = require('webpack');
 let HtmlWebpackPlugin = require('html-webpack-plugin');
 module.exports = {
  devServer:{
   port:3000,
   open:true,
   contentBase:'./dist'
  },
  mode:'development',
  entry:'./src/index.js',
  output:{
   filename:'bundle.js',
   path:path.resolve(__dirname,'./dist')
  },
  module:{
   rules:[
    {
     test:/\.js$/,
     use:{
      loader:'babel-loader',
      options:{
       presets:[
        '@babel/preset-env',
        '@babel/preset-react'
       ]
      }
     }
    }
   ]
  },
  plugins:[
   new webpack.DllReferencePlugin({
    manifest:path.resolve(__dirname,'dist','manifest.json')
   }),
   new HtmlWebpackPlugin({
    template:'./src/index.html',
    filename:'index.html'
   })
  ]
 }
  1. 这时候再打包,就会发现react和react-dom不打包了,自然打包出的文件就小很多了

  2. 注意:如果第一次打包,那么要先打包下react和react-dom,即:

 npx webpack --config webpack.config.react.js
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值