DllPlugin
什么是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
(图片来源网络,侵删)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); + } + });
- autodll-webpack-plugin
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。