webpack4流程分析6

1.Compilation

// 经过之前的步骤我们得到了创建出来的modules 执行回调会到compilation.seal封装代码
function seal() {
  this.hooks.seal.call();
  // 触发各种hook 为我们构建提供很多的钩子
  this.hooks.beforeChunks.call();
  // _preparedEntrypoints 在addEntry的时候添加的 为每个入口生成一个chunk
  for (const preparedEntrypoint of this._preparedEntrypoints) {
    const module = preparedEntrypoint.module; // 入口模块
    const name = preparedEntrypoint.name; // main
    //  new Chunk(name)
    const chunk = this.addChunk(name); // 新建chunk将module添加到chunk中
    // extend ChunkGroup 主要用来优化 chunk graph
    const entrypoint = new Entrypoint(name); // 生成入口点
    entrypoint.setRuntimeChunk(chunk); // 运行时chunk
    entrypoint.addOrigin(null, name, preparedEntrypoint.request); // 增加来源
    this.namedChunkGroups.set(name, entrypoint); // key为chunk的名称 值为chunkGroup
    this.entrypoints.set(name, entrypoint); // key为chunk的名称 值为chunkGroup
    this.chunkGroups.push(entrypoint); // 添加一个新的chunkGroup

    // 建立chunkGroup和chunk的关系 	chunk.addGroup(chunkGroup);
    // this._groups.add(chunkGroup)
    GraphHelpers.connectChunkGroupAndChunk(entrypoint, chunk);
    // 建立chunk和module的关系 	chunk.addModule(module);
    // this._modules.add(module);
    GraphHelpers.connectChunkAndModule(chunk, module);
    chunk.entryModule = module; // 代码块的入口模块
    chunk.name = name; // 代码块的名称
    // 依赖的深度??
    // this.assignDepth(module);
  }
  // [{Entrypoint: chunks: [ chunk: [{_modules, _groups}] ]}]
  // 构建chunkGraph 用来生成优化chunk依赖图
  buildChunkGraph(this, this.chunkGroups.slice());
}
复制代码

2. buildChunkGraph

// seal的流程很多 先分析 buildChunkGraph 主要分为三步
const buildChunkGraph = (compilation, inputChunkGroups) => {
  // 1. 建立chunkGroup chunk module之间的关系 使用 blockInfoMap 保存信息
  visitModules();
  // 2. 建立不同chunkGroup之间的父子关系 优化chunkGroup
  connectChunkGroups();
  // 3. 清理无用的chunk 清理相关的联系
  cleanupUnconnectedGroups();
};
复制代码

2.1 demo

// 为了方便看里面的逻辑 建立一个demo
// index.js
import common from "./common.js";
import("./async.js").then((result) => console.log(result));
// async.js
import title from "./title.js";
import("./common.js").then((result) => console.log(result));
export const lazy = "lazy";
// common.js
import title from "./title.js";
// title.js
export const title = "title";
复制代码

demo.png

2.2 visitModules

// 1. 建立关联
const visitModules = (
  compilation,
  inputChunkGroups,
  chunkGroupInfoMap,
  blockConnections,
  blocksWithNestedBlocks,
  allCreatedChunkGroups
) => {
  // 1.使用blockInfo用来存储模块关系 同步存入modules 异步blocks module graph

  // 经过处理 blockInfoMap 中共有6条记录 特别注意ImportDependenciesBlock_async的两个
  // const obj = {
  //   NormalModule_index: { modules: [common], blocks: [async] },
  //   ImportDependenciesBlock_async: { modules: [async], blocks: [] },
  //   NormalModule_common: { modules: [title], blocks: [] },
  //   NormalModule_async: { blocks: [common], modules: [title] },
  //   ImportDependenciesBlock_common: { modules: [common] },
  //   NormalModule_title: { modules: [] },
  // };

  const blockInfoMap = extraceBlockInfoMap(compilation);

  // 2.处理模块之见的关系 chunk graph
  let nextFreeModuleIndex = 0; // 下一个模块的空闲索引 每个模块是有两个index的默认是0
  let nextFreeModuleIndex2 = 0; // 通过下表去添加值
  const ADD_AND_ENTER_MODULE = 0; // 增加进入模块
  const ENTER_MODULE = 1; // 进入模块
  const PROCESS_BLOCK = 2; // 处理代码块
  const LEAVE_MODULE = 3; // 离开模块

  const reduceChunkGroupToQueueItem = (queue, chunkGroup) => {
    for (const chunk of chunkGroup.chunks) {
      queue.push({
        action: ENTER_MODULE,
        block: module,
        module: chunk.entryModule,
        chunk,
        chunkGroup,
      });
    }
    // 设置 chunkGroupInfoMap 映射 chunkGroup 和相关的信息对象
    chunkGroupInfoMap.set(chunkGroup, { chunkGroup, children: undefined });
    return queue;
  };
  // 将 entryPoint(chunkGroup) 变成一个queue {block, chunk, chunkGroup, module}
  let queue = inputChunkGroups
    .reduce(reduceChunkGroupToQueueItem, [])
    .reverse();
  const iteratorBlock = (b) => {
    // 1. 为block创建一个chunk import动态引入的会单独生成一个chunk(这个时候chunk中还没有依赖的module)
    // const chunkGroup = new ChunkGroup(groupOptions);
    // if (module) chunkGroup.addOrigin(module, loc, request); this.origins.push({})
    // const chunk = this.addChunk(name);
    // this.chunkGroups.push(chunkGroup);
    c = compilation.addChunkInGroup(b.chunkName, module);
    blockChunkGroups.set(b, c); // c是一个chunkGroup
    allCreatedChunkGroups.add(c); // 已经创建的chunksGroup
    blockConnections.set(b, []); // chunk Group的依赖
    // 2. 建立 module 所属的 chunkGroup 和 block 和 block 属于的chunkGroup的依赖关系
    // 主要用于优化 chunk graph
    blockConnections.get(b).push({
      originChunkGroupInfo: chunkGroupInfo, // chunkGroupInfoMap对应的信息
      chunkGroup: c,
    });
    // 3. 创建/跟新 chunk Group 的信息
    queueConnect.set(chunkGroup, connectList);
    connectList.add(c);
    // 4. 代码块 用作外层的遍历
    queueDelayed.push({
      action: PROCESS_BLOCK,
      block: b,
      module: module,
      chunk: c.chunks[0],
      chunkGroup: c,
    });
  };

  /**
   * 第一次外层while是入口 entry: {block, chunk, module, chunkGroup}
   * 第一次内层循环
   *  进入ENTER_MODULE 处理 完成后(没有break)进入 PROCESS_BLOCK
   *  PROCESS_BLOCK中会处理 modules 和 blocks
   *  index中的
   *      modules 是 common queue.push()
   *      blocks 是 async iteratorBlock是 新建chunk queueDelayed.push() 外层循环
   *
   * 第二次内层循环
   *  处理 ./common.js 调用 module.addChunk(chunk);
   *  在处理 common 的 modules(./title.js) 和 blocks(无)
   *
   * 第三次内层循环
   *  处理 title.js 没有 modules 和 blocks
   *
   *  处理queueConnect 在处理blocks的时候会处理
   *
   * 在处理 queueDelayed 开始外层的循环
   * // 这里使用了reverse的
   * queue = queueDelayed.reverse()
   *
   * 开始第二次外层循环 
   * 开始一次内循环
   *  queueDelayed的参数 {
   *    block: b, // index中blocks的block async.js
			  module: module, // index的module index.js
   *  }
      从bockInfoMap中找到 async 对应的 blockInfo
      block为  './async.js'  modules为空
   *
   * 。。。 通过while有一直处理下去 建立 graph图
   * 
   * 我们得到三个 chunkGroup entry async common
   */
  // 外层循环 会对queueDelayed的数据集进行处理 第一次的queue是entry开始
  while (queue.length) {
    // 每一轮的内层都对应同一个chunkGroup 对chunkGroup中所有的module进行处理
    while (queue.length) {
      const queueItem = queue.pop();
      module = queueItem.module;
      block = queueItem.block;
      chunk = queueItem.chunk;
      chunkGroup = queueItem.chunkGroup;
      chunkGroupInfo = chunkGroupInfoMap.get(chunkGroup);
      // 判断不同的同作
      switch (queueItem.action) {
        case ADD_AND_ENTER_MODULE: {
          if (chunk.addModule(module)) {
            module.addChunk(chunk);
          }
          break;
        }
        // 入口出的就是进入模块
        case ENTER_MODULE: {
          chunkGroup.setModuleIndex(
            module,
            chunkGroupCounters.get(chunkGroup).index++
          );
          // 添加一个离开的动作
          queue.push({ action: LEAVE_MODULE });
        }
        // 上面没有break 执行完ENTER_MODULE就会执行PROCESS_BLOCK处理代码快
        case PROCESS_BLOCK: {
          // 获取这个module的同步依赖modules和异步依赖blocks
          // 入口出的block就是chunk.entryModule
          const blockInfo = blockInfoMap.get(block);
          // 同步的依赖
          for (const refModule of blockInfo.modules) {
            if (chunk.containsModule(refModule)) {
              continue; // 有就跳过 否则添加 继续内层的遍历
            } else {
              // 将依赖的module添加到这个chunkGroup中了
              queueBuffer.push({
                action: ADD_AND_ENTER_MODULE,
                block: refModule,
                module: refModule,
                chunk,
                chunkGroup,
              });
            }
          }
          // 处理blocks
          for (const block of blockInfo.blocks) iteratorBlock(block);
          break;
        }
        case LEAVE_MODULE: {
          // 将这个module添加都了chunkGroup中
          chunkGroup.setModuleIndex(module);
          break;
        }
      }
    }
    // block的处理会set值
    while (queueConnect.size > 0) {
      for (const [chunkGroup, targets] of queueConnect) {
        const info = chunkGroupInfoMap.get(chunkGroup);
        // 1. 添加i个新的模块数据集 添加chunkGroup中chunk的模块
        const resultingAvailableModules = new Set(minAvailableModules);
        resultingAvailableModules.add(m);
        info.children = targets;
        // 2. 更新chunkGroup的信息
        chunkGroupInfoMap.set(target, chunkGroupInfo);
        if (outdatedChunkGroupInfo.size > 0) {
          // 合并模块
          for (const info of outdatedChunkGroupInfo) {
          }
        }
      }
    }

    // 内层遍历完成表示一个chunkGroup完了
    // 处理queueDelayed 就是 用来处理block 异步的是在说有的同步处理了再处理的
    if (queue.length === 0) {
      const tempQueue = queue;
      queue = queueDelayed.reverse();
      queueDelayed = tempQueue;
    }
  }
};
复制代码

2.3 extraceBlockInfoMap

// 经过之前的流程 我们可以得到4个模块

// 1. 处理index.js对应的模块 因为是pop会先处理block push的
// {NormalModule => Object}   // 1.index.js
// {ImportDependenciesBlock => Object}  // 2.async
// 2.处理common模块
// {NormalModule => Object} // 3.common

// 3.处理async模块
// {NormalModule => Object} // 4.async模块 里面 import 了 common
// {ImportDependenciesBlock => Object} // 5.async 模块中的 common
// 4.处理title的module
// {NormalModule => Object} // 6.title模块
const extraceBlockInfoMap = () => {
  const blockInfoMap = new Map();
  const iteratorDependency = (d) => {
    // module
    blockInfoModules.add(refModule);
  };
  const iteratorBlockPrepare = (b) => {
    blockInfoBlocks.push(b);
    // index和async中有block的依赖会再次遍历
    blockQueue.push(b); // 将block加入到blockQueue中 下一次遍历
  };

  // 遍历执行所有的模块 开始我们是有四个模块的
  // {"~/src/index.js" => NormalModule} 里面有 import('./async')
  // {"~/src/common.js" => NormalModule}
  // {"~/src/async.js" => NormalModule} 里面有 import('./common')
  // {"~/src/title.js" => NormalModule}
  for (const module of compilation.modules) {
    blockQueue = [module]; // blockQueue
    currentModule = module; // 当前模块
    // block的需要加入到队列中再次处理
    while (blockQueue.length > 0) {
      block = blockQueue.pop(); // 这里用的是pop 所有会先处理block加进来的
      // 分别处理 variables dependencies blocks
      if (block.variables) {
        // 变量
        iteratorDependency();
      }
      if (block.dependencies) {
        // 依赖
        iteratorDependency();
      }
      if (block.blocks) {
        // import的动态模块依赖
        iteratorBlockPrepare();
      }
      const blockInfo = {
        modules: blockInfoModules,
        blocks: blockInfoBlocks,
      };
      // compilation.modules module
      blockInfoMap.set(block, blockInfo);
    }
  }
  return blockInfoMap;
};
复制代码

2.4 connectChunkGroups

// 经过上面的处理 我们得到三个chunkGroup 连接chunkGroup 建立父子关系
const connectChunkGroups = (
  blocksWithNestedBlocks,
  blockConnections,
  chunkGroupInfoMap
) => {
  // 检查代码块中是否已经有了所有的模块
  const areModulesAvailable = () => {};
  // 遍历所有的connections chunk group的依赖
  // 在处理blocks的时候 async和common的时候 会被加到里面 blockConnections.set()
  // [ImportDependenciesBlock => Array(1), ImportDependenciesBlock => Array(1)]
  const map = {
    "./sync.js": {
      // const chunkGroup = new ChunkGroup(groupOptions);
      chunkGroup: compilation.addChunkInGroup(b.chunkName, module),
    },
  };
  // block是blocks中的block
  // blockConnections.set('./async', [{originChunkGroupInfo, chunkGroup}])
  for (const [block, connections] of blockConnections) {
    // 1. 检查连接是否有必要
    // 2. Foreach edge
    for (let i = 0; i < connections.length; i++) {
      // chunkGroup是new 出来的c  originChunkGroupInfo是map对象中值
      const { chunkGroup, originChunkGroupInfo } = connections[i];
      // 之前是通过 chunkGroup.setModuleIndex(module); 往里面添加了module
      // 3. Connect block with chunk 把block添加到chunkGroup中
      GraphHelpers.connectDependenciesBlockAndChunkGroup(block, chunkGroup);
      //  4. Connect chunk with parent建立父子关系  blockInfoMap中的属性
      GraphHelpers.connectChunkGroupParentAndChild(
        originChunkGroupInfo.chunkGroup,
        chunkGroup
      );
    }
  }
};

const connectChunkGroupParentAndChild = (parent, child) => {
  // chunkGroup
  if (parent.addChild(child)) {
    // this._parents.add(parentChunk);
    child.addParent(parent);
  }
};

// async.js: {chunkGroup: chunkGroup}
const connectDependenciesBlockAndChunkGroup = (depBlock, chunkGroup) => {
  if (chunkGroup.addBlock(depBlock)) {
    depBlock.chunkGroup = chunkGroup;
  }
};
复制代码

2.5 cleanupUnconnectedGroups

const cleanupUnconnectedGroups = (compilation, allCreatedChunkGroups) => {
  // async和common建立的chunkGroup
  for (const chunkGroup of allCreatedChunkGroups) {
    if (chunkGroup.getNumberOfParents() === 0) {
      // 如果有父亲 就将chunkGroup中所有的chunk删除
      for (const chunk of chunkGroup.chunks) {
        const idx = compilation.chunks.indexOf(chunk);
        if (idx >= 0) compilation.chunks.splice(idx, 1);
        chunk.remove("unconnected");
      }
      chunkGroup.remove("unconnected");
    }
  }
};
复制代码

3. optimizeChunk

// 生成chunk之后我们对进行一些优化的处理
this.hooks.optimize.call();
// module
this.hooks.optimizeModulesBasic.call(this.modules)
this.hooks.optimizeModules.call(this.modules)
this.hooks.optimizeModulesAdvanced.call(this.modules)
// chunks
this.hooks.optimizeChunksBasic.call(this.chunks, this.chunkGroups)
this.hooks.optimizeChunks.call(this.chunks, this.chunkGroups)
this.hooks.optimizeChunksAdvanced.call(this.chunks, this.chunkGroups)
this.hooks.optimizeTree.callAsync(this.chunks, this.modules, err => {
  this.applyModuleIds(); // 设置模块id
  this.applyChunkIds(); // 设置 chunk.id
  this.createHash(); // hash
  // 生成资源
  this.createModuleAssets();
  // 生成chunk资源
  this.hooks.beforeChunkAssets.call();
	this.createChunkAssets();
})
复制代码

4. SplitChunksPlugin

// 这个特性非常重要 单独说明下 当我们触发optimizeChunksAdvanced的时候
// 面试被问过 splitChunks的原理是什么 不知道
// 也是在webpackOptionsApply中处理的
if (options.optimization.splitChunks) {
  // 配置的splitChunks
  const SplitChunksPlugin = require("./optimize/SplitChunksPlugin");
  new SplitChunksPlugin(options.optimization.splitChunks).apply(compiler);
}
// 配置的runtimeChunk
if (options.optimization.runtimeChunk) {
  const RuntimeChunkPlugin = require("./optimize/RuntimeChunkPlugin");
  new RuntimeChunkPlugin(options.optimization.runtimeChunk).apply(compiler);
}

class SplitChunksPlugin {
  constructor(options) {
    // 格式化
    this.options = SplitChunksPlugin.normalizeOptions(options);
  }
  apply(compiler) {
    compiler.hooks.thisCompilation.tap("SplitChunksPlugin", (compilation) => {
      // 监听这个钩子 在生成了chunkGroup之后 优化的时候触发的代码分割
      compilation.hooks.optimizeChunksAdvanced.tap(
        "SplitChunksPlugin",
        (chunks) => {}
      )
    })
  }
}
复制代码

4.1 config

// 以element-admin的配置为例子 加一些配置的说明
config.optimization.splitChunks({
   // initial async all function(return chunks) 要提取的模块
  chunks: 'all',
  // minSize: 10000, // 最小的体积 10k的才会分出来
  // maxSize: 0, // 代表能分则分 分不了就算了 保证尽量的小
  // minChunks: 1, //  最小的被引用次数
  // maxAsyncRequests: 5, // 按需加载的代码块最多允许的并行请求数 在webpack5里默认值变为6
  // maxInitialRequests: 3, // 入口代码块最多允许的并行请求数,在webpack5里默认值变为4
  // automaticNameDelimiter: "~", // 代码块命名分割符
  // name: true, // 每个缓存组打包得到的代码块的名称
  cacheGroups: {
    libs: {
      name: 'chunk-libs', // 打包的名字
      test: /[\\/]node_modules[\\/]/, // 正则
      priority: 10, // 优先级
      chunks: 'initial'
    },
    elementUI: {
      name: 'chunk-elementUI',
      priority: 20, 
      test: /[\\/]node_modules[\\/]_?element-ui(.*)/ 
    },
    // 之前一直打包不出来是因为没有设置 minSize
    commons: {
      name: 'chunk-commons',
      test: resolve('src/components'), 
      minSize: 0, // 最小提取字节数
      minChunks: 2, // 最小的被引用次数
      priority: 5,
      reuseExistingChunk: true // 重用模块
    }
  }
})
复制代码

4.2 demo

// 为了演示效果 我们安装element-ui和jquery

// index.js
import $ from "jquery";
import ElementUI from "element-ui";
import("./async.js").then((result) => console.log(result));
import("./async1.js").then((result) => console.log(result));
import("./async2.js").then((result) => console.log(result));
// async async1 async2 设置了minChunks表示至少被几个chunk引用
import title from "./title.js";
复制代码

得到打包结果

WX20210621-103945@2x.png

4.3

// splitChunk就是将每个模块按照规则分配到不同的缓存组中
// 每个缓存组对应最终分割出来的新代码块
// chunksInfoMap 
// addModuleToChunksInfoMap
// newChunk = compilation.addChunk(chunkName);
function  apply(compiler) {
  compiler.hooks.thisCompilation.tap("SplitChunksPlugin", (compilation) => {
    // 监听这个钩子 在生成了chunkGroup之后 优化的时候触发的代码分割
    compilation.hooks.optimizeChunksAdvanced.tap(
      "SplitChunksPlugin",
      (chunks) => {
        // 生成一个index 给每个选中的chunk一个index  create strings from chunks
        indexMap.set(chunk, index++);
        // key和chunkSet的关系
        const chunkSetsInGraph = new Map();
        // 遍历modules为每个module的chunk生成一个key
        // 经过上面的处理 我们得到四个chunk n个modules(element-ui和jquery中有很多个module)
        // {1: {}, 2: {}, 3: {}, 4: {}, '2, 3, 4': {set(3)}} title.js是在三个chunks中的
        for (const module of compilation.modules) {
          // chunksIterable return this._chunks
          const chunksKey = getKey(module.chunksIterable);
          if (!chunkSetsInGraph.has(chunksKey)) {
            chunkSetsInGraph.set(chunksKey, new Set(module.chunksIterable));
          }
        }

        // 按照count对这些chunk进行分组
        const chunkSetsByCount = new Map();
        // {1: [4], 3: [3]} 数量为1的是四个chunk 3个的是 set(3)
        for (const chunksSet of chunkSetsInGraph.values()) {
          // 每个module对应一个chunksSet 一个chunkSet中有多个module就是有多个count
          const count = chunksSet.size;
          let array = chunkSetsByCount.get(count);
          if (array === undefined) {
            array = [];
            chunkSetsByCount.set(count, array);
          }
          array.push(chunksSet);
        }

        // 创建一个可能组合的列表  Map<string, Set<Chunk>[]>
        const combinationsCache = new Map();
        // 根据key得到module中对应的chunks集合 set
        const chunksSet = chunkSetsInGraph.get(key);
        const getCombinations = (key) => {
          const chunksSet = chunkSetsInGraph.get(key);
          var array = [chunksSet];
          if (chunksSet.size > 1) {
            for (const [count, setArray] of chunkSetsByCount) {
              // "equal" is not needed because they would have been merge in the first step
              if (count < chunksSet.size) {
                for (const set of setArray) {
                  if (isSubset(chunksSet, set)) {
                    array.push(set);
                  }
                }
              }
            }
          }
          return array;
        };
        // 处理缓存
        // const selectedChunksCacheByChunksSet = new WeakMap();
        // // 通过将过滤器功能应用于列表来获取列表和键 出于性能原因,它被缓存
        // const getSelectedChunks = (chunks, chunkFilter) => {};
        // Map a list of chunks to a list of modules 代码分割的信息
        const chunksInfoMap = new Map();
        const addModuleToChunksInfoMap = (
          cacheGroup, // the current cache group 当前的cache组
          cacheGroupIndex, // the index of the cache group of ordering
          selectedChunks, // chunks selected for this module
          selectedChunksKey, // a key of selectedChunks
          module // the current module
        ) => {
          // minChunks属性
          if (selectedChunks.length < cacheGroup.minChunks) return;
          // name
          const name = cacheGroup.getName();
          // key
          const key =
            cacheGroup.key +
            (name ? ` name:${name}` : ` chunks:${selectedChunksKey}`);
          let info = chunksInfoMap.get(key);
          // 添加新的缓存组信息
          chunksInfoMap.set(
            key,
            (info = {
              modules: new SortableSet(undefined, sortByIdentifier),
              cacheGroup,
              cacheGroupIndex,
              name,
              size: 0,
              chunks: new Set(),
              reuseableChunks: new Set(),
              chunksKeys: new Set(),
            })
          );
          info.modules.add(module);
          info.size += module.size(); // 判断我们设置的miniSize
          info.chunksKeys.add(selectedChunksKey);
          for (const chunk of selectedChunks) {
            info.chunks.add(chunk); // 最后打包的是chunk
          }
        };
        // 遍历模块 分组
        for (const module of compilation.modules) {
          // 一个module可能符合多个条件 我们会根据 优先级来判断
          let cacheGroups = this.options.getCacheGroups(module, context);
          const chunksKey = getKey(module.chunksIterable);
          for (const cacheGroupSource of cacheGroups) {
            const minSize = cacheGroupSource.minSize;
            const cacheGroup = {
              // 一系列的属性 配置
              key: cacheGroupSource.key,
              // 默认优先级是0
              priority: cacheGroupSource.priority || 0,
              minSize,
              minChunks: cacheGroupSource.minChunks,
            };
          }
          // 根据webpack的配置 选出符合添加的chunk
          for (const chunkCombination of combs) {
            addModuleToChunksInfoMap();
          }
        }
        // 处理size < minSize
        for (const pair of chunksInfoMap) {
          chunksInfoMap.delete(pair[0]);
        }
        // maxSize
        const maxSizeQueueMap = new Map();
        while (chunksInfoMap.size > 0) {
          let bestEntryKey; // 最匹配的cacheGroup分组信息
          let bestEntry;
          for (const pair of chunksInfoMap) {
            bestEntry = pair[1];
            bestEntryKey = pair[0];
          }
          const item = bestEntry;
          chunksInfoMap.delete(bestEntryKey);
          let chunkName = item.name;
          // 新的chunk
          let newChunk;
          // 重用模块 如果没有name 看是否能复用
          if (item.cacheGroup.reuseExistingChunk) {
          }
          // 创建新的代码块
          newChunk = compilation.addChunk(chunkName);
          for (const chunk of usedChunks) {
            // Add graph connections for splitted chunk 建立关系
            chunk.split(newChunk);
          }
          if (chunkName) {
            const entrypoint = compilation.entrypoints.get(chunkName);
          }
          // 删除提取出来的模块
          for (const [key, info] of chunksInfoMap) {
          }
          // Make sure that maxSize is fulfilled
          for (const chunk of compilation.chunks.slice()) {
          }
        }
      }
    );
  });
}
复制代码

5. hash

// 各种hash值 content hash chunk hash full hash module hash
function createHash() {
  const hashFunction = outputOptions.hashFunction;
  const hash = createHash(hashFunction);
  // new MainTemplate(this.outputOptions);
  this.mainTemplate.updateHash(hash);
  this.chunkTemplate.updateHash(hash);
  for (const key of Object.keys(this.moduleTemplates).sort()) {
    this.moduleTemplates[key].updateHash(hash);
  }
  // module hash
  for (let i = 0; i < this.modules.length; i++) {
    const module = modules[i];
    const moduleHash = createHash(hashFunction);
    module.updateHash(moduleHash);
  }
  const chunks = this.chunks.slice();
  chunks.sort((a, b) => {});
  // chunk hash
  for (let i = 0; i < chunks.length; i++) {
    const chunk = chunks[i];
    const chunkHash = createHash(hashFunction);
    // hasRuntime
    this.hooks.contentHash.call(chunk);
  }
  this.fullHash = /** @type {string} */ (hash.digest(hashDigest));
  this.hash = this.fullHash.substr(0, hashDigestLength);
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享