{"componentChunkName":"component---src-templates-blog-post-js","path":"/2019/12/17/【webpack配置】二、插件系统/","result":{"data":{"content":{"edges":[{"node":{"id":"6b15bf89-919c-5c2f-9879-8fdb5e43472d","html":"<p>webpack本身可以定义为事件驱动、基于插件的打包器。插件是webpack生态系统的关键拼图，使得社区开发者可以hook到关键事件中、可以侵入到webpack的编译过程的每一切面。</p>\n<h2 id=\"aop\" style=\"position:relative;\"><a href=\"#aop\" aria-label=\"aop permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>AOP</h2>\n<p><a href=\"https://en.wikipedia.org/wiki/Aspect-oriented_programming\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">AOP</a>（Aspect-Oriented Programming）：面向切面编程，是对面向对象编程的扩充，在实现对关注点模块化扩展的同时，保证了与原系统的低耦合性。即使你没了解过这个思想，在日常的开发工作中，像表单验证、埋点日志收集、路由钩子、装饰器decorators等场景，都有这种模式的影子。</p>\n<p>webpack的tapable就是遵循AOP模式的一个实现。</p>\n<h2 id=\"tapable\" style=\"position:relative;\"><a href=\"#tapable\" aria-label=\"tapable permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Tapable</h2>\n<p>Tapable作为webpack扩展功能的骨架与核心，与Nodejs的EventEmitter类似。扩展tapable的类和对象，我们称之为tapable实例，即是我们通常所说的插件。借助tapable提供的钩子，我们可以侵入到编译阶段的每个过程中。\n<img src=\"https://2img.net/h/i968.photobucket.com/albums/ae170/laughingjacky/Blog%20Assets%202019/tapable-skeleton_zpsbr3gitgy.png\" alt=\"Tapable skeleton\"></p>\n<p>通过一个简单的demo，看一下Tapable的基本用法👇：</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// 为了测试拦截器的loop，我们选用loopHook</span>\n<span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span>SyncLoopHook<span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'tapable'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> syncLoopHook <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">SyncLoopHook</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token string\">'name'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'age'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// tap第一个插件，传入上下文</span>\nsyncLoopHook<span class=\"token punctuation\">.</span><span class=\"token function\">tap</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    name<span class=\"token operator\">:</span> <span class=\"token string\">'firstPlugin'</span><span class=\"token punctuation\">,</span>\n    context<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">context<span class=\"token punctuation\">,</span> name<span class=\"token punctuation\">,</span> age</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>name<span class=\"token punctuation\">,</span> age<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>context<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// tap第零个插件，放在第一个前面</span>\nsyncLoopHook<span class=\"token punctuation\">.</span><span class=\"token function\">tap</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    name<span class=\"token operator\">:</span> <span class=\"token string\">'zeroPlugin'</span><span class=\"token punctuation\">,</span>\n    before<span class=\"token operator\">:</span> <span class=\"token string\">'firstPlugin'</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">name<span class=\"token punctuation\">,</span> age</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>name<span class=\"token punctuation\">,</span> age<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// 添加上下文，观察call、register、loop、tap四个阶段</span>\nsyncLoopHook<span class=\"token punctuation\">.</span><span class=\"token function\">intercept</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    context<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function-variable function\">call</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">context<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>args</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'arguments: '</span><span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>args<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function-variable function\">register</span><span class=\"token operator\">:</span> <span class=\"token parameter\">tap</span> <span class=\"token operator\">=></span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'tap name: '</span><span class=\"token punctuation\">,</span> tap<span class=\"token punctuation\">.</span>name<span class=\"token punctuation\">)</span> <span class=\"token operator\">||</span> tap<span class=\"token punctuation\">,</span>\n    <span class=\"token function-variable function\">loop</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">context<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>args</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'loop args: '</span><span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>args<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function-variable function\">tap</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">context<span class=\"token punctuation\">,</span> tap</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n        console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'tap event: '</span><span class=\"token punctuation\">,</span> tap<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>context<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            context<span class=\"token punctuation\">.</span>name <span class=\"token operator\">=</span> <span class=\"token string\">'John'</span><span class=\"token punctuation\">;</span>\n            context<span class=\"token punctuation\">.</span>age <span class=\"token operator\">=</span> <span class=\"token number\">36</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// call the hook</span>\n<span class=\"token function\">syncLoopHook</span><span class=\"token punctuation\">.</span><span class=\"token function\">call</span><span class=\"token punctuation\">(</span><span class=\"token string\">'David'</span><span class=\"token punctuation\">,</span> <span class=\"token number\">25</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>通过控制台的输出，可以看到Tapable整个流程为register➡️call➡️loop➡️tap➡️tap callback。</p>\n<p>网上介绍这个API的文章很多，在这儿就不赘述了，建议直接看github的<a href=\"https://github.com/webpack/tapable/tree/tapable-1\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">README</a>。</p>\n<h2 id=\"webpack工作流\" style=\"position:relative;\"><a href=\"#webpack%E5%B7%A5%E4%BD%9C%E6%B5%81\" aria-label=\"webpack工作流 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>webpack工作流</h2>\n<p>要写好一个插件，必须了解webpack插件的这些切面是如何工作的。</p>\n<p>通用模块打包器的大致流程是依赖解析➡️模块映射➡️打包，在webpack中，为了使用nodeJS的文件系统，第一个被这样处理的就是<a href=\"https://webpack.js.org/plugins/internal-plugins/#nodeenvironmentplugin\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">NodeEnvironmentPlugin</a>。</p>\n<p>下面是webpack的七大模块：\n<img src=\"https://2img.net/h/i968.photobucket.com/albums/ae170/laughingjacky/Blog%20Assets%202019/webpack-arch_zpsaossyeof.png\" alt=\"webpack arch\"></p>\n<h3 id=\"开机键compiler\" style=\"position:relative;\"><a href=\"#%E5%BC%80%E6%9C%BA%E9%94%AEcompiler\" aria-label=\"开机键compiler permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>开机键Compiler</h3>\n<p>Compiler的作用可以用两行伪代码来表示：</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> webpack <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'webpack'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> compiler <span class=\"token operator\">=</span> <span class=\"token function\">webpack</span><span class=\"token punctuation\">(</span>someConfig<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>作为插件开发者，需要从webpack机制/流程/事件发生的时间点来切入，添加你想实现的功能及特性，compiler作为top-level实例，同时也是webpack runtime, 正担任这个角色。它控制着webpack的启动与停止，使你能用上run、emit这些钩子。</p>\n<h3 id=\"藏宝图compilation\" style=\"position:relative;\"><a href=\"#%E8%97%8F%E5%AE%9D%E5%9B%BEcompilation\" aria-label=\"藏宝图compilation permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>藏宝图Compilation</h3>\n<p>compilation作为compiler的产物，描绘了整个app依赖关系的深度遍历藏宝图，webpack通过compilation掌握你的代码依赖全貌。webpack的load, seal, optimize, chunk, hash都在这一阶段完成，因此具有optimize-modules、seal及optimize-chunk-assets等hook。</p>\n<p><img src=\"https://2img.net/h/i968.photobucket.com/albums/ae170/laughingjacky/Blog%20Assets%202019/webpack-compilation_zpsrcr5pbdc.jpg\" alt=\"webpack-compilaton\"></p>\n<h3 id=\"寻路resolver\" style=\"position:relative;\"><a href=\"#%E5%AF%BB%E8%B7%AFresolver\" aria-label=\"寻路resolver permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>寻路resolver</h3>\n<p>类似于nodejs的resolver处理文件路径，webpack的resolver由<a href=\"https://github.com/webpack/enhanced-resolve\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">enhanced-resolver</a>创建。我们也可以通过resolveLoader或者自己编写<a href=\"https://github.com/shaketbaby/directory-named-webpack-plugin\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">插件</a>自定义模块解析策略。</p>\n<p><img src=\"https://2img.net/h/i968.photobucket.com/albums/ae170/laughingjacky/Blog%20Assets%202019/webpack-resolver_zpsuuef66tv.jpg\" alt=\"webpack-resolver\"></p>\n<h3 id=\"同声传译loaders\" style=\"position:relative;\"><a href=\"#%E5%90%8C%E5%A3%B0%E4%BC%A0%E8%AF%91loaders\" aria-label=\"同声传译loaders permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>同声传译loaders</h3>\n<p>在resolve文件依赖进行build过程中，肯定会寻找到非JS的文件。这时就需要loader根据ruleSet将!@#$%$^&#x26;变成标准模块，加到chunk中。</p>\n<h3 id=\"模块工厂module-factory\" style=\"position:relative;\"><a href=\"#%E6%A8%A1%E5%9D%97%E5%B7%A5%E5%8E%82module-factory\" aria-label=\"模块工厂module factory permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>模块工厂Module Factory</h3>\n<p>ModuleFactory将resolver、loaders和源模块实例零件进行黏合加工，产出模块对象到内存中。\n除了Normal类型之外，还有ContextFactory用于处理上下文的动态依赖。</p>\n<p><img src=\"https://2img.net/h/i968.photobucket.com/albums/ae170/laughingjacky/Blog%20Assets%202019/webpack-module-factory_zpshw5mzeso.jpg\" alt=\"webpack-module-factory\"></p>\n<h3 id=\"寻宝科学家parser\" style=\"position:relative;\"><a href=\"#%E5%AF%BB%E5%AE%9D%E7%A7%91%E5%AD%A6%E5%AE%B6parser\" aria-label=\"寻宝科学家parser permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>寻宝科学家Parser</h3>\n<p>AST是计算机与人类的桥梁，Parser是Module与bundle Template的桥梁。webpack parser使用的是acorn引擎实现AST。</p>\n<p><img src=\"https://2img.net/h/i968.photobucket.com/albums/ae170/laughingjacky/Blog%20Assets%202019/webpack-parser_zpsx2m3mx4i.jpg\" alt=\"webpack-parser\"></p>\n<h3 id=\"圣诞树的外衣template\" style=\"position:relative;\"><a href=\"#%E5%9C%A3%E8%AF%9E%E6%A0%91%E7%9A%84%E5%A4%96%E8%A1%A3template\" aria-label=\"圣诞树的外衣template permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>圣诞树的外衣Template</h3>\n<p>template顾名思义作为文件输出的数据模版，将template subclass组合到一起，生成最后打包文件的框架结构。当然，由于模块类型的不同，template有多种类型，包括:</p>\n<ul>\n<li>MainTemplate: 运行时bundle的wrapper</li>\n<li>ChunkTemplate: 控制chunk wrapper的形式和格式</li>\n<li>ModuleTemplate: 模块模版</li>\n<li>DependencyTemplate: 依赖模版</li>\n<li>RuntimeTemplate: 运行时模版</li>\n</ul>\n<p><img src=\"https://2img.net/h/i968.photobucket.com/albums/ae170/laughingjacky/Blog%20Assets%202019/webpack-template_zps2ih4abgu.jpg\" alt=\"webpack-template\"></p>\n<h2 id=\"总结\" style=\"position:relative;\"><a href=\"#%E6%80%BB%E7%BB%93\" aria-label=\"总结 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>总结</h2>\n<p>当我们开启热更新的时候，webpack会按照这种运作机制不断地解析文件、生成依赖图、输出bundle文件。正是因为webpack采用基于切面设计的插件系统和基于插件的运作体系，我们才能够编写优秀的自定义插件实现增量更新，才能够根据差异性的应用场景持续添加特性，达成科学快速的工程化解决方案。</p>\n<h2 id=\"相关资料\" style=\"position:relative;\"><a href=\"#%E7%9B%B8%E5%85%B3%E8%B5%84%E6%96%99\" aria-label=\"相关资料 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>相关资料</h2>\n<ol>\n<li><a href=\"https://github.com/thelarkinn/artsy-webpack-tour\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">artsy-webpack-tour</a></li>\n<li><a href=\"https://medium.com/webpack/the-contributors-guide-to-webpack-part-2-9fd5e658e08c\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">The Contributors Guide to webpack — Part 2\n</a></li>\n<li><a href=\"https://www.cnblogs.com/tugenhua0707/p/11317557.html\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">webpack4核心模块tapable源码解析</a></li>\n<li><a href=\"https://alligator.io/js/create-custom-webpack-plugin/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Creating a Custom webpack Plugin\n</a></li>\n<li>头图来自：<a href=\"https://juejin.im/post/5c0206626fb9a049bc4c6540\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">从Webpack源码探究打包流程，萌新也能看懂～</a></li>\n<li>插图部分来自：<a href=\"https://www.youtube.com/watch?v=H3g0BdyVVxA&#x26;list=PLw5h0DiJ-9PDZ0i7cZK7NqrsMRENAR48i&#x26;index=3\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">everything-is-a-plugin</a></li>\n</ol>","fields":{"slug":"/【webpack配置】二、插件系统/"},"tableOfContents":"<ul>\n<li><a href=\"//#aop\">AOP</a></li>\n<li><a href=\"//#tapable\">Tapable</a></li>\n<li>\n<p><a href=\"//#webpack%E5%B7%A5%E4%BD%9C%E6%B5%81\">webpack工作流</a></p>\n<ul>\n<li><a href=\"//#%E5%BC%80%E6%9C%BA%E9%94%AEcompiler\">开机键Compiler</a></li>\n<li><a href=\"//#%E8%97%8F%E5%AE%9D%E5%9B%BEcompilation\">藏宝图Compilation</a></li>\n<li><a href=\"//#%E5%AF%BB%E8%B7%AFresolver\">寻路resolver</a></li>\n<li><a href=\"//#%E5%90%8C%E5%A3%B0%E4%BC%A0%E8%AF%91loaders\">同声传译loaders</a></li>\n<li><a href=\"//#%E6%A8%A1%E5%9D%97%E5%B7%A5%E5%8E%82module-factory\">模块工厂Module Factory</a></li>\n<li><a href=\"//#%E5%AF%BB%E5%AE%9D%E7%A7%91%E5%AD%A6%E5%AE%B6parser\">寻宝科学家Parser</a></li>\n<li><a href=\"//#%E5%9C%A3%E8%AF%9E%E6%A0%91%E7%9A%84%E5%A4%96%E8%A1%A3template\">圣诞树的外衣Template</a></li>\n</ul>\n</li>\n<li><a href=\"//#%E6%80%BB%E7%BB%93\">总结</a></li>\n<li><a href=\"//#%E7%9B%B8%E5%85%B3%E8%B5%84%E6%96%99\">相关资料</a></li>\n</ul>","frontmatter":{"id":null,"description":"Sean Larkin曾在演讲中表示，webpack中80%的部分都是由插件机制完成。随着我们对webpack研究的深入，会发现其内部的每样东西，都被模块化为单一职责的工具抽象类。","title":"【webpack配置】二、插件系统","slug":"/","date":"2019年12月17日","tags":["webpack","tapable"],"headerImage":"  https://2img.net/h/i968.photobucket.com/albums/ae170/laughingjacky/Blog%20Assets%202019/webpacn-series-2-headimage_zps1wcoczne.png"}},"previous":null,"next":null}]},"site":{"siteMetadata":{"title":"王晓博 - 银河系漫游指南","description":"如果这个博客好久不更新了,说明我更浑浑噩噩了"}}},"pageContext":{"id":"6b15bf89-919c-5c2f-9879-8fdb5e43472d","index":1}},"staticQueryHashes":[]}