UNPKG

4 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5"use strict";
6
7const Queue = require("./util/Queue");
8
9const addToSet = (a, b) => {
10 let changed = false;
11 for (const item of b) {
12 if (!a.has(item)) {
13 a.add(item);
14 changed = true;
15 }
16 }
17 return changed;
18};
19
20class FlagDependencyExportsPlugin {
21 apply(compiler) {
22 compiler.hooks.compilation.tap(
23 "FlagDependencyExportsPlugin",
24 compilation => {
25 compilation.hooks.finishModules.tap(
26 "FlagDependencyExportsPlugin",
27 modules => {
28 const dependencies = new Map();
29
30 const queue = new Queue();
31
32 let module;
33 let moduleWithExports;
34 let moduleProvidedExports;
35
36 const processDependenciesBlock = depBlock => {
37 for (const dep of depBlock.dependencies) {
38 if (processDependency(dep)) return true;
39 }
40 for (const variable of depBlock.variables) {
41 for (const dep of variable.dependencies) {
42 if (processDependency(dep)) return true;
43 }
44 }
45 for (const block of depBlock.blocks) {
46 if (processDependenciesBlock(block)) return true;
47 }
48 return false;
49 };
50
51 const processDependency = dep => {
52 const exportDesc = dep.getExports && dep.getExports();
53 if (!exportDesc) return;
54 moduleWithExports = true;
55 const exports = exportDesc.exports;
56 // break early if it's only in the worst state
57 if (module.buildMeta.providedExports === true) {
58 return true;
59 }
60 // break if it should move to the worst state
61 if (exports === true) {
62 module.buildMeta.providedExports = true;
63 notifyDependencies();
64 return true;
65 }
66 // merge in new exports
67 if (Array.isArray(exports)) {
68 if (addToSet(moduleProvidedExports, exports)) {
69 notifyDependencies();
70 }
71 }
72 // store dependencies
73 const exportDeps = exportDesc.dependencies;
74 if (exportDeps) {
75 for (const exportDependency of exportDeps) {
76 // add dependency for this module
77 const set = dependencies.get(exportDependency);
78 if (set === undefined) {
79 dependencies.set(exportDependency, new Set([module]));
80 } else {
81 set.add(module);
82 }
83 }
84 }
85 return false;
86 };
87
88 const notifyDependencies = () => {
89 const deps = dependencies.get(module);
90 if (deps !== undefined) {
91 for (const dep of deps) {
92 queue.enqueue(dep);
93 }
94 }
95 };
96
97 // Start with all modules without provided exports
98 for (const module of modules) {
99 if (!module.buildMeta.providedExports) {
100 queue.enqueue(module);
101 }
102 }
103
104 while (queue.length > 0) {
105 module = queue.dequeue();
106
107 if (module.buildMeta.providedExports !== true) {
108 moduleWithExports =
109 module.buildMeta && module.buildMeta.exportsType;
110 moduleProvidedExports = Array.isArray(
111 module.buildMeta.providedExports
112 )
113 ? new Set(module.buildMeta.providedExports)
114 : new Set();
115 processDependenciesBlock(module);
116 if (!moduleWithExports) {
117 module.buildMeta.providedExports = true;
118 notifyDependencies();
119 } else if (module.buildMeta.providedExports !== true) {
120 module.buildMeta.providedExports = Array.from(
121 moduleProvidedExports
122 );
123 }
124 }
125 }
126 }
127 );
128 const providedExportsCache = new WeakMap();
129 compilation.hooks.rebuildModule.tap(
130 "FlagDependencyExportsPlugin",
131 module => {
132 providedExportsCache.set(module, module.buildMeta.providedExports);
133 }
134 );
135 compilation.hooks.finishRebuildingModule.tap(
136 "FlagDependencyExportsPlugin",
137 module => {
138 module.buildMeta.providedExports = providedExportsCache.get(module);
139 }
140 );
141 }
142 );
143 }
144}
145
146module.exports = FlagDependencyExportsPlugin;