DllPlugin

06-17 1632阅读

什么是DLL

  • DllPlugin和DllReferencePlugin提供了拆分包的方法,可以极大地提高构建时性能。术语DLL代表动态链接库,它最初是由Microsoft引入的。
  • .dll为后缀的文件称为动态链接库,在一个动态链接库中可以包含给其他模块调用的函数和数据
  • 把基础模块独立出来打包到单独的动态连接库里
  • 当需要导入的模块在动态连接库里的时候,模块不能再次被打包,而是去动态连接库里获取

    使用DLL

    安装依赖

    cnpm i webpack webpack-cli html-webpack-plugin isarray is-promise -D
    

    定义Dll

    • dll-plugin
    • DllPlugin插件: 用于打包出一个个动态连接库
    • DllReferencePlugin: 在配置文件中引入DllPlugin插件打包好的动态连接库

      webpack.dll.config.js

      DllPlugin
      (图片来源网络,侵删)
      const path = require("path");
      const DllPlugin = require("webpack/lib/DllPlugin");
      const DllPlugin2 = require("./plugins/DllPlugin");
      module.exports = {
        mode: "development",
        devtool: false,
        entry: {
          utils:["isarray","is-promise"]
        },
        output: {
          path: path.resolve(__dirname, "dist"),
          filename: "utils.dll.js", //react.dll.js
          library: "_dll_utils",
        },
        plugins: [
          new DllPlugin2({
            //暴露出去的dll函数
            name: "_dll_utils",
            //输出的manifest json文件的绝对路径
            path: path.join(__dirname, "dist", "utils.manifest.json")
          }),
        ],
      };
      

      使用动态链接库文件

      webpack.config.js

      const path = require("path");
      const DllReferencePlugin = require("webpack/lib/DllReferencePlugin.js");
      const HtmlWebpackPlugin = require('html-webpack-plugin');
      module.exports = {
        mode: "development",
        devtool: false,
        entry: "./src/index.js",
        output: {
          path: path.resolve(__dirname, 'dist'),
          filename: 'bundle.js'
        },
        plugins: [
          new DllReferencePlugin({
            manifest: require("./dist/utils.manifest.json"),
          }),
          new HtmlWebpackPlugin({
            template: './src/index.html'
          })
        ],
      };
      

      html中使用

      
      
          
          
          dll
      
      
          

      index.js

      src\index.js

      let isarray = require("isarray");
      console.log('isarray([1, 2, 3])=',isarray([1, 2, 3]));
      

      package.json

      package.json

        "scripts": {
          "dll": "webpack --config webpack.dll.config.js",
          "build": "webpack --config webpack.config.js"
        }
      

      dll.js

      const webpack = require("webpack");
      const webpackOptions = require("./webpack.dll.config");
      const compiler = webpack(webpackOptions);
      debugger
      compiler.run((err, stats) => {
        console.log(
          stats.toJson({})
        );
      });
      

      build.js

      const webpack = require("webpack");
      const webpackOptions = require("./webpack.config");
      const compiler = webpack(webpackOptions);
      compiler.run((err, stats) => {
        console.log(
          stats.toJson({})
        );
      });
      

      打包文件分析

      index.html

      
      
          
          
          dll
      
      
          

      utils.dll.js

      dist\utils.dll.js

      var _dll_utils =
        (function (modules) {
          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;
          }
          return __webpack_require__(__webpack_require__.s = 0);
        })
          ({
            "./node_modules/_is-promise@4.0.0@is-promise/index.js":
              (function (module, exports) {
                module.exports = isPromise;
                module.exports.default = isPromise;
                function isPromise(obj) {
                  return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';
                }
              }),
            "./node_modules/_isarray@2.0.5@isarray/index.js":
              (function (module, exports) {
                var toString = {}.toString;
                module.exports = Array.isArray || function (arr) {
                  return toString.call(arr) == '[object Array]';
                };
              }),
            0:
              (function (module, exports, __webpack_require__) {
                module.exports = __webpack_require__;
              })
          });
      

      utils.manifest.json

      dist\utils.manifest.json

      {
        "name": "_dll_utils",
        "content": {
          "./node_modules/_is-promise@4.0.0@is-promise/index.js": {
            "id": "./node_modules/_is-promise@4.0.0@is-promise/index.js",
            "buildMeta": { "providedExports": true }
          },
          "./node_modules/_isarray@2.0.5@isarray/index.js": {
            "id": "./node_modules/_isarray@2.0.5@isarray/index.js",
            "buildMeta": {
              "providedExports": true
            }
          }
        }
      }
      

      bundle.js

      dist\bundle.js

      (function (modules) {
        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;
        }
        return __webpack_require__(__webpack_require__.s = "./src/index.js");
      })
        ({
          "./node_modules/_isarray@2.0.5@isarray/index.js":
            (function (module, exports, __webpack_require__) {
              module.exports = (__webpack_require__("dll-reference _dll_utils"))("./node_modules/_isarray@2.0.5@isarray/index.js");
            }),
          "./src/index.js":
            (function (module, exports, __webpack_require__) {
              let isarray = __webpack_require__("./node_modules/_isarray@2.0.5@isarray/index.js");
              console.log('isarray([1, 2, 3])=', isarray([1, 2, 3]));
            }),
          "dll-reference _dll_utils":
            (function (module, exports) {
              module.exports = _dll_utils;
            })
        });
      

      实现DllPlugin.js

      DllPlugin.js

      plugins\DllPlugin.js

      const DllEntryPlugin = require("./DllEntryPlugin");
      class DllPlugin {
          constructor(options) {
              this.options = options;
          }
          apply(compiler) {
              compiler.hooks.entryOption.tap("DllPlugin", (context, entry) => {
                  Object.keys(entry).forEach(name => {
                      new DllEntryPlugin(context, entry[name],name).apply(compiler);
                  });
                  return true;
              });
          }
      }
      module.exports = DllPlugin;
      

      DllEntryPlugin.js

      plugins\DllEntryPlugin.js

      const SingleEntryDependency = require("webpack/lib/dependencies/SingleEntryDependency");
      const DllEntryDependency = require("./dependencies/DllEntryDependency");
      const DllModuleFactory = require("./DllModuleFactory");
      class DllEntryPlugin {
          constructor(context, entries, name) {
              this.context = context;// c:/aprepare/zhufeng_dll_prepare
              this.entries = entries;// ['isarray', 'is-promise']
              this.name = name; // utils
          }
          apply(compiler) {
              compiler.hooks.compilation.tap(
                  "DllEntryPlugin",
                  (compilation, { normalModuleFactory }) => {
                      const dllModuleFactory = new DllModuleFactory();
                      compilation.dependencyFactories.set(
                          DllEntryDependency,
                          dllModuleFactory
                      );
                      compilation.dependencyFactories.set(
                          SingleEntryDependency,
                          normalModuleFactory
                      );
                  }
              );
              compiler.hooks.make.tapAsync("DllEntryPlugin", (compilation, callback) => {
                  compilation.addEntry(
                      this.context,
                      new DllEntryDependency(
                          this.entries.map((entry) => new SingleEntryDependency(entry)),
                          this.name//utils
                      ),
                      this.name,//utils
                      callback
                  );
              });
          }
      }
      module.exports = DllEntryPlugin;
      

      DllModuleFactory.js

      plugins\DllModuleFactory.js

      const { Tapable } = require("tapable");
      const DllModule = require("./DllModule");
      class DllModuleFactory extends Tapable {
          constructor() {
              super();
              this.hooks = {};
          }
          create(data, callback) {
              const dependency = data.dependencies[0];
              callback(
                  null,
                  new DllModule(
                      data.context,
                      dependency.dependencies,// [SingleEntryDependency, SingleEntryDependency]
                      dependency.name,//utils
                      dependency.type//'dll entry'
                  )
              );
          }
      }
      module.exports = DllModuleFactory;
      

      DllEntryDependency.js

      plugins\dependencies\DllEntryDependency.js

      const Dependency = require("webpack/lib/Dependency");
      class DllEntryDependency extends Dependency {
          constructor(dependencies, name) {
              super();
              this.dependencies = dependencies;//[SingleEntryDependency,SingleEntryDependency ]
              this.name = name;//utils
          }
          get type() {
              return "dll entry";
          }
      }
      module.exports = DllEntryDependency;
      

      DllModule.js

      plugins\DllModule.js

      const { RawSource } = require("webpack-sources");
      const Module = require("webpack/lib/Module");
      class DllModule extends Module {
          constructor(context, dependencies, name, type) {
              super("javascript/dynamic", context);//c:/aprepare/zhufeng_dll_prepare2
              this.dependencies = dependencies;
              this.name = name;//utils
              this.type = type;//dll entry
          }
          identifier() {
              return `dll ${this.name}`;
          }
          readableIdentifier() {
              return `dll ${this.name}`;
          }
          build(options, compilation, resolver, fs, callback) {
              this.built = true;
              this.buildMeta = {};
              this.buildInfo = {};
              return callback();
          }
          source() {
              return new RawSource("module.exports = __webpack_require__;");
          }
          size() {
              return 12;
          }
      }
      module.exports = DllModule;
      

      实现LibManifestPlugin.js

      LibManifestPlugin.js

      plugins\LibManifestPlugin.js

      const path = require("path");
      const asyncLib = require("neo-async");
      class LibManifestPlugin {
          constructor(options) {
              this.options = options;
          }
          apply(compiler) {
              compiler.hooks.emit.tapAsync(
                  "LibManifestPlugin",
                  (compilation, callback) => {
                      asyncLib.forEach(
                          compilation.chunks,
                          (chunk, done) => {
                              // c:aprepare/zhufeng_dll_prepare/dist/utils.manifest.json
                              const targetPath = this.options.path;
                              const name =this.options.name;//_dll_utils
                              let content ={};
                              for(let module of chunk.modulesIterable){
                                  if (module.libIdent) {
                                      const ident = module.libIdent({context:compiler.options.context});
                                      content[ident]= {id: module.id};
                                  }
                              }
                              const manifest = {name,content};//name=_dll_utils
                              compiler.outputFileSystem.mkdirp(path.dirname(targetPath), err => {
                                  compiler.outputFileSystem.writeFile(
                                      targetPath,
                                      JSON.stringify(manifest),
                                      done
                                  );
                              });
                          },
                          callback
                      );
                  }
              );
          }
      }
      module.exports = LibManifestPlugin;
      

      DllPlugin.js

      plugins\DllPlugin.js

      const DllEntryPlugin = require("./DllEntryPlugin");
      +const LibManifestPlugin = require("./LibManifestPlugin");
      class DllPlugin {
          constructor(options) {
              this.options = options;
          }
          apply(compiler) {
              compiler.hooks.entryOption.tap("DllPlugin", (context, entry) => {
                  Object.keys(entry).forEach(name => {
                      new DllEntryPlugin(context, entry[name],name).apply(compiler);
                  });
                  return true;
              });
      +        new LibManifestPlugin(this.options).apply(compiler);
          }
      }
      module.exports = DllPlugin;
      

      实现DllReferencePlugin.js

      DllReferencePlugin.js

      plugins\DllReferencePlugin.js

      const DelegatedSourceDependency = require("webpack/lib/dependencies/DelegatedSourceDependency");
      const ExternalModuleFactoryPlugin = require("./ExternalModuleFactoryPlugin");
      const DelegatedModuleFactoryPlugin = require("./DelegatedModuleFactoryPlugin");
      class DllReferencePlugin {
          constructor(options) {
              this.options = options;
          }
          apply(compiler) {
              compiler.hooks.compilation.tap(
                  "DllReferencePlugin",
                  (compilation, { normalModuleFactory }) => {
                      compilation.dependencyFactories.set(
                          DelegatedSourceDependency,
                          normalModuleFactory
                      );
                  }
              );
              compiler.hooks.compile.tap("DllReferencePlugin", ({normalModuleFactory}) => {
                  let manifest = this.options.manifest;
                  let name = manifest.name;//_dll_utils
                  let content = manifest.content;//{'is-promise':'','isarray':''}
                  //外部模块  "dll-reference _dll_utils"引用window._dll_utils
                  const externals = {};
                  const source = "dll-reference " + name;//dll-reference _dll_utils
                  externals[source] = name;//dll-reference _dll_utils=>_dll_utils
            new ExternalModuleFactoryPlugin("var", externals).apply(normalModuleFactory);
                  new DelegatedModuleFactoryPlugin({
                      source,
                      context: compiler.options.context,
                      content
                  }).apply(normalModuleFactory);
              });
          }
      }
      module.exports = DllReferencePlugin;
      

      ExternalModuleFactoryPlugin.js

      plugins\ExternalModuleFactoryPlugin.js

      const ExternalModule = require('webpack/lib/ExternalModule');
      class ExternalModuleFactoryPlugin{
          constructor(type, externals) {
              this.type = type;//var
              this.externals = externals;//{"dll-reference _dll_utils":"_dll_utils"}
          }
          apply(normalModuleFactory) {
              //const globalType = this.type;
              normalModuleFactory.hooks.factory.tap(
                  "ExternalModuleFactoryPlugin",
                  //传进去老的工厂函数,返回新的工厂函数
                  factory => (data, callback) => {
               const dependency = data.dependencies[0];//DelegatedSourceDependency
               let request = dependency.request;// "dll-reference _dll_utils"
               let value = this.externals[request];//_dll_utils
               if(value){//如果是一个外部模块
                   callback(
                       null,
                       new ExternalModule(value, 'var', dependency.request)//_dll_utils
                   );
               }else{//否则 是个普通模块 走老的普通模块工厂的生产模块的逻辑
                   factory(data, callback);
               }
                  }
              );
          }
      }
      module.exports = ExternalModuleFactoryPlugin;
      

      DelegatedModuleFactoryPlugin.js

      plugins\DelegatedModuleFactoryPlugin.js

      const DelegatedModule = require("./DelegatedModule");
      class DelegatedModuleFactoryPlugin {
          constructor(options) {
              this.options = options;
              options.type = options.type || "require";
          }
          apply(normalModuleFactory) {
              normalModuleFactory.hooks.module.tap(
                  "DelegatedModuleFactoryPlugin",
                  module => {
                      if (module.libIdent) {
                          const request = module.libIdent(this.options);
                          if (request && request in this.options.content) {
                              const resolved = this.options.content[request];
                              return new DelegatedModule(
                                  this.options.source,//dll-reference _dll_utils
                                  resolved,//{"id":"./node_modules/_is-promise@4.0.0@is-promise/index.js"}
                                  module//老模块
                              );
                          }
                      }
                      return module;
                  }
              );
          }
      }
      module.exports = DelegatedModuleFactoryPlugin;
      

      DelegatedModule.js

      plugins\DelegatedModule.js

      const { RawSource } = require("webpack-sources");
      const DelegatedSourceDependency = require("webpack/lib/dependencies/DelegatedSourceDependency");
      const Module = require("webpack/lib/Module");
      class DelegatedModule extends Module {
          constructor(sourceRequest, data,originalRequest) {
              super("javascript/dynamic", null);
              this.sourceRequest = sourceRequest;//dll-reference _dll_utils
              this.request = data.id;//{"id":"./node_modules/_is-promise@4.0.0@is-promise/index.js"}
              this.originalRequest = originalRequest;//老模块
          }
          libIdent(options) {//模块ID还是老的模块ID
              return this.originalRequest.libIdent(options);
          }
          identifier() {
              return `delegated ${this.request} from ${this.sourceRequest}`;
          }
          readableIdentifier() {
              return `delegated ${this.request} from ${this.sourceRequest}`;
          }
          size(){
              return 42;
          }
          build(options, compilation, resolver, fs, callback) {
              this.built = true;
              this.buildMeta = {};
              this.buildInfo = {};
              this.delegatedSourceDependency = new DelegatedSourceDependency(
                  this.sourceRequest
              );
              this.addDependency(this.delegatedSourceDependency);
              callback();
          }
          source() {
              let str = `module.exports = (__webpack_require__("${this.sourceRequest}"))(${JSON.stringify(this.request)});`;
              return new RawSource(str);
          }
      }
      module.exports = DelegatedModule;
      

      autodll-webpack-plugin

      • autodll-webpack-plugin

        webpack.config.js

        const path = require('path');
        const AutodllWebpackPlugin = require('autodll-webpack-plugin');
        const HtmlWebpackPlugin = require('html-webpack-plugin');
        module.exports = {
            mode:'development',
            devtool:false,
            entry:'./src/index.js',
            output:{
                path:path.resolve(__dirname,'dist'),//输出目录
                filename:'bundle.js',               //打包后的文件名
                publicPath:''                       //访问路径 
            },
            plugins:[
                new HtmlWebpackPlugin({
                    inject: true,
                    template: './src/index.html',
                }),
                new AutodllWebpackPlugin({
                    inject: true,
                    filename: '[name].dll.js',
                    entry:{
                        utils:['isarray','is-promise']
                    }
                })
            ]
        }
        

        plugin.js

        node_modules_autodll-webpack-plugin@0.4.2@autodll-webpack-plugin\lib\plugin.js

        +const HtmlWebpackPlugin = require("html-webpack-plugin");
        +        compiler.hooks.compilation.tap('AutoDllPlugin', function (compilation) {
        +          if (compilation.hooks.htmlWebpackPluginBeforeHtmlGeneration) {
        +            compilation.hooks.htmlWebpackPluginBeforeHtmlGeneration.tapAsync('AutoDllPlugin', doCompilation);
        +          } else if (HtmlWebpackPlugin.getHooks && HtmlWebpackPlugin.getHooks(compilation)) {
        +            HtmlWebpackPlugin.getHooks(compilation).beforeAssetTagGeneration.tapAsync('AutoDllPlugin', doCompilation);
        +          }
        +        });
        
VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]