UNPKG

4.43 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 let providedExportsAreTemporary;
36
37 const processDependenciesBlock = depBlock => {
38 for (const dep of depBlock.dependencies) {
39 if (processDependency(dep)) return true;
40 }
41 for (const variable of depBlock.variables) {
42 for (const dep of variable.dependencies) {
43 if (processDependency(dep)) return true;
44 }
45 }
46 for (const block of depBlock.blocks) {
47 if (processDependenciesBlock(block)) return true;
48 }
49 return false;
50 };
51
52 const processDependency = dep => {
53 const exportDesc = dep.getExports && dep.getExports();
54 if (!exportDesc) return;
55 moduleWithExports = true;
56 const exports = exportDesc.exports;
57 // break early if it's only in the worst state
58 if (module.buildMeta.providedExports === true) {
59 return true;
60 }
61 // break if it should move to the worst state
62 if (exports === true) {
63 module.buildMeta.providedExports = true;
64 notifyDependencies();
65 return true;
66 }
67 // merge in new exports
68 if (Array.isArray(exports)) {
69 if (addToSet(moduleProvidedExports, exports)) {
70 notifyDependencies();
71 }
72 }
73 // store dependencies
74 const exportDeps = exportDesc.dependencies;
75 if (exportDeps) {
76 providedExportsAreTemporary = true;
77 for (const exportDependency of exportDeps) {
78 // add dependency for this module
79 const set = dependencies.get(exportDependency);
80 if (set === undefined) {
81 dependencies.set(exportDependency, new Set([module]));
82 } else {
83 set.add(module);
84 }
85 }
86 }
87 return false;
88 };
89
90 const notifyDependencies = () => {
91 const deps = dependencies.get(module);
92 if (deps !== undefined) {
93 for (const dep of deps) {
94 queue.enqueue(dep);
95 }
96 }
97 };
98
99 // Start with all modules without provided exports
100 for (const module of modules) {
101 if (module.buildInfo.temporaryProvidedExports) {
102 // Clear exports when they are temporary
103 // and recreate them
104 module.buildMeta.providedExports = null;
105 queue.enqueue(module);
106 } else if (!module.buildMeta.providedExports) {
107 queue.enqueue(module);
108 }
109 }
110
111 while (queue.length > 0) {
112 module = queue.dequeue();
113
114 if (module.buildMeta.providedExports !== true) {
115 moduleWithExports =
116 module.buildMeta && module.buildMeta.exportsType;
117 moduleProvidedExports = Array.isArray(
118 module.buildMeta.providedExports
119 )
120 ? new Set(module.buildMeta.providedExports)
121 : new Set();
122 providedExportsAreTemporary = false;
123 processDependenciesBlock(module);
124 module.buildInfo.temporaryProvidedExports = providedExportsAreTemporary;
125 if (!moduleWithExports) {
126 module.buildMeta.providedExports = true;
127 notifyDependencies();
128 } else if (module.buildMeta.providedExports !== true) {
129 module.buildMeta.providedExports = Array.from(
130 moduleProvidedExports
131 );
132 }
133 }
134 }
135 }
136 );
137 const providedExportsCache = new WeakMap();
138 compilation.hooks.rebuildModule.tap(
139 "FlagDependencyExportsPlugin",
140 module => {
141 providedExportsCache.set(module, module.buildMeta.providedExports);
142 }
143 );
144 compilation.hooks.finishRebuildingModule.tap(
145 "FlagDependencyExportsPlugin",
146 module => {
147 module.buildMeta.providedExports = providedExportsCache.get(module);
148 }
149 );
150 }
151 );
152 }
153}
154
155module.exports = FlagDependencyExportsPlugin;