source: trip-planner-front/node_modules/webpack/lib/optimize/InnerGraphPlugin.js@ 6a3a178

Last change on this file since 6a3a178 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 11.8 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const PureExpressionDependency = require("../dependencies/PureExpressionDependency");
9const InnerGraph = require("./InnerGraph");
10
11/** @typedef {import("estree").ClassDeclaration} ClassDeclarationNode */
12/** @typedef {import("estree").ClassExpression} ClassExpressionNode */
13/** @typedef {import("estree").Node} Node */
14/** @typedef {import("estree").VariableDeclarator} VariableDeclaratorNode */
15/** @typedef {import("../Compiler")} Compiler */
16/** @typedef {import("../Dependency")} Dependency */
17/** @typedef {import("../dependencies/HarmonyImportSpecifierDependency")} HarmonyImportSpecifierDependency */
18/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
19/** @typedef {import("./InnerGraph").InnerGraph} InnerGraph */
20/** @typedef {import("./InnerGraph").TopLevelSymbol} TopLevelSymbol */
21
22const { topLevelSymbolTag } = InnerGraph;
23
24class InnerGraphPlugin {
25 /**
26 * Apply the plugin
27 * @param {Compiler} compiler the compiler instance
28 * @returns {void}
29 */
30 apply(compiler) {
31 compiler.hooks.compilation.tap(
32 "InnerGraphPlugin",
33 (compilation, { normalModuleFactory }) => {
34 const logger = compilation.getLogger("webpack.InnerGraphPlugin");
35
36 compilation.dependencyTemplates.set(
37 PureExpressionDependency,
38 new PureExpressionDependency.Template()
39 );
40
41 /**
42 * @param {JavascriptParser} parser the parser
43 * @param {Object} parserOptions options
44 * @returns {void}
45 */
46 const handler = (parser, parserOptions) => {
47 const onUsageSuper = sup => {
48 InnerGraph.onUsage(parser.state, usedByExports => {
49 switch (usedByExports) {
50 case undefined:
51 case true:
52 return;
53 default: {
54 const dep = new PureExpressionDependency(sup.range);
55 dep.loc = sup.loc;
56 dep.usedByExports = usedByExports;
57 parser.state.module.addDependency(dep);
58 break;
59 }
60 }
61 });
62 };
63
64 parser.hooks.program.tap("InnerGraphPlugin", () => {
65 InnerGraph.enable(parser.state);
66 });
67
68 parser.hooks.finish.tap("InnerGraphPlugin", () => {
69 if (!InnerGraph.isEnabled(parser.state)) return;
70
71 logger.time("infer dependency usage");
72 InnerGraph.inferDependencyUsage(parser.state);
73 logger.timeAggregate("infer dependency usage");
74 });
75
76 // During prewalking the following datastructures are filled with
77 // nodes that have a TopLevelSymbol assigned and
78 // variables are tagged with the assigned TopLevelSymbol
79
80 // We differ 3 types of nodes:
81 // 1. full statements (export default, function declaration)
82 // 2. classes (class declaration, class expression)
83 // 3. variable declarators (const x = ...)
84
85 /** @type {WeakMap<Node, TopLevelSymbol>} */
86 const statementWithTopLevelSymbol = new WeakMap();
87 /** @type {WeakMap<Node, Node>} */
88 const statementPurePart = new WeakMap();
89
90 /** @type {WeakMap<ClassExpressionNode | ClassDeclarationNode, TopLevelSymbol>} */
91 const classWithTopLevelSymbol = new WeakMap();
92
93 /** @type {WeakMap<VariableDeclaratorNode, TopLevelSymbol>} */
94 const declWithTopLevelSymbol = new WeakMap();
95 /** @type {WeakSet<VariableDeclaratorNode>} */
96 const pureDeclarators = new WeakSet();
97
98 // The following hooks are used during prewalking:
99
100 parser.hooks.preStatement.tap("InnerGraphPlugin", statement => {
101 if (!InnerGraph.isEnabled(parser.state)) return;
102
103 if (parser.scope.topLevelScope === true) {
104 if (statement.type === "FunctionDeclaration") {
105 const name = statement.id ? statement.id.name : "*default*";
106 const fn = InnerGraph.tagTopLevelSymbol(parser, name);
107 statementWithTopLevelSymbol.set(statement, fn);
108 return true;
109 }
110 }
111 });
112
113 parser.hooks.blockPreStatement.tap("InnerGraphPlugin", statement => {
114 if (!InnerGraph.isEnabled(parser.state)) return;
115
116 if (parser.scope.topLevelScope === true) {
117 if (statement.type === "ClassDeclaration") {
118 const name = statement.id ? statement.id.name : "*default*";
119 const fn = InnerGraph.tagTopLevelSymbol(parser, name);
120 classWithTopLevelSymbol.set(statement, fn);
121 return true;
122 }
123 if (statement.type === "ExportDefaultDeclaration") {
124 const name = "*default*";
125 const fn = InnerGraph.tagTopLevelSymbol(parser, name);
126 const decl = statement.declaration;
127 if (
128 decl.type === "ClassExpression" ||
129 decl.type === "ClassDeclaration"
130 ) {
131 classWithTopLevelSymbol.set(decl, fn);
132 } else if (parser.isPure(decl, statement.range[0])) {
133 statementWithTopLevelSymbol.set(statement, fn);
134 if (
135 !decl.type.endsWith("FunctionExpression") &&
136 !decl.type.endsWith("Declaration") &&
137 decl.type !== "Literal"
138 ) {
139 statementPurePart.set(statement, decl);
140 }
141 }
142 }
143 }
144 });
145
146 parser.hooks.preDeclarator.tap(
147 "InnerGraphPlugin",
148 (decl, statement) => {
149 if (!InnerGraph.isEnabled(parser.state)) return;
150 if (
151 parser.scope.topLevelScope === true &&
152 decl.init &&
153 decl.id.type === "Identifier"
154 ) {
155 const name = decl.id.name;
156 if (decl.init.type === "ClassExpression") {
157 const fn = InnerGraph.tagTopLevelSymbol(parser, name);
158 classWithTopLevelSymbol.set(decl.init, fn);
159 } else if (parser.isPure(decl.init, decl.id.range[1])) {
160 const fn = InnerGraph.tagTopLevelSymbol(parser, name);
161 declWithTopLevelSymbol.set(decl, fn);
162 if (
163 !decl.init.type.endsWith("FunctionExpression") &&
164 decl.init.type !== "Literal"
165 ) {
166 pureDeclarators.add(decl);
167 }
168 return true;
169 }
170 }
171 }
172 );
173
174 // During real walking we set the TopLevelSymbol state to the assigned
175 // TopLevelSymbol by using the fill datastructures.
176
177 // In addition to tracking TopLevelSymbols, we sometimes need to
178 // add a PureExpressionDependency. This is needed to skip execution
179 // of pure expressions, even when they are not dropped due to
180 // minimizing. Otherwise symbols used there might not exist anymore
181 // as they are removed as unused by this optimization
182
183 // When we find a reference to a TopLevelSymbol, we register a
184 // TopLevelSymbol dependency from TopLevelSymbol in state to the
185 // referenced TopLevelSymbol. This way we get a graph of all
186 // TopLevelSymbols.
187
188 // The following hooks are called during walking:
189
190 parser.hooks.statement.tap("InnerGraphPlugin", statement => {
191 if (!InnerGraph.isEnabled(parser.state)) return;
192 if (parser.scope.topLevelScope === true) {
193 InnerGraph.setTopLevelSymbol(parser.state, undefined);
194
195 const fn = statementWithTopLevelSymbol.get(statement);
196 if (fn) {
197 InnerGraph.setTopLevelSymbol(parser.state, fn);
198 const purePart = statementPurePart.get(statement);
199 if (purePart) {
200 InnerGraph.onUsage(parser.state, usedByExports => {
201 switch (usedByExports) {
202 case undefined:
203 case true:
204 return;
205 default: {
206 const dep = new PureExpressionDependency(
207 purePart.range
208 );
209 dep.loc = statement.loc;
210 dep.usedByExports = usedByExports;
211 parser.state.module.addDependency(dep);
212 break;
213 }
214 }
215 });
216 }
217 }
218 }
219 });
220
221 parser.hooks.classExtendsExpression.tap(
222 "InnerGraphPlugin",
223 (expr, statement) => {
224 if (!InnerGraph.isEnabled(parser.state)) return;
225 if (parser.scope.topLevelScope === true) {
226 const fn = classWithTopLevelSymbol.get(statement);
227 if (
228 fn &&
229 parser.isPure(
230 expr,
231 statement.id ? statement.id.range[1] : statement.range[0]
232 )
233 ) {
234 InnerGraph.setTopLevelSymbol(parser.state, fn);
235 onUsageSuper(expr);
236 }
237 }
238 }
239 );
240
241 parser.hooks.classBodyElement.tap(
242 "InnerGraphPlugin",
243 (element, classDefinition) => {
244 if (!InnerGraph.isEnabled(parser.state)) return;
245 if (parser.scope.topLevelScope === true) {
246 const fn = classWithTopLevelSymbol.get(classDefinition);
247 if (fn) {
248 InnerGraph.setTopLevelSymbol(parser.state, undefined);
249 }
250 }
251 }
252 );
253
254 parser.hooks.classBodyValue.tap(
255 "InnerGraphPlugin",
256 (expression, element, classDefinition) => {
257 if (!InnerGraph.isEnabled(parser.state)) return;
258 if (parser.scope.topLevelScope === true) {
259 const fn = classWithTopLevelSymbol.get(classDefinition);
260 if (fn) {
261 if (
262 !element.static ||
263 parser.isPure(
264 expression,
265 element.key ? element.key.range[1] : element.range[0]
266 )
267 ) {
268 InnerGraph.setTopLevelSymbol(parser.state, fn);
269 if (element.type !== "MethodDefinition" && element.static) {
270 InnerGraph.onUsage(parser.state, usedByExports => {
271 switch (usedByExports) {
272 case undefined:
273 case true:
274 return;
275 default: {
276 const dep = new PureExpressionDependency(
277 expression.range
278 );
279 dep.loc = expression.loc;
280 dep.usedByExports = usedByExports;
281 parser.state.module.addDependency(dep);
282 break;
283 }
284 }
285 });
286 }
287 } else {
288 InnerGraph.setTopLevelSymbol(parser.state, undefined);
289 }
290 }
291 }
292 }
293 );
294
295 parser.hooks.declarator.tap("InnerGraphPlugin", (decl, statement) => {
296 if (!InnerGraph.isEnabled(parser.state)) return;
297 const fn = declWithTopLevelSymbol.get(decl);
298
299 if (fn) {
300 InnerGraph.setTopLevelSymbol(parser.state, fn);
301 if (pureDeclarators.has(decl)) {
302 if (decl.init.type === "ClassExpression") {
303 if (decl.init.superClass) {
304 onUsageSuper(decl.init.superClass);
305 }
306 } else {
307 InnerGraph.onUsage(parser.state, usedByExports => {
308 switch (usedByExports) {
309 case undefined:
310 case true:
311 return;
312 default: {
313 const dep = new PureExpressionDependency(
314 decl.init.range
315 );
316 dep.loc = decl.loc;
317 dep.usedByExports = usedByExports;
318 parser.state.module.addDependency(dep);
319 break;
320 }
321 }
322 });
323 }
324 }
325 parser.walkExpression(decl.init);
326 InnerGraph.setTopLevelSymbol(parser.state, undefined);
327 return true;
328 }
329 });
330
331 parser.hooks.expression
332 .for(topLevelSymbolTag)
333 .tap("InnerGraphPlugin", () => {
334 const topLevelSymbol = /** @type {TopLevelSymbol} */ (
335 parser.currentTagData
336 );
337 const currentTopLevelSymbol = InnerGraph.getTopLevelSymbol(
338 parser.state
339 );
340 InnerGraph.addUsage(
341 parser.state,
342 topLevelSymbol,
343 currentTopLevelSymbol || true
344 );
345 });
346 parser.hooks.assign
347 .for(topLevelSymbolTag)
348 .tap("InnerGraphPlugin", expr => {
349 if (!InnerGraph.isEnabled(parser.state)) return;
350 if (expr.operator === "=") return true;
351 });
352 };
353 normalModuleFactory.hooks.parser
354 .for("javascript/auto")
355 .tap("InnerGraphPlugin", handler);
356 normalModuleFactory.hooks.parser
357 .for("javascript/esm")
358 .tap("InnerGraphPlugin", handler);
359
360 compilation.hooks.finishModules.tap("InnerGraphPlugin", () => {
361 logger.timeAggregateEnd("infer dependency usage");
362 });
363 }
364 );
365 }
366}
367
368module.exports = InnerGraphPlugin;
Note: See TracBrowser for help on using the repository browser.