You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
225 lines
6.7 KiB
225 lines
6.7 KiB
/* |
|
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;
|
|
|