-
Notifications
You must be signed in to change notification settings - Fork 0
/
DebugImportVarsWebpackPlugin.js
141 lines (128 loc) · 4.37 KB
/
DebugImportVarsWebpackPlugin.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
const HarmonyImportDependency = require("webpack/lib/dependencies/HarmonyImportDependency");
const Dependency = require("webpack/lib/Dependency");
let makeSerializable;
try {
makeSerializable = require("webpack/lib/util/makeSerializable");
} catch (e) {
makeSerializable = () => {};
}
module.exports = class DebugImportVarsWebpackPlugin {
apply(compiler) {
compiler.hooks.compilation.tap(
"DebugImportVarsWebpackPlugin",
(compilation) => {
compilation.dependencyTemplates.set(
DebugImportVarsDependency,
new DebugImportVarsDependency.Template()
);
}
);
compiler.hooks.normalModuleFactory.tap(
"DebugImportVarsWebpackPlugin",
(factory) => {
factory.hooks.parser
.for("javascript/auto")
.tap("DebugImportVarsWebpackPlugin", (parser) => {
// need to use "importSpecifier" instead of "import", because for some reason
// HarmonyImportDependencyParserPlugin stops execution of the hook chain.
parser.hooks.importSpecifier.tap(
"DebugImportVarsWebpackPlugin",
(statement) => {
// capturing the output of HarmonyImportDependencyParserPlugin on the import hook
const dependency = last(parser.state.module.dependencies);
if (dependency instanceof HarmonyImportDependency) {
parser.state.module.addDependency(
new DebugImportVarsDependency(
dependency,
statement.specifiers
)
);
}
}
);
});
}
);
}
};
class DebugImportVarsDependency extends Dependency {
constructor(harmonyDependency, specifiers) {
super();
this.harmonyDependency = harmonyDependency;
this.specifiers = specifiers?.map((specifier) => {
return {
type: specifier.type,
localName: specifier.local?.name,
importedName: specifier.imported?.name,
};
});
}
updateHash(hash) {
super.updateHash(hash);
for (const specifier of this.specifiers) {
hash.update(Object.values(specifier).join("|"));
}
}
serialize(context) {
const { write } = context;
this.harmonyDependency.serialize(context);
write(this.specifiers);
super.serialize(context);
}
deserialize(context) {
const { read } = context;
this.harmonyDependency = new HarmonyImportDependency().deserialize(context);
this.specifiers = read();
super.deserialize(context);
}
}
makeSerializable(DebugImportVarsDependency, "DebugImportVarsDependency");
DebugImportVarsDependency.Template = class DebugImportVarsDependencyTemplate {
apply(dep, source, runtimeOrTemplateContextInWebpack5) {
const moduleGraph = runtimeOrTemplateContextInWebpack5?.moduleGraph;
const generatedModuleName = dep.harmonyDependency.getImportVar(moduleGraph);
const debugImportVar = this.getDebugImportVar(
generatedModuleName,
dep.specifiers
);
source.insert(0, debugImportVar);
}
getDebugImportVar(generatedModuleName, specifiers) {
const importVars = specifiers
.map((specifier) => {
const localName = specifier.localName;
switch (specifier.type) {
case "ImportSpecifier":
return [
localName,
`${generatedModuleName}.${specifier.importedName}`,
];
case "ImportNamespaceSpecifier":
return [localName, generatedModuleName];
case "ImportDefaultSpecifier":
return [
localName,
// add fallback to namespace import if there is no default export
`${generatedModuleName}.default;if(typeof ${localName}==="undefined")${localName}=${generatedModuleName}`,
];
default:
return null;
}
})
.filter(Boolean);
if (!importVars.length) {
return "";
}
const declareImportVars = `let ${importVars
.map((importVar) => importVar[0])
.join(",")};`;
// init vars asynchronously to allow cycles in the dependency graph
const asyncInitImportVars = `setTimeout(() => {${importVars
.map((importVar) => `${importVar[0]} = ${importVar[1]}`)
.join(";")}}, 0);`;
return `${declareImportVars}${asyncInitImportVars}\n`;
}
};
function last(arr) {
return arr[arr.length - 1];
}