UNPKG

6.78 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const util = require("util");
9const { RawSource, ReplaceSource } = require("webpack-sources");
10const Generator = require("../Generator");
11const InitFragment = require("../InitFragment");
12const HarmonyCompatibilityDependency = require("../dependencies/HarmonyCompatibilityDependency");
13
14/** @typedef {import("webpack-sources").Source} Source */
15/** @typedef {import("../DependenciesBlock")} DependenciesBlock */
16/** @typedef {import("../Dependency")} Dependency */
17/** @typedef {import("../DependencyTemplates")} DependencyTemplates */
18/** @typedef {import("../Generator").GenerateContext} GenerateContext */
19/** @typedef {import("../Module")} Module */
20/** @typedef {import("../Module").ConcatenationBailoutReasonContext} ConcatenationBailoutReasonContext */
21/** @typedef {import("../NormalModule")} NormalModule */
22/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
23
24// TODO: clean up this file
25// replace with newer constructs
26
27const deprecatedGetInitFragments = util.deprecate(
28 (template, dependency, templateContext) =>
29 template.getInitFragments(dependency, templateContext),
30 "DependencyTemplate.getInitFragment is deprecated (use apply(dep, source, { initFragments }) instead)",
31 "DEP_WEBPACK_JAVASCRIPT_GENERATOR_GET_INIT_FRAGMENTS"
32);
33
34const TYPES = new Set(["javascript"]);
35
36class JavascriptGenerator extends Generator {
37 /**
38 * @param {NormalModule} module fresh module
39 * @returns {Set<string>} available types (do not mutate)
40 */
41 getTypes(module) {
42 return TYPES;
43 }
44
45 /**
46 * @param {NormalModule} module the module
47 * @param {string=} type source type
48 * @returns {number} estimate size of the module
49 */
50 getSize(module, type) {
51 const originalSource = module.originalSource();
52 if (!originalSource) {
53 return 39;
54 }
55 return originalSource.size();
56 }
57
58 /**
59 * @param {NormalModule} module module for which the bailout reason should be determined
60 * @param {ConcatenationBailoutReasonContext} context context
61 * @returns {string | undefined} reason why this module can't be concatenated, undefined when it can be concatenated
62 */
63 getConcatenationBailoutReason(module, context) {
64 // Only harmony modules are valid for optimization
65 if (
66 !module.buildMeta ||
67 module.buildMeta.exportsType !== "namespace" ||
68 module.presentationalDependencies === undefined ||
69 !module.presentationalDependencies.some(
70 d => d instanceof HarmonyCompatibilityDependency
71 )
72 ) {
73 return "Module is not an ECMAScript module";
74 }
75
76 // Some expressions are not compatible with module concatenation
77 // because they may produce unexpected results. The plugin bails out
78 // if some were detected upfront.
79 if (module.buildInfo && module.buildInfo.moduleConcatenationBailout) {
80 return `Module uses ${module.buildInfo.moduleConcatenationBailout}`;
81 }
82 }
83
84 /**
85 * @param {NormalModule} module module for which the code should be generated
86 * @param {GenerateContext} generateContext context for generate
87 * @returns {Source} generated code
88 */
89 generate(module, generateContext) {
90 const originalSource = module.originalSource();
91 if (!originalSource) {
92 return new RawSource("throw new Error('No source available');");
93 }
94
95 const source = new ReplaceSource(originalSource);
96 const initFragments = [];
97
98 this.sourceModule(module, initFragments, source, generateContext);
99
100 return InitFragment.addToSource(source, initFragments, generateContext);
101 }
102
103 /**
104 * @param {Module} module the module to generate
105 * @param {InitFragment[]} initFragments mutable list of init fragments
106 * @param {ReplaceSource} source the current replace source which can be modified
107 * @param {GenerateContext} generateContext the generateContext
108 * @returns {void}
109 */
110 sourceModule(module, initFragments, source, generateContext) {
111 for (const dependency of module.dependencies) {
112 this.sourceDependency(
113 module,
114 dependency,
115 initFragments,
116 source,
117 generateContext
118 );
119 }
120
121 if (module.presentationalDependencies !== undefined) {
122 for (const dependency of module.presentationalDependencies) {
123 this.sourceDependency(
124 module,
125 dependency,
126 initFragments,
127 source,
128 generateContext
129 );
130 }
131 }
132
133 for (const childBlock of module.blocks) {
134 this.sourceBlock(
135 module,
136 childBlock,
137 initFragments,
138 source,
139 generateContext
140 );
141 }
142 }
143
144 /**
145 * @param {Module} module the module to generate
146 * @param {DependenciesBlock} block the dependencies block which will be processed
147 * @param {InitFragment[]} initFragments mutable list of init fragments
148 * @param {ReplaceSource} source the current replace source which can be modified
149 * @param {GenerateContext} generateContext the generateContext
150 * @returns {void}
151 */
152 sourceBlock(module, block, initFragments, source, generateContext) {
153 for (const dependency of block.dependencies) {
154 this.sourceDependency(
155 module,
156 dependency,
157 initFragments,
158 source,
159 generateContext
160 );
161 }
162
163 for (const childBlock of block.blocks) {
164 this.sourceBlock(
165 module,
166 childBlock,
167 initFragments,
168 source,
169 generateContext
170 );
171 }
172 }
173
174 /**
175 * @param {Module} module the current module
176 * @param {Dependency} dependency the dependency to generate
177 * @param {InitFragment[]} initFragments mutable list of init fragments
178 * @param {ReplaceSource} source the current replace source which can be modified
179 * @param {GenerateContext} generateContext the render context
180 * @returns {void}
181 */
182 sourceDependency(module, dependency, initFragments, source, generateContext) {
183 const constructor = /** @type {new (...args: any[]) => Dependency} */ (
184 dependency.constructor
185 );
186 const template = generateContext.dependencyTemplates.get(constructor);
187 if (!template) {
188 throw new Error(
189 "No template for dependency: " + dependency.constructor.name
190 );
191 }
192
193 const templateContext = {
194 runtimeTemplate: generateContext.runtimeTemplate,
195 dependencyTemplates: generateContext.dependencyTemplates,
196 moduleGraph: generateContext.moduleGraph,
197 chunkGraph: generateContext.chunkGraph,
198 module,
199 runtime: generateContext.runtime,
200 runtimeRequirements: generateContext.runtimeRequirements,
201 concatenationScope: generateContext.concatenationScope,
202 initFragments
203 };
204
205 template.apply(dependency, source, templateContext);
206
207 // TODO remove in webpack 6
208 if ("getInitFragments" in template) {
209 const fragments = deprecatedGetInitFragments(
210 template,
211 dependency,
212 templateContext
213 );
214
215 if (fragments) {
216 for (const fragment of fragments) {
217 initFragments.push(fragment);
218 }
219 }
220 }
221 }
222}
223
224module.exports = JavascriptGenerator;