You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			226 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			JavaScript
		
	
		
		
			
		
	
	
			226 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			JavaScript
		
	
| 
											9 months ago
										 | /* | ||
|  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | ||
|  | 	Author Tobias Koppers @sokra | ||
|  | */ | ||
|  | 
 | ||
|  | "use strict"; | ||
|  | 
 | ||
|  | const util = require("util"); | ||
|  | const { RawSource, ReplaceSource } = require("webpack-sources"); | ||
|  | const Generator = require("../Generator"); | ||
|  | const InitFragment = require("../InitFragment"); | ||
|  | const HarmonyCompatibilityDependency = require("../dependencies/HarmonyCompatibilityDependency"); | ||
|  | 
 | ||
|  | /** @typedef {import("webpack-sources").Source} Source */ | ||
|  | /** @typedef {import("../DependenciesBlock")} DependenciesBlock */ | ||
|  | /** @typedef {import("../Dependency")} Dependency */ | ||
|  | /** @typedef {import("../DependencyTemplates")} DependencyTemplates */ | ||
|  | /** @typedef {import("../Generator").GenerateContext} GenerateContext */ | ||
|  | /** @typedef {import("../Module")} Module */ | ||
|  | /** @typedef {import("../Module").ConcatenationBailoutReasonContext} ConcatenationBailoutReasonContext */ | ||
|  | /** @typedef {import("../NormalModule")} NormalModule */ | ||
|  | /** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */ | ||
|  | 
 | ||
|  | // TODO: clean up this file
 | ||
|  | // replace with newer constructs
 | ||
|  | 
 | ||
|  | const deprecatedGetInitFragments = util.deprecate( | ||
|  | 	(template, dependency, templateContext) => | ||
|  | 		template.getInitFragments(dependency, templateContext), | ||
|  | 	"DependencyTemplate.getInitFragment is deprecated (use apply(dep, source, { initFragments }) instead)", | ||
|  | 	"DEP_WEBPACK_JAVASCRIPT_GENERATOR_GET_INIT_FRAGMENTS" | ||
|  | ); | ||
|  | 
 | ||
|  | const TYPES = new Set(["javascript"]); | ||
|  | 
 | ||
|  | class JavascriptGenerator extends Generator { | ||
|  | 	/** | ||
|  | 	 * @param {NormalModule} module fresh module | ||
|  | 	 * @returns {Set<string>} available types (do not mutate) | ||
|  | 	 */ | ||
|  | 	getTypes(module) { | ||
|  | 		return TYPES; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param {NormalModule} module the module | ||
|  | 	 * @param {string=} type source type | ||
|  | 	 * @returns {number} estimate size of the module | ||
|  | 	 */ | ||
|  | 	getSize(module, type) { | ||
|  | 		const originalSource = module.originalSource(); | ||
|  | 		if (!originalSource) { | ||
|  | 			return 39; | ||
|  | 		} | ||
|  | 		return originalSource.size(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param {NormalModule} module module for which the bailout reason should be determined | ||
|  | 	 * @param {ConcatenationBailoutReasonContext} context context | ||
|  | 	 * @returns {string | undefined} reason why this module can't be concatenated, undefined when it can be concatenated | ||
|  | 	 */ | ||
|  | 	getConcatenationBailoutReason(module, context) { | ||
|  | 		// Only harmony modules are valid for optimization
 | ||
|  | 		if ( | ||
|  | 			!module.buildMeta || | ||
|  | 			module.buildMeta.exportsType !== "namespace" || | ||
|  | 			module.presentationalDependencies === undefined || | ||
|  | 			!module.presentationalDependencies.some( | ||
|  | 				d => d instanceof HarmonyCompatibilityDependency | ||
|  | 			) | ||
|  | 		) { | ||
|  | 			return "Module is not an ECMAScript module"; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// Some expressions are not compatible with module concatenation
 | ||
|  | 		// because they may produce unexpected results. The plugin bails out
 | ||
|  | 		// if some were detected upfront.
 | ||
|  | 		if (module.buildInfo && module.buildInfo.moduleConcatenationBailout) { | ||
|  | 			return `Module uses ${module.buildInfo.moduleConcatenationBailout}`; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param {NormalModule} module module for which the code should be generated | ||
|  | 	 * @param {GenerateContext} generateContext context for generate | ||
|  | 	 * @returns {Source} generated code | ||
|  | 	 */ | ||
|  | 	generate(module, generateContext) { | ||
|  | 		const originalSource = module.originalSource(); | ||
|  | 		if (!originalSource) { | ||
|  | 			return new RawSource("throw new Error('No source available');"); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		const source = new ReplaceSource(originalSource); | ||
|  | 		const initFragments = []; | ||
|  | 
 | ||
|  | 		this.sourceModule(module, initFragments, source, generateContext); | ||
|  | 
 | ||
|  | 		return InitFragment.addToSource(source, initFragments, generateContext); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param {Module} module the module to generate | ||
|  | 	 * @param {InitFragment[]} initFragments mutable list of init fragments | ||
|  | 	 * @param {ReplaceSource} source the current replace source which can be modified | ||
|  | 	 * @param {GenerateContext} generateContext the generateContext | ||
|  | 	 * @returns {void} | ||
|  | 	 */ | ||
|  | 	sourceModule(module, initFragments, source, generateContext) { | ||
|  | 		for (const dependency of module.dependencies) { | ||
|  | 			this.sourceDependency( | ||
|  | 				module, | ||
|  | 				dependency, | ||
|  | 				initFragments, | ||
|  | 				source, | ||
|  | 				generateContext | ||
|  | 			); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (module.presentationalDependencies !== undefined) { | ||
|  | 			for (const dependency of module.presentationalDependencies) { | ||
|  | 				this.sourceDependency( | ||
|  | 					module, | ||
|  | 					dependency, | ||
|  | 					initFragments, | ||
|  | 					source, | ||
|  | 					generateContext | ||
|  | 				); | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		for (const childBlock of module.blocks) { | ||
|  | 			this.sourceBlock( | ||
|  | 				module, | ||
|  | 				childBlock, | ||
|  | 				initFragments, | ||
|  | 				source, | ||
|  | 				generateContext | ||
|  | 			); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param {Module} module the module to generate | ||
|  | 	 * @param {DependenciesBlock} block the dependencies block which will be processed | ||
|  | 	 * @param {InitFragment[]} initFragments mutable list of init fragments | ||
|  | 	 * @param {ReplaceSource} source the current replace source which can be modified | ||
|  | 	 * @param {GenerateContext} generateContext the generateContext | ||
|  | 	 * @returns {void} | ||
|  | 	 */ | ||
|  | 	sourceBlock(module, block, initFragments, source, generateContext) { | ||
|  | 		for (const dependency of block.dependencies) { | ||
|  | 			this.sourceDependency( | ||
|  | 				module, | ||
|  | 				dependency, | ||
|  | 				initFragments, | ||
|  | 				source, | ||
|  | 				generateContext | ||
|  | 			); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		for (const childBlock of block.blocks) { | ||
|  | 			this.sourceBlock( | ||
|  | 				module, | ||
|  | 				childBlock, | ||
|  | 				initFragments, | ||
|  | 				source, | ||
|  | 				generateContext | ||
|  | 			); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param {Module} module the current module | ||
|  | 	 * @param {Dependency} dependency the dependency to generate | ||
|  | 	 * @param {InitFragment[]} initFragments mutable list of init fragments | ||
|  | 	 * @param {ReplaceSource} source the current replace source which can be modified | ||
|  | 	 * @param {GenerateContext} generateContext the render context | ||
|  | 	 * @returns {void} | ||
|  | 	 */ | ||
|  | 	sourceDependency(module, dependency, initFragments, source, generateContext) { | ||
|  | 		const constructor = /** @type {new (...args: any[]) => Dependency} */ ( | ||
|  | 			dependency.constructor | ||
|  | 		); | ||
|  | 		const template = generateContext.dependencyTemplates.get(constructor); | ||
|  | 		if (!template) { | ||
|  | 			throw new Error( | ||
|  | 				"No template for dependency: " + dependency.constructor.name | ||
|  | 			); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		const templateContext = { | ||
|  | 			runtimeTemplate: generateContext.runtimeTemplate, | ||
|  | 			dependencyTemplates: generateContext.dependencyTemplates, | ||
|  | 			moduleGraph: generateContext.moduleGraph, | ||
|  | 			chunkGraph: generateContext.chunkGraph, | ||
|  | 			module, | ||
|  | 			runtime: generateContext.runtime, | ||
|  | 			runtimeRequirements: generateContext.runtimeRequirements, | ||
|  | 			concatenationScope: generateContext.concatenationScope, | ||
|  | 			codeGenerationResults: generateContext.codeGenerationResults, | ||
|  | 			initFragments | ||
|  | 		}; | ||
|  | 
 | ||
|  | 		template.apply(dependency, source, templateContext); | ||
|  | 
 | ||
|  | 		// TODO remove in webpack 6
 | ||
|  | 		if ("getInitFragments" in template) { | ||
|  | 			const fragments = deprecatedGetInitFragments( | ||
|  | 				template, | ||
|  | 				dependency, | ||
|  | 				templateContext | ||
|  | 			); | ||
|  | 
 | ||
|  | 			if (fragments) { | ||
|  | 				for (const fragment of fragments) { | ||
|  | 					initFragments.push(fragment); | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | module.exports = JavascriptGenerator; |