webpack插件

06-13 1456阅读

plugin

插件向第三方开发者提供了 webpack 引擎中完整的能力。使用阶段式的构建回调,开发者可以引入它们自己的行为到 webpack 构建流程中。创建插件比创建 loader 更加高级,因为你将需要理解一些 webpack 底层的内部特性来做相应的钩子

webpack插件
(图片来源网络,侵删)

为什么需要一个插件

  • webpack 基础配置无法满足需求
  • 插件几乎能够任意更改 webpack 编译结果
  • webpack 内部也是通过大量内部插件实现的

    可以加载插件的常用对象

    对象钩子
    Compilerrun,compile,compilation,make,emit,done
    CompilationbuildModule,normalModuleLoader,succeedModule,finishModules,seal,optimize,after-seal
    Module FactorybeforeResolver,afterResolver,module,parser
    Module
    Parserprogram,statement,call,expression
    Templatehash,bootstrap,localVars,render

    创建插件

    • 插件是一个类
    • 类上有一个apply的实例方法
    • apply的参数是compiler
      class DonePlugin {
          constructor(options) {
              this.options = options;
          }
          apply(compiler) {
          }
      }
      module.exports = DonePlugin;
      

      Compiler 和 Compilation

      在插件开发中最重要的两个资源就是compiler和compilation对象。理解它们的角色是扩展 webpack 引擎重要的第一步。

      • compiler 对象代表了完整的 webpack 环境配置。这个对象在启动 webpack 时被一次性建立,并配置好所有可操作的设置,包括 options,loader 和 plugin。当在 webpack 环境中应用一个插件时,插件将收到此 compiler 对象的引用。可以使用它来访问 webpack 的主环境。
      • compilation 对象代表了一次资源版本构建。当运行 webpack 开发环境中间件时,每当检测到一个文件变化,就会创建一个新的 compilation,从而生成一组新的编译资源。一个 compilation 对象表现了当前的模块资源、编译生成资源、变化的文件、以及被跟踪依赖的状态信息。compilation 对象也提供了很多关键时机的回调,以供插件做自定义处理时选择使用。

        基本插件架构

        • 插件是由「具有 apply 方法的 prototype 对象」所实例化出来的
        • 这个 apply 方法在安装插件时,会被 webpack compiler 调用一次
        • apply 方法可以接收一个 webpack compiler 对象的引用,从而可以在回调函数中访问到 compiler 对象

          使用插件代码

          • [使用插件]https://github.com/webpack/webpack/blob/master/lib/webpack.js#L60-L69)
            if (options.plugins && Array.isArray(options.plugins)) {
              for (const plugin of options.plugins) {
                plugin.apply(compiler);
              }
            }
            

            Compiler 插件

            • [done: new AsyncSeriesHook(“stats”])

              同步

              class DonePlugin {
                constructor(options) {
                  this.options = options;
                }
                apply(compiler) {
                  compiler.hooks.done.tap("DonePlugin", (stats) => {
                    console.log("Hello ", this.options.name);
                  });
                }
              }
              module.exports = DonePlugin;
              

              异步

              class DonePlugin {
                constructor(options) {
                  this.options = options;
                }
                apply(compiler) {
                  compiler.hooks.done.tapAsync("DonePlugin", (stats, callback) => {
                    console.log("Hello ", this.options.name);
                    callback();
                  });
                }
              }
              module.exports = DonePlugin;
              

              使用插件

              • 要安装这个插件,只需要在你的 webpack 配置的 plugin 数组中添加一个实例
                const DonePlugin = require("./plugins/DonePlugin");
                module.exports = {
                  entry: "./src/index.js",
                  output: {
                    path: path.resolve("build"),
                    filename: "bundle.js",
                  },
                  plugins: [new DonePlugin({ name: "hs" })],
                };
                

                compilation 插件

                • 使用 compiler 对象时,你可以绑定提供了编译 compilation 引用的回调函数,然后拿到每次新的 compilation 对象。这些 compilation 对象提供了一些钩子函数,来钩入到构建流程的很多步骤中

                  webpack-assets-plugin.js

                  plugins\webpack-assets-plugin.js

                  //编写个Compilation插件,用来打印本次产出的代码块和文件
                  class WebpackAssetsPlugin {
                    constructor(options) {
                      this.options = options;
                    }
                    apply(compiler) {
                      //每当webpack开启一次新的编译 ,就会创建一个新的compilation
                      compiler.hooks.compilation.tap('WebpackAssetsPlugin', (compilation) => {
                        //每次根据chunk创建一个新的文件后会触发一次chunkAsset
                        compilation.hooks.chunkAsset.tap('WebpackAssetsPlugin', (chunk, filename) => {
                          console.log(chunk.name || chunk.id, filename);
                        });
                      });
                    }
                  }
                  module.exports = WebpackAssetsPlugin;
                  

                  打包 zip

                  • webpack-sources

                    webpack-archive-plugin.js

                    plugins\webpack-archive-plugin.js

                    const jszip = require('jszip');
                    const { RawSource } = require('webpack-sources');
                    const { Compilation } = require('webpack');
                    /**
                     * 1.如何获取打出后的文件名和文件内容
                     * 2.如何打压缩包 
                     * 3.如何向目标目录输出压缩包
                     */
                    class WebpackArchivePlugin {
                      constructor(options) {
                        this.options = options;
                      }
                      apply(compiler) {
                        compiler.hooks.compilation.tap('WebpackAssetsPlugin', (compilation) => {
                          //当确定好文件,当你处理每个资源的时候处执行
                          compilation.hooks.processAssets.tapPromise({ name: 'WebpackArchivePlugin' }, (assets) => {
                            const zip = new jszip();
                            for (const filename in assets) {
                              const sourceObj = assets[filename];
                              const sourceCode = sourceObj.source();
                              zip.file(filename, sourceCode);
                            }
                            return zip.generateAsync({ type: 'nodebuffer' }).then(zipContent => {
                              assets[`archive_${Date.now()}。zip`] = new RawSource(zipContent);
                            });
                          });
                        });
                      }
                    }
                    module.exports = WebpackArchivePlugin;
                    

                    webpack.config.js

                    webpack.config.js

                    const WebpackArchivePlugin = require('./plugins/webpack-archive-plugin');
                      plugins: [
                    +   new WebpackArchivePlugin({
                    +     filename:'[timestamp].zip'
                    +   })
                    ]
                    

                    自动外链

                    自动外链

                    使用外部类库

                    • 手动指定 external
                    • 手动引入 script

                      能否检测代码中的 import 自动处理这个步骤?

                      {
                        externals:{
                          //key jquery是要require或import 的模块名,值 jQuery是一个全局变量名
                        'jquery':'$'
                      }, 
                        module:{}
                      }
                      

                      思路

                      • 解决 import 自动处理external和script的问题,需要怎么实现,该从哪方面开始考虑
                      • 依赖 当检测到有import该library时,将其设置为不打包类似exteral,并在指定模版中加入 script,那么如何检测 import?这里就用Parser
                      • external依赖 需要了解 external 是如何实现的,webpack 的 external 是通过插件ExternalsPlugin实现的,ExternalsPlugin 通过tap NormalModuleFactory 在每次创建 Module 的时候判断是否是ExternalModule
                      • webpack4 加入了模块类型之后,Parser获取需要指定类型 moduleType,一般使用javascript/auto即可

                        使用 plugins

                        plugins: [
                          new HtmlWebpackPlugin({
                                    template:'./src/index.html'
                          }),
                          new AutoExternalPlugin({
                              jquery:{//自动把jquery模块变成一个外部依赖模块
                                  variable:'jQuery',//不再打包,而是从window.jQuery变量上获取jquery对象
                                  url:'https://cdn.bootcss.com/jquery/3.1.0/jquery.js'//CDN脚本
                              },
                              lodash:{//自动把jquery模块变成一个外部依赖模块
                                  variable:'_',//不再打包,而是从window.jQuery变量上获取jquery对象
                                  url:'https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.js'//CDN脚本
                              }
                          })
                        ];
                        

                        AutoExternalPlugin

                        • ExternalsPlugin.js
                        • ExternalModuleFactoryPlugin
                        • ExternalModule.js
                        • parser
                        • factory
                        • htmlWebpackPluginAlterAssetTags

                          AsyncSeriesBailHook factorize

                          let { AsyncSeriesBailHook } = require("tapable");
                          let factorize = new AsyncSeriesBailHook(['resolveData']);
                          //最后总得返回一个模块吧 switch case default 
                          factorize.tapAsync('factory1', (resolveData, callback) => {
                            if (resolveData === 'jquery') {
                              callback(null, {
                                id: resolveData,
                                type: '外部模块',
                                source: 'window.jQuery'
                              });
                            } else {
                              callback(null);
                            }
                          });
                          //生成正常模块的工厂函数最后一个工厂函数了,
                          factorize.tapAsync('factory2', (resolveData, callback) => {
                            callback(null, { id: resolveData, type: '正常模块', source: 'webpack打包后的内容' });
                          });
                          factorize.callAsync('jquery', (err, module) => {
                            console.log(module);
                          });
                          factorize.callAsync('lodash', (err, module) => {
                            console.log(module);
                          });
                          

                          plugins\auto-external-plugin.js

                          const { ExternalModule } = require("webpack");
                          const HtmlWebpackPlugin = require('html-webpack-plugin');
                          /**
                           * 1.需要向输出html文件中添加CDN脚本引用
                           * 2.在打包生产模块的时候,截断正常的打包逻辑,变成外部依赖模块
                           */
                          class AutoExternalPlugin{
                              constructor(options){
                                  this.options = options;
                                  this.externalModules = Object.keys(this.options);//['jquery'] 进行自动外键的模块
                                  this.importedModules = new Set();//存放着所有的实际真正使用到的外部依赖模块
                              }
                              apply(compiler){
                                  //每种模块会对应一个模块工厂 普通模块对应的就是普通模块工厂
                                  //https://webpack.docschina.org/api/normalmodulefactory-hooks/
                                  compiler.hooks.normalModuleFactory.tap('AutoExternalPlugin',(normalModuleFactory)=>{
                                      //https://webpack.docschina.org/api/parser/#root
                                      normalModuleFactory.hooks.parser
                                      .for('javascript/auto')//普通 的JS文件对应的钩子就是'javascript/auto'
                                      .tap('AutoExternalPlugin',parser=>{
                                          //在parser遍历语法的过程中,如果遍历到了import节点
                                          //https://webpack.docschina.org/api/parser/#import
                                          parser.hooks.import.tap('AutoExternalPlugin',(statement,source)=>{
                                              if(this.externalModules.includes(source)){
                                                  this.importedModules.add(source);
                                              }
                                          });
                                          //https://webpack.docschina.org/api/parser/#call
                                          //call=HookMap key方法名 值是这个方法对应的钩子
                                          parser.hooks.call.for('require').tap('AutoExternalPlugin',(expression)=>{
                                              let value = expression.arguments[0].value;
                                              if(this.externalModules.includes(value)){
                                                  this.importedModules.add(value);
                                              }
                                          });
                                      })
                                      //2.改造模块的生产过程,如果是外链模块,就直接生产一个外链模块返回
                                      //https://webpack.docschina.org/api/normalmodulefactory-hooks/
                                      normalModuleFactory.hooks.factorize.tapAsync('AutoExternalPlugin',(resolveData,callback)=>{
                                          let {request} = resolveData;//模块名 jquery lodash
                                          if(this.externalModules.includes(request)){
                                              let {variable} = this.options[request];
                                              //request=jquery window.jQuery
                                              callback(null,new ExternalModule(variable,'window',request));
                                          }else{
                                              callback(null);//如果是正常模块,直接向后执行。走正常的打包模块的流程
                                          }
                                      });
                                  });
                                  //是往输出的HTML中添加一个新的CDN Script标签
                                  compiler.hooks.compilation.tap('AutoExternalPlugin',(compilation)=>{
                                      HtmlWebpackPlugin.getHooks(compilation).alterAssetTags.tapAsync('AutoExternalPlugin',(htmlData,callback)=>{
                                          //console.log(JSON.stringify(htmlData,null,2));
                                          Reflect.ownKeys(this.options).filter(key=>this.importedModules.has(key)).forEach(key=>{
                                              //jquery
                                              htmlData.assetTags.scripts.unshift({
                                                  tagName:'script',
                                                  voidTag:false,
                                                  attributes:{
                                                      defer:false,
                                                      src:this.options[key].url
                                                  }
                                              });
                                          })
                                          callback(null,htmlData);
                                      });
                                  });
                              }
                          }
                          module.exports = AutoExternalPlugin;
                          /**
                           * Node {
                            type: 'ImportDeclaration',
                            start: 0,
                            end: 23,
                            loc: SourceLocation {
                              start: Position { line: 1, column: 0 },
                              end: Position { line: 1, column: 23 }
                            },
                            range: [ 0, 23 ],
                            specifiers: [
                              Node {
                                type: 'ImportDefaultSpecifier',
                                start: 7,
                                end: 8,
                                loc: [SourceLocation],
                                range: [Array],
                                local: [Node]
                              }
                            ],
                            source: Node {
                              type: 'Literal',
                              start: 14,
                              end: 22,
                              loc: SourceLocation { start: [Position], end: [Position] },
                              range: [ 14, 22 ],
                              value: 'jquery',
                              raw: "'jquery'"
                            }
                          }
                          jquery
                           */
                          

                          AsyncQueue

                          AsyncQueue

                          let AsyncQueue = require('webpack/lib/util/AsyncQueue');
                          let AsyncQueue = require('./AsyncQueue');
                          function processor(item, callback) {
                              setTimeout(() => {
                                  console.log('process',item);
                                  callback(null, item);
                              }, 3000);
                          }
                          const getKey = (item) => {
                              return item.key;
                          }
                          let queue  = new AsyncQueue({
                              name:'createModule',parallelism:3,processor,getKey
                          });
                          const start = Date.now();
                          let item1 = {key:'module1'};
                          queue.add(item1,(err,result)=>{
                              console.log(err,result);
                              console.log(Date.now() - start);
                          });
                          queue.add(item1,(err,result)=>{
                              console.log(err,result);
                              console.log(Date.now() - start);
                          });
                          queue.add({key:'module2'},(err,result)=>{
                              console.log(err,result);
                              console.log(Date.now() - start);
                          });
                          queue.add({key:'module3'},(err,result)=>{
                              console.log(err,result);
                              console.log(Date.now() - start);
                          });
                          queue.add({key:'module4'},(err,result)=>{
                              console.log(err,result);
                              console.log(Date.now() - start);
                          });
                          

                          use.js

                          use.js

                          const QUEUED_STATE = 0;//已经 入队,待执行
                          const PROCESSING_STATE = 1;//处理中
                          const DONE_STATE = 2;//处理完成
                          class ArrayQueue {
                              constructor() {
                                  this._list = [];
                              }
                              enqueue(item) {
                                  this._list.push(item);//[1,2,3]
                              }
                              dequeue() {
                                  return this._list.shift();//移除并返回数组中的第一个元素
                              }
                          }
                          class AsyncQueueEntry {
                              constructor(item, callback) {
                                  this.item = item;//任务的描述
                                  this.state = QUEUED_STATE;//这个条目当前的状态
                                  this.callback = callback;//任务完成的回调
                              }
                          }
                          class AsyncQueue {
                              constructor({ name, parallelism, processor, getKey }) {
                                  this._name = name;//队列的名字
                                  this._parallelism = parallelism;//并发执行的任务数
                                  this._processor = processor;//针对队列中的每个条目执行什么操作
                                  this._getKey = getKey;//函数,返回一个key用来唯一标识每个元素
                                  this._entries = new Map();
                                  this._queued = new ArrayQueue();//将要执行的任务数组队列 
                                  this._activeTasks = 0;//当前正在执行的数,默认值1
                                  this._willEnsureProcessing = false;//是否将要开始处理
                              }
                              add = (item, callback) => {
                                  const key = this._getKey(item);//获取这个条目对应的key
                                  const entry = this._entries.get(key);//获取 这个key对应的老的条目
                                  if (entry !== undefined) {
                                      if (entry.state === DONE_STATE) {
                                          process.nextTick(() => callback(entry.error, entry.result));
                                      } else if (entry.callbacks === undefined) {
                                          entry.callbacks = [callback];
                                      } else {
                                          entry.callbacks.push(callback);
                                      }
                                      return;
                                  }
                                  const newEntry = new AsyncQueueEntry(item, callback);//创建一个新的条目
                                  this._entries.set(key, newEntry);//放到_entries
                                  this._queued.enqueue(newEntry);//把这个新条目放放队列
                                  if (this._willEnsureProcessing === false) {
                                      this._willEnsureProcessing = true;
                                      setImmediate(this._ensureProcessing);
                                  }
                              }
                              _ensureProcessing = () => {
                                  //如果当前的激活的或者 说正在执行任务数行小于并发数
                                  while (this._activeTasks  {
                                  this._processor(entry.item, (e, r) => {
                                      this._handleResult(entry, e, r);
                                  });
                              }
                              _handleResult = (entry, error, result) => {
                                  const callback = entry.callback;
                                  const callbacks = entry.callbacks;
                                  entry.state = DONE_STATE;//把条目的状态设置为已经完成
                                  entry.callback = undefined;//把callback
                                  entry.callbacks = undefined;
                                  entry.result = result;//把结果赋给entry
                                  entry.error = error;//把错误对象赋给entry
                                  callback(error, result);
                                  if (callbacks !== undefined) {
                                      for (const callback of callbacks) {
                                          callback(error, result);
                                      }
                                  }
                                  this._activeTasks--;
                                  if (this._willEnsureProcessing === false) {
                                      this._willEnsureProcessing = true;
                                      setImmediate(this._ensureProcessing);
                                  }
                              }
                          }
                          module.exports = AsyncQueue;
                          

                          参考

                          • Node.js SDK
                          • writing-a-plugin
                          • api/plugins

                            钩子集合

                            • wepback-plugin-visualizer

                              收集

                                      Object.keys(this.hooks).forEach(hookName => {
                                          const hook = this.hooks[hookName];
                                          if (hook instanceof HookMap) {
                                              for (let key of hook._map.keys()) {
                                                  hook.for(key).tap('flow', () => {
                                                      console.log(`|JavascriptParser|${hookName}|${hook.for(key).constructor.name}|${hook._args}|`);
                                                  });
                                              }
                                          } else {
                                              hook.tap('flow', () => {
                                                  console.log(`|JavascriptParser|${hookName}|${hook.constructor.name}|${hook._args}|`);
                                              });
                                          }
                                      });
                              

                              触发时机

                              • hooks
                                对象钩子名称类型参数含义
                                CompilerenvironmentSyncHook在编译器准备环境时调用,时机就在配置文件中初始化插件之后
                                CompilerafterEnvironmentSyncHook
                                CompilerentryOptionSyncBailHookcontext,entry
                                CompilerafterPluginsSyncHookcompiler
                                CompilerafterResolversSyncHookcompiler
                                CompilerinitializeSyncHook
                                CompilerbeforeRunAsyncSeriesHookcompiler
                                CompilerrunAsyncSeriesHookcompiler
                                CompilerinfrastructureLogSyncBailHookorigin,type,args
                                CompilerreadRecordsAsyncSeriesHook
                                CompilernormalModuleFactorySyncHooknormalModuleFactory
                                CompilercontextModuleFactorySyncHookcontextModuleFactory
                                CompilerbeforeCompileAsyncSeriesHookparams
                                CompilercompileSyncHookparams
                                CompilerthisCompilationSyncHookcompilation,params
                                CompilercompilationSyncHookcompilation,params
                                CompilermakeAsyncParallelHookcompilation
                                CompilationaddEntrySyncHookentry,options
                                NormalModuleFactorybeforeResolveAsyncSeriesBailHookresolveData
                                NormalModuleFactoryfactorizeAsyncSeriesBailHookresolveData
                                NormalModuleFactoryresolveAsyncSeriesBailHookresolveData
                                NormalModuleFactoryafterResolveAsyncSeriesBailHookresolveData
                                NormalModuleFactorycreateModuleAsyncSeriesBailHookcreateData,resolveData
                                NormalModuleFactorymoduleSyncWaterfallHookmodule,createData,resolveData
                                CompilationbuildModuleSyncHookmodule
                                CompilationnormalModuleLoaderSyncHookloaderContext,module
                                JavascriptParserprogramSyncBailHookast,comments
                                JavascriptParserpreStatementSyncBailHookstatement
                                JavascriptParserpreStatementSyncBailHookstatement
                                JavascriptParserblockPreStatementSyncBailHookdeclaration
                                JavascriptParserpreDeclaratorSyncBailHookdeclarator,statement
                                JavascriptParserblockPreStatementSyncBailHookdeclaration
                                JavascriptParserstatementSyncBailHookstatement
                                JavascriptParserdeclaratorSyncBailHookdeclarator,statement
                                JavascriptParserstatementSyncBailHookstatement
                                JavascriptParserfinishSyncBailHookast,comments
                                CompilationsucceedModuleSyncHookmodule
                                NormalModuleFactorybeforeResolveAsyncSeriesBailHookresolveData
                                NormalModuleFactoryfactorizeAsyncSeriesBailHookresolveData
                                NormalModuleFactoryresolveAsyncSeriesBailHookresolveData
                                NormalModuleFactoryafterResolveAsyncSeriesBailHookresolveData
                                NormalModuleFactorycreateModuleAsyncSeriesBailHookcreateData,resolveData
                                NormalModuleFactorymoduleSyncWaterfallHookmodule,createData,resolveData
                                CompilationbuildModuleSyncHookmodule
                                CompilationnormalModuleLoaderSyncHookloaderContext,module
                                JavascriptParserprogramSyncBailHookast,comments
                                JavascriptParserpreStatementSyncBailHookstatement
                                JavascriptParserblockPreStatementSyncBailHookdeclaration
                                JavascriptParserstatementSyncBailHookstatement
                                JavascriptParserfinishSyncBailHookast,comments
                                CompilationsucceedModuleSyncHookmodule
                                CompilationsucceedEntrySyncHookentry,options,module
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilerfinishMakeAsyncSeriesHookcompilation
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationfinishModulesAsyncSeriesHookmodules
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationsealSyncHook
                                CompilationoptimizeDependenciesSyncBailHookmodules
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationafterOptimizeDependenciesSyncHookmodules
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationbeforeChunksSyncHook
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationafterChunksSyncHookchunks
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationoptimizeSyncHook
                                CompilationoptimizeModulesSyncBailHookmodules
                                CompilationafterOptimizeModulesSyncHookmodules
                                CompilationoptimizeChunksSyncBailHookchunks,chunkGroups
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationafterOptimizeChunksSyncHookchunks,chunkGroups
                                CompilationoptimizeTreeAsyncSeriesHookchunks,modules
                                CompilationafterOptimizeTreeSyncHookchunks,modules
                                CompilationoptimizeChunkModulesAsyncSeriesBailHookchunks,modules
                                CompilationafterOptimizeChunkModulesSyncHookchunks,modules
                                CompilationshouldRecordSyncBailHook
                                CompilationreviveModulesSyncHookmodules,records
                                CompilationbeforeModuleIdsSyncHookmodules
                                CompilationmoduleIdsSyncHookmodules
                                CompilationoptimizeModuleIdsSyncHookmodules
                                CompilationafterOptimizeModuleIdsSyncHookmodules
                                CompilationreviveChunksSyncHookchunks,records
                                CompilationbeforeChunkIdsSyncHookchunks
                                CompilationchunkIdsSyncHookchunks
                                CompilationoptimizeChunkIdsSyncHookchunks
                                CompilationafterOptimizeChunkIdsSyncHookchunks
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationrecordModulesSyncHookmodules,records
                                CompilationrecordChunksSyncHookchunks,records
                                CompilationoptimizeCodeGenerationSyncHookmodules
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationbeforeModuleHashSyncHook
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationafterModuleHashSyncHook
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationbeforeCodeGenerationSyncHook
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationafterCodeGenerationSyncHook
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationbeforeRuntimeRequirementsSyncHook
                                CompilationadditionalModuleRuntimeRequirementsSyncHookmodule,runtimeRequirements,context
                                CompilationadditionalModuleRuntimeRequirementsSyncHookmodule,runtimeRequirements,context
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationadditionalChunkRuntimeRequirementsSyncHookchunk,runtimeRequirements,context
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationadditionalTreeRuntimeRequirementsSyncHookchunk,runtimeRequirements,context
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationafterRuntimeRequirementsSyncHook
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationbeforeHashSyncHook
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationchunkHashSyncHookchunk,chunkHash,ChunkHashContext
                                CompilationcontentHashSyncHookchunk
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationfullHashSyncHookhash
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationafterHashSyncHook
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationrecordHashSyncHookrecords
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationbeforeModuleAssetsSyncHook
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationshouldGenerateChunkAssetsSyncBailHook
                                CompilationbeforeChunkAssetsSyncHook
                                CompilationrenderManifestSyncWaterfallHookresult,options
                                CompilationassetPathSyncWaterfallHookpath,options,assetInfo
                                CompilationchunkAssetSyncHookchunk,filename
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationadditionalChunkAssetsObjectundefined
                                CompilationadditionalAssetsObjectundefined
                                CompilationoptimizeAssetsAsyncSeriesHookassets
                                CompilationprocessAssetsAsyncSeriesHookassets
                                CompilationoptimizeChunkAssetsObjectundefined
                                CompilationafterOptimizeChunkAssetsObjectundefined
                                CompilationafterOptimizeAssetsSyncHookassets
                                CompilationafterProcessAssetsSyncHookassets
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationrecordSyncHookcompilation,records
                                CompilationneedAdditionalSealSyncBailHook
                                CompilationafterSealAsyncSeriesHook
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilerafterCompileAsyncSeriesHookcompilation
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilershouldEmitSyncBailHookcompilation
                                CompileremitAsyncSeriesHookcompilation
                                CompilationassetPathSyncWaterfallHookpath,options,assetInfo
                                CompilerassetEmittedAsyncSeriesHookfile,info
                                CompilerafterEmitAsyncSeriesHookcompilation
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationneedAdditionalPassSyncBailHook
                                CompileremitRecordsAsyncSeriesHook
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilerdoneAsyncSeriesHookstats
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilationlogSyncBailHookorigin,logEntry
                                CompilershutdownAsyncSeriesHook
                                CompilationstatsNormalizeSyncHookoptions,context
                                CompilationstatsFactorySyncHookstatsFactory,options
                                CompilationstatsPrinterSyncHookstatsPrinter,options
                                CompilationprocessErrorsSyncWaterfallHookerrors
                                CompilationprocessWarningsSyncWaterfallHookwarnings
                                CompilerafterDoneSyncHookstats
                                CompilerinfrastructureLogSyncBailHookorigin,type,args

                                工作流

                                初始化阶段
                                事件名解释代码位置
                                读取命令行参数从命令行中读取用户输入的参数require(“./convert-argv”)(argv)
                                实例化 Compiler1.用上一步得到的参数初始化 Compiler 实例 2.Compiler 负责文件监听和启动编译 3.Compiler 实例中包含了完整的 Webpack 配置,全局只有一个 Compiler 实例。compiler = webpack(options);
                                加载插件1.依次调用插件的 apply 方法,让插件可以监听后续的所有事件节点。 同时给插件传入 compiler 实例的引用,以方便插件通过 compiler 调用 Webpack 提供的 API。plugin.apply(compiler)
                                处理入口读取配置的 Entrys,为每个 Entry 实例化一个对应的 EntryPlugin,为后面该 Entry 的递归解析工作做准备new EntryOptionPlugin().apply(compiler) new SingleEntryPlugin(context, item, name) compiler.hooks.make.tapAsync
                                编译阶段
                                事件名解释代码位置
                                run启动一次新的编译this.hooks.run.callAsync
                                compile该事件是为了告诉插件一次新的编译将要启动,同时会给插件传入compiler 对象。compile(callback)
                                compilation当 Webpack 以开发模式运行时,每当检测到文件变化,一次新的 Compilation 将被创建。 一个 Compilation 对象包含了当前的模块资源、编译生成资源、变化的文件等。 Compilation 对象也提供了很多事件回调供插件做扩展。newCompilation(params)
                                make一个新的 Compilation 创建完毕主开始编译this.hooks.make.callAsync
                                addEntry即将从 Entry 开始读取文件compilation.addEntry this._addModuleChain
                                moduleFactory创建模块工厂const moduleFactory = this.dependencyFactories.get(Dep)
                                create创建模块moduleFactory.create
                                factory开始创建模块factory(result, (err, module) resolver(result this.hooks.resolver.tap(“NormalModuleFactory”
                                resolveRequestArray解析loader路径resolveRequestArray
                                resolve解析资源文件路径resolve
                                userRequest得到包括loader在内的资源文件的绝对路径用!拼起来的字符串userRequest
                                ruleSet.exec它可以根据模块路径名,匹配出模块所需的loaderthis.ruleSet.exec
                                _run它可以根据模块路径名,匹配出模块所需的loader_run
                                loaders得到所有的loader数组[results0].concat(loaders, results[1], results[2])
                                getParser获取AST解析器this.getParser(type, settings.parser)
                                buildModule开始编译模块this.buildModule(module buildModule(module, optional, origin, dependencies, thisCallback)
                                build开始真正编译入口模块build(options
                                doBuild开始真正编译入口模块doBuild
                                执行loader使用loader进行转换runLoaders runLoaders
                                iteratePitchingLoaders开始递归执行pitch loaderiteratePitchingLoaders
                                loadLoader加载loaderloadLoader
                                runSyncOrAsync执行pitchLoaderrunSyncOrAsync
                                processResource开始处理资源processResource options.readResource iterateNormalLoaders iterateNormalLoaders
                                createSource创建源代码对象this.createSource
                                parse使用parser转换抽象语法树this.parser.parse
                                parse解析抽象语法树parse(source, initialState)
                                acorn.parse解析语法树acorn.parse(code, parserOptions)
                                ImportDependency遍历并添加添加依赖parser.state.module.addDependency(clearDep)
                                succeedModule生成语法树后就表示一个模块编译完成this.hooks.succeedModule.call(module)
                                processModuleDependencies递归编译依赖的模块this.processModuleDependencies(module processModuleDependencies(module, callback) this.addModuleDependencies buildModule
                                make后结束makethis.hooks.make.callAsync(compilation, err => {}
                                finish编译完成compilation.finish();
                                结束阶段
                                事件名解释代码位置
                                seal封装compilation.seal seal(callback)
                                addChunk生成资源addChunk(name)
                                createChunkAssets创建资源this.createChunkAssets()
                                getRenderManifest获得要渲染的描述文件getRenderManifest(options)
                                render渲染源码source = fileManifest.render();
                                afterCompile编译结束this.hooks.afterCompile
                                shouldEmit所有需要输出的文件已经生成好,询问插件哪些文件需要输出,哪些不需要。this.hooks.shouldEmit
                                emit确定好要输出哪些文件后,执行文件输出,可以在这里获取和修改输出内容。this.emitAssets(compilation this.hooks.emit.callAsync const emitFiles = err this.outputFileSystem.writeFile
                                this.emitRecords写入记录this.emitRecords
                                done全部完成this.hooks.done.callAsync
VPS购买请点击我

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

目录[+]