1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | "use strict";
|
7 |
|
8 | const util = require("util");
|
9 | const ExternalModule = require("./ExternalModule");
|
10 | const { resolveByProperty, cachedSetProperty } = require("./util/cleverMerge");
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | const UNSPECIFIED_EXTERNAL_TYPE_REGEXP = /^[a-z0-9]+ /;
|
16 | const EMPTY_RESOLVE_OPTIONS = {};
|
17 |
|
18 |
|
19 | const callDeprecatedExternals = util.deprecate(
|
20 | (externalsFunction, context, request, cb) => {
|
21 | externalsFunction.call(null, context, request, cb);
|
22 | },
|
23 | "The externals-function should be defined like ({context, request}, cb) => { ... }",
|
24 | "DEP_WEBPACK_EXTERNALS_FUNCTION_PARAMETERS"
|
25 | );
|
26 |
|
27 | const cache = new WeakMap();
|
28 |
|
29 | const resolveLayer = (obj, layer) => {
|
30 | let map = cache.get(obj);
|
31 | if (map === undefined) {
|
32 | map = new Map();
|
33 | cache.set(obj, map);
|
34 | } else {
|
35 | const cacheEntry = map.get(layer);
|
36 | if (cacheEntry !== undefined) return cacheEntry;
|
37 | }
|
38 | const result = resolveByProperty(obj, "byLayer", layer);
|
39 | map.set(layer, result);
|
40 | return result;
|
41 | };
|
42 |
|
43 | class ExternalModuleFactoryPlugin {
|
44 | |
45 |
|
46 |
|
47 |
|
48 | constructor(type, externals) {
|
49 | this.type = type;
|
50 | this.externals = externals;
|
51 | }
|
52 |
|
53 | |
54 |
|
55 |
|
56 |
|
57 | apply(normalModuleFactory) {
|
58 | const globalType = this.type;
|
59 | normalModuleFactory.hooks.factorize.tapAsync(
|
60 | "ExternalModuleFactoryPlugin",
|
61 | (data, callback) => {
|
62 | const context = data.context;
|
63 | const contextInfo = data.contextInfo;
|
64 | const dependency = data.dependencies[0];
|
65 |
|
66 | |
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 | const handleExternal = (value, type, callback) => {
|
73 | if (value === false) {
|
74 |
|
75 | return callback();
|
76 | }
|
77 |
|
78 | let externalConfig;
|
79 | if (value === true) {
|
80 | externalConfig = dependency.request;
|
81 | } else {
|
82 | externalConfig = value;
|
83 | }
|
84 |
|
85 | if (type === undefined) {
|
86 | if (
|
87 | typeof externalConfig === "string" &&
|
88 | UNSPECIFIED_EXTERNAL_TYPE_REGEXP.test(externalConfig)
|
89 | ) {
|
90 | const idx = externalConfig.indexOf(" ");
|
91 | type = externalConfig.substr(0, idx);
|
92 | externalConfig = externalConfig.substr(idx + 1);
|
93 | } else if (
|
94 | Array.isArray(externalConfig) &&
|
95 | externalConfig.length > 0 &&
|
96 | UNSPECIFIED_EXTERNAL_TYPE_REGEXP.test(externalConfig[0])
|
97 | ) {
|
98 | const firstItem = externalConfig[0];
|
99 | const idx = firstItem.indexOf(" ");
|
100 | type = firstItem.substr(0, idx);
|
101 | externalConfig = [
|
102 | firstItem.substr(idx + 1),
|
103 | ...externalConfig.slice(1)
|
104 | ];
|
105 | }
|
106 | }
|
107 | callback(
|
108 | null,
|
109 | new ExternalModule(
|
110 | externalConfig,
|
111 | type || globalType,
|
112 | dependency.request
|
113 | )
|
114 | );
|
115 | };
|
116 |
|
117 | |
118 |
|
119 |
|
120 |
|
121 |
|
122 | const handleExternals = (externals, callback) => {
|
123 | if (typeof externals === "string") {
|
124 | if (externals === dependency.request) {
|
125 | return handleExternal(dependency.request, undefined, callback);
|
126 | }
|
127 | } else if (Array.isArray(externals)) {
|
128 | let i = 0;
|
129 | const next = () => {
|
130 | let asyncFlag;
|
131 | const handleExternalsAndCallback = (err, module) => {
|
132 | if (err) return callback(err);
|
133 | if (!module) {
|
134 | if (asyncFlag) {
|
135 | asyncFlag = false;
|
136 | return;
|
137 | }
|
138 | return next();
|
139 | }
|
140 | callback(null, module);
|
141 | };
|
142 |
|
143 | do {
|
144 | asyncFlag = true;
|
145 | if (i >= externals.length) return callback();
|
146 | handleExternals(externals[i++], handleExternalsAndCallback);
|
147 | } while (!asyncFlag);
|
148 | asyncFlag = false;
|
149 | };
|
150 |
|
151 | next();
|
152 | return;
|
153 | } else if (externals instanceof RegExp) {
|
154 | if (externals.test(dependency.request)) {
|
155 | return handleExternal(dependency.request, undefined, callback);
|
156 | }
|
157 | } else if (typeof externals === "function") {
|
158 | const cb = (err, value, type) => {
|
159 | if (err) return callback(err);
|
160 | if (value !== undefined) {
|
161 | handleExternal(value, type, callback);
|
162 | } else {
|
163 | callback();
|
164 | }
|
165 | };
|
166 | if (externals.length === 3) {
|
167 |
|
168 | callDeprecatedExternals(
|
169 | externals,
|
170 | context,
|
171 | dependency.request,
|
172 | cb
|
173 | );
|
174 | } else {
|
175 | const dependencyType = dependency.category || "";
|
176 | const promise = externals(
|
177 | {
|
178 | context,
|
179 | request: dependency.request,
|
180 | dependencyType,
|
181 | contextInfo,
|
182 | getResolve: options => (context, request, callback) => {
|
183 | const resolveContext = {
|
184 | fileDependencies: data.fileDependencies,
|
185 | missingDependencies: data.missingDependencies,
|
186 | contextDependencies: data.contextDependencies
|
187 | };
|
188 | let resolver = normalModuleFactory.getResolver(
|
189 | "normal",
|
190 | dependencyType
|
191 | ? cachedSetProperty(
|
192 | data.resolveOptions || EMPTY_RESOLVE_OPTIONS,
|
193 | "dependencyType",
|
194 | dependencyType
|
195 | )
|
196 | : data.resolveOptions
|
197 | );
|
198 | if (options) resolver = resolver.withOptions(options);
|
199 | if (callback) {
|
200 | resolver.resolve(
|
201 | {},
|
202 | context,
|
203 | request,
|
204 | resolveContext,
|
205 | callback
|
206 | );
|
207 | } else {
|
208 | return new Promise((resolve, reject) => {
|
209 | resolver.resolve(
|
210 | {},
|
211 | context,
|
212 | request,
|
213 | resolveContext,
|
214 | (err, result) => {
|
215 | if (err) reject(err);
|
216 | else resolve(result);
|
217 | }
|
218 | );
|
219 | });
|
220 | }
|
221 | }
|
222 | },
|
223 | cb
|
224 | );
|
225 | if (promise && promise.then) promise.then(r => cb(null, r), cb);
|
226 | }
|
227 | return;
|
228 | } else if (typeof externals === "object") {
|
229 | const resolvedExternals = resolveLayer(
|
230 | externals,
|
231 | contextInfo.issuerLayer
|
232 | );
|
233 | if (
|
234 | Object.prototype.hasOwnProperty.call(
|
235 | resolvedExternals,
|
236 | dependency.request
|
237 | )
|
238 | ) {
|
239 | return handleExternal(
|
240 | resolvedExternals[dependency.request],
|
241 | undefined,
|
242 | callback
|
243 | );
|
244 | }
|
245 | }
|
246 | callback();
|
247 | };
|
248 |
|
249 | handleExternals(this.externals, callback);
|
250 | }
|
251 | );
|
252 | }
|
253 | }
|
254 | module.exports = ExternalModuleFactoryPlugin;
|