webpack4流程分析7

1. createModuleAssets();

// 生成module资源 在生成hash之后会生成资源
this.hooks.beforeModuleAssets.call();
this.createModuleAssets();
// 遍历modules 获取module.buildInfo.assets
function createModuleAssets() {
	for (let i = 0; i < this.modules.length; i++) {
    const module = this.modules[i];
    if (module.buildInfo.assets) {
      const assetsInfo = module.buildInfo.assetsInfo;
      for (const assetName of Object.keys(module.buildInfo.assets)) {
        const fileName = this.getPath(assetName);
        // 触发emitAsset生成资源
        this.emitAsset(
          fileName,
          module.buildInfo.assets[assetName],
          assetsInfo ? assetsInfo.get(assetName) : undefined
        );
        this.hooks.moduleAsset.call(module, fileName);
      }
    }
  }
}
// 生成资源
function emitAsset() {
  this.assets[file] = source;
	this.assetsInfo.set(file, assetInfo);
}
复制代码

2. createChunkAssets

this.hooks.beforeChunkAssets.call();
this.createChunkAssets(); // chunk

const mainTemplate = new MainTemplate(this.outputOptions)
const chunkTemplate = new ChunkTemplate(this.outputOptions);
const moduleTemplates = {
  javascript: new ModuleTemplate(this.runtimeTemplate, "javascript"),
  webassembly: new ModuleTemplate(this.runtimeTemplate, "webassembly")
};

function createChunkAssets() {
  // 1. 获取template
  const template = chunk.hasRuntime() 
    ? this.mainTemplate : this.chunkTemplate;
  // 2. 执行getRenderManifest 触发renderManifest钩子
  // JavascriptModulesPlugin中注册的 result中push一个render方法
  const manifest = template.getRenderManifest({
    moduleTemplates: this.moduleTemplates,
  })
  for (const fileManifest of manifest) {
     // 3. 得到路径和相关info
    const pathAndInfo = this.getPathWithInfo
    // 4. 执行render方法
    source = fileManifest.render();
    // 映射资源 compilation.assets
    this.emitAsset(file, source, assetInfo);
  } 
}
复制代码

2.1 MainTemplate

class MainTemplate {
  constructor(outputOptions) {
    	this.hooks.render.tap("MainTemplate",() => {
        // webpack-sources
        const source = new ConcatSource();
	      source.add("/******/ (function(modules) { // webpackBootstrap\n");
        source.add(
          // 触发 JavascriptModulesPlugin 的钩子
					this.hooks.modules.call()
				);
        return source
      })
  }
  getRenderManifest(options) {
    this.hooks.renderManifest.call(result, options)
  }
  render() {
    // 1.生成runTime代码
    const buf = this.renderBootstrap()
    // 2.包裹 runtime 与 chunk 代码
    // render在构造器中tap的
    let source = this.hooks.render.call()
    source = this.hooks.renderWithEntry.call(source, chunk, hash);
    return new ConcatSource(source, ";");
  }
}
复制代码

2.2 ChunkTemplate

class ChunkTemplate {
  getRenderManifest(options) {
    this.hooks.renderManifest.call(result, options);
  }
}
复制代码

2.3 JavascriptModulesPlugin

class JavascriptModulesPlugin {
  apply(compiler) {

    // parse 和 generator
    normalModuleFactory.hooks.createParser
      .for("javascript/auto")
      .tap("JavascriptModulesPlugin", options => {
        return new Parser(options, "auto");
    });
    normalModuleFactory.hooks.createGenerator
      .for("javascript/auto")
      .tap("JavascriptModulesPlugin", () => {
        return new JavascriptGenerator();
    });
    

    compiler.hooks.compilation.tap(	"JavascriptModulesPlugin", 	(compilation, { normalModuleFactory }) => {
      // mainTemplate
      compilation.mainTemplate.hooks.renderManifest.tap("JavascriptModulesPlugin", (result, options) => {
        	result.push({
            render: () => 
              compilation.mainTemplate.render()
          })
      })
      // modules
      compilation.mainTemplate.hooks.modules.tap(	"JavascriptModulesPlugin", () => {
        return Template.renderChunkModules()
      })
      // chunkTemplate
      compilation.chunkTemplate.hooks.renderManifest.tap("JavascriptModulesPlugin", (result, options) => {
        result.push({
          render: () => 
            this.renderJavascript(
              compilation.chunkTemplate,
              chunk,
              moduleTemplates.javascript, // options.moduleTemplates
              dependencyTemplates
            )
        })
      })
      // 
    })
  }
  renderJavascript(chunkTemplate, chunk, moduleTemplate, dependencyTemplates) {
    const moduleSources = Template.renderChunkModules()
    const core = chunkTemplate.hooks.modules.call()
    // render JsonpChunkTemplatePlugin 添加jsonp代码 异步包裹代码
    let source = chunkTemplate.hooks.render.call()
    source = chunkTemplate.hooks.renderWithEntry.call(source, chunk);
    return new ConcatSource(source, ";");
  }
}
复制代码

2.4 Template

class Template {
  // chunkModule的render也是执行这里
  static renderChunkModules(chunk, filterFn, moduleTemplate) {
    const source = new ConcatSource();
		const modules = chunk.getModules().filter(filterFn);
    // 调用render方法
    const allModules = modules.map(module => {
      return {
        id: module.id,
        // moduleTemplate 传递过来的参数 生成每个module的代码
        source: moduleTemplate.render(module, dependencyTemplates, {
          chunk
        })
      };
    });
  }
}
复制代码

2.5 ModuleTemplate

// 执行moduleTemplate的render方法
class ModuleTemplate {
  render(module, dependencyTemplates, options) {
    // 执行module的source方法
    const moduleSource = module.source()
    // 对源码再次做一些处理
    const moduleSourcePostContent = this.hooks.content.call()
    const moduleSourcePostModule = this.hooks.module.call()
    // FunctionModulePlugin 对源码进行包裹
    const moduleSourcePostRender = this.hooks.render.call()
    // 添加注释代码
    return this.hooks.package.call()
  }
}
复制代码

2.6 NormalModule

class NormalModule {
  source(dependencyTemplates, runtimeTemplate, type = "javascript") {
    // 执行JavascriptGenerator的generate方法
    const source = this.generator.generate()
  }
}
复制代码

2.7 NormalModuleFactory

class NormalModuleFactory {
  constructor(context, resolverFactory, options) {
    this.hooks.factory.tap("NormalModuleFactory", () => (result, callback) => {
      // resolver返回的
      createdModule = new NormalModule(result);
    })
    this.hooks.resolver.tap("NormalModuleFactory", () => (data, callback) => {
      callback(null, {
        parser: this.getParser(type, settings.parser),
				generator: this.getGenerator(type, settings.generator),
      })
    })
  }
  getGenerator() {
    // JavascriptModulesPlugin
    const generator = this.hooks.createGenerator
			.for(type)
			.call(generatorOptions);
    this.hooks.generator.for(type).call(generator, generatorOptions);
  }
}

复制代码

2.8 JavascriptGenerator

class JavascriptGenerator {
  generate() {
    const source = new ReplaceSource(originalSource);
    this.sourceBlock()
  }
  sourceBlock() {
    for (const dependency of block.dependencies) {
      this.sourceDependency()
    }
    // block.variables
    for (const childBlock of block.blocks) {
      this.sourceBlock()
    }
  }
  sourceDependency() {
    // build module 的时候 执行 parse 添加的依赖
    const template = dependencyTemplates.get(dependency.constructor);
    // 根据不同的依赖对源码做不同的处理 webpack-sources 感觉就是对源码进行处理
    // 增加代码 修改代码 具体做了什么不分析 之后看打包生成的代码结构
    template.apply(dependency, source, runtimeTemplate, dependencyTemplates);
  }
}
复制代码

2.9 dependencyTemplates

// 经过ast的处理 增加了5个依赖 对应不同的模板 在 dependencies 目录下
HarmonyCompatibilityDependency 
HarmonyInitDependency  
ConstDependency  
HarmonyImportSideEffectDependency  
HarmonyImportSpecifierDependency 
复制代码

2.9.1 HarmonyCompatibilityDependency

// HarmonyImportSpecifierDependency
HarmonyExportSpecifierDependency.Template = class HarmonyExportSpecifierDependencyTemplate {
  apply(dep, source) {}
}
复制代码

2.9.2 HarmonyInitDependency

HarmonyInitDependency.Template = class HarmonyInitDependencyTemplate {
  apply() {
    item.template.harmonyInit()
  }
}
复制代码

2.9.3 ConstDependency

ConstDependency.Template = class ConstDependencyTemplate {
	apply(dep, source) {
		if (typeof dep.range === "number") {
			source.insert(dep.range, dep.expression);
			return;
		}
		source.replace(dep.range[0], dep.range[1] - 1, dep.expression);
	}
};
复制代码

2.9.4 HarmonyImportSideEffectDependency

HarmonyImportSideEffectDependency.Template = class HarmonyImportSideEffectDependencyTemplate extends HarmonyImportDependency.Template {}
复制代码

2.9.5 HarmonyImportDependency

HarmonyImportDependency.Template = class HarmonyImportDependencyTemplate {
	apply(dep, source, runtime) {
		// no-op
	}
}
复制代码

2.9.5 HarmonyImportSpecifierDependency

HarmonyImportSpecifierDependency.Template = class HarmonyImportSpecifierDependencyTemplate extends HarmonyImportDependency.Template {
	apply(dep, source, runtime) {
		super.apply(dep, source, runtime);
		const content = this.getContent(dep, runtime);
		source.replace(dep.range[0], dep.range[1] - 1, content);
	}
}
复制代码

2.10 WebpackOptionsApply

class WebpackOptionsApply {
  process(options, compiler) {
    switch (options.target) {
      JsonpTemplatePlugin = require("./web/JsonpTemplatePlugin");
      new JsonpTemplatePlugin().apply(compiler);
      new FunctionModulePlugin().apply(compiler);
    }
  }
}
复制代码

2.11 FunctionModulePlugin

class FunctionModulePlugin {
	apply(compiler) {
		compiler.hooks.compilation.tap("FunctionModulePlugin", compilation => {
			new FunctionModuleTemplatePlugin().apply(
				compilation.moduleTemplates.javascript
			);
		});
	}
}
复制代码

2.11.1 FunctionModuleTemplatePlugin

class FunctionModuleTemplatePlugin {
  apply(moduleTemplate) {
    moduleTemplate.hooks.render.tap("FunctionModuleTemplatePlugin", (moduleSource, module) => {
      	source.add()
    })
    moduleTemplate.hooks.package.tap()
  }
}
复制代码

2.12 JsonpTemplatePlugin

class JsonpTemplatePlugin {
	apply(compiler) {
		compiler.hooks.thisCompilation.tap("JsonpTemplatePlugin", compilation => {
			new JsonpMainTemplatePlugin().apply(compilation.mainTemplate);
			new JsonpChunkTemplatePlugin().apply(compilation.chunkTemplate);
		});
	}
}
复制代码

2.12.1 JsonpMainTemplatePlugin

2.12.2 JsonpChunkTemplatePlugin

class JsonpChunkTemplatePlugin {
  apply(chunkTemplate) {
    // 添加jsonp代码
    chunkTemplate.hooks.render.tap(
			"JsonpChunkTemplatePlugin",
      (modules, chunk) => {}
    )
  }
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享