webpack 5.69.1 → 5.70.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of webpack might be problematic. Click here for more details.
- package/lib/BannerPlugin.js +10 -4
- package/lib/CleanPlugin.js +64 -18
- package/lib/Compilation.js +41 -17
- package/lib/ContextModule.js +90 -26
- package/lib/ContextModuleFactory.js +65 -21
- package/lib/EntryOptionPlugin.js +1 -0
- package/lib/Generator.js +1 -0
- package/lib/ModuleHashingError.js +29 -0
- package/lib/NodeStuffPlugin.js +10 -0
- package/lib/NormalModule.js +21 -16
- package/lib/NormalModuleFactory.js +15 -8
- package/lib/ProgressPlugin.js +3 -4
- package/lib/RuntimeTemplate.js +1 -0
- package/lib/WebpackOptionsApply.js +2 -0
- package/lib/asset/AssetGenerator.js +119 -31
- package/lib/cache/ResolverCachePlugin.js +89 -28
- package/lib/config/browserslistTargetHandler.js +3 -5
- package/lib/config/normalization.js +1 -0
- package/lib/dependencies/ContextDependencyHelpers.js +1 -1
- package/lib/dependencies/HarmonyAcceptImportDependency.js +5 -3
- package/lib/dependencies/HarmonyExportInitFragment.js +4 -1
- package/lib/dependencies/ImportContextDependency.js +0 -2
- package/lib/dependencies/ImportMetaContextDependency.js +35 -0
- package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +252 -0
- package/lib/dependencies/ImportMetaContextPlugin.js +59 -0
- package/lib/dependencies/LoaderPlugin.js +2 -0
- package/lib/dependencies/RequireContextDependency.js +0 -16
- package/lib/esm/ModuleChunkLoadingRuntimeModule.js +24 -8
- package/lib/node/ReadFileChunkLoadingRuntimeModule.js +22 -7
- package/lib/node/RequireChunkLoadingRuntimeModule.js +22 -7
- package/lib/schemes/HttpUriPlugin.js +44 -3
- package/lib/util/internalSerializables.js +2 -0
- package/lib/web/JsonpChunkLoadingRuntimeModule.js +15 -5
- package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +30 -20
- package/module.d.ts +15 -0
- package/package.json +2 -2
- package/schemas/WebpackOptions.check.js +1 -1
- package/schemas/WebpackOptions.json +17 -1
- package/schemas/plugins/schemes/HttpUriPlugin.check.js +1 -1
- package/schemas/plugins/schemes/HttpUriPlugin.json +4 -0
- package/types.d.ts +164 -73
package/lib/BannerPlugin.js
CHANGED
@@ -77,6 +77,7 @@ class BannerPlugin {
|
|
77
77
|
undefined,
|
78
78
|
options
|
79
79
|
);
|
80
|
+
const cache = new WeakMap();
|
80
81
|
|
81
82
|
compiler.hooks.compilation.tap("BannerPlugin", compilation => {
|
82
83
|
compilation.hooks.processAssets.tap(
|
@@ -102,10 +103,15 @@ class BannerPlugin {
|
|
102
103
|
|
103
104
|
const comment = compilation.getPath(banner, data);
|
104
105
|
|
105
|
-
compilation.updateAsset(
|
106
|
-
|
107
|
-
|
108
|
-
|
106
|
+
compilation.updateAsset(file, old => {
|
107
|
+
let cached = cache.get(old);
|
108
|
+
if (!cached || cached.comment !== comment) {
|
109
|
+
const source = new ConcatSource(comment, "\n", old);
|
110
|
+
cache.set(old, { source, comment });
|
111
|
+
return source;
|
112
|
+
}
|
113
|
+
return cached.source;
|
114
|
+
});
|
109
115
|
}
|
110
116
|
}
|
111
117
|
}
|
package/lib/CleanPlugin.js
CHANGED
@@ -19,6 +19,7 @@ const processAsyncTree = require("./util/processAsyncTree");
|
|
19
19
|
/** @typedef {import("./util/fs").StatsCallback} StatsCallback */
|
20
20
|
|
21
21
|
/** @typedef {(function(string):boolean)|RegExp} IgnoreItem */
|
22
|
+
/** @typedef {Map<string, number>} Assets */
|
22
23
|
/** @typedef {function(IgnoreItem): void} AddToIgnoreCallback */
|
23
24
|
|
24
25
|
/**
|
@@ -40,18 +41,32 @@ const validate = createSchemaValidation(
|
|
40
41
|
baseDataPath: "options"
|
41
42
|
}
|
42
43
|
);
|
44
|
+
const _10sec = 10 * 1000;
|
45
|
+
|
46
|
+
/**
|
47
|
+
* marge assets map 2 into map 1
|
48
|
+
* @param {Assets} as1 assets
|
49
|
+
* @param {Assets} as2 assets
|
50
|
+
* @returns {void}
|
51
|
+
*/
|
52
|
+
const mergeAssets = (as1, as2) => {
|
53
|
+
for (const [key, value1] of as2) {
|
54
|
+
const value2 = as1.get(key);
|
55
|
+
if (!value2 || value1 > value2) as1.set(key, value1);
|
56
|
+
}
|
57
|
+
};
|
43
58
|
|
44
59
|
/**
|
45
60
|
* @param {OutputFileSystem} fs filesystem
|
46
61
|
* @param {string} outputPath output path
|
47
|
-
* @param {
|
62
|
+
* @param {Map<string, number>} currentAssets filename of the current assets (must not start with .. or ., must only use / as path separator)
|
48
63
|
* @param {function((Error | null)=, Set<string>=): void} callback returns the filenames of the assets that shouldn't be there
|
49
64
|
* @returns {void}
|
50
65
|
*/
|
51
66
|
const getDiffToFs = (fs, outputPath, currentAssets, callback) => {
|
52
67
|
const directories = new Set();
|
53
68
|
// get directories of assets
|
54
|
-
for (const asset of currentAssets) {
|
69
|
+
for (const [asset] of currentAssets) {
|
55
70
|
directories.add(asset.replace(/(^|\/)[^/]*$/, ""));
|
56
71
|
}
|
57
72
|
// and all parent directories
|
@@ -91,13 +106,15 @@ const getDiffToFs = (fs, outputPath, currentAssets, callback) => {
|
|
91
106
|
};
|
92
107
|
|
93
108
|
/**
|
94
|
-
* @param {
|
95
|
-
* @param {
|
109
|
+
* @param {Assets} currentAssets assets list
|
110
|
+
* @param {Assets} oldAssets old assets list
|
96
111
|
* @returns {Set<string>} diff
|
97
112
|
*/
|
98
113
|
const getDiffToOldAssets = (currentAssets, oldAssets) => {
|
99
114
|
const diff = new Set();
|
100
|
-
|
115
|
+
const now = Date.now();
|
116
|
+
for (const [asset, ts] of oldAssets) {
|
117
|
+
if (ts >= now) continue;
|
101
118
|
if (!currentAssets.has(asset)) diff.add(asset);
|
102
119
|
}
|
103
120
|
return diff;
|
@@ -124,7 +141,7 @@ const doStat = (fs, filename, callback) => {
|
|
124
141
|
* @param {Logger} logger logger
|
125
142
|
* @param {Set<string>} diff filenames of the assets that shouldn't be there
|
126
143
|
* @param {function(string): boolean} isKept check if the entry is ignored
|
127
|
-
* @param {function(Error=): void} callback callback
|
144
|
+
* @param {function(Error=, Assets=): void} callback callback
|
128
145
|
* @returns {void}
|
129
146
|
*/
|
130
147
|
const applyDiff = (fs, outputPath, dry, logger, diff, isKept, callback) => {
|
@@ -137,11 +154,13 @@ const applyDiff = (fs, outputPath, dry, logger, diff, isKept, callback) => {
|
|
137
154
|
};
|
138
155
|
/** @typedef {{ type: "check" | "unlink" | "rmdir", filename: string, parent: { remaining: number, job: Job } | undefined }} Job */
|
139
156
|
/** @type {Job[]} */
|
140
|
-
const jobs = Array.from(diff, filename => ({
|
157
|
+
const jobs = Array.from(diff.keys(), filename => ({
|
141
158
|
type: "check",
|
142
159
|
filename,
|
143
160
|
parent: undefined
|
144
161
|
}));
|
162
|
+
/** @type {Assets} */
|
163
|
+
const keptAssets = new Map();
|
145
164
|
processAsyncTree(
|
146
165
|
jobs,
|
147
166
|
10,
|
@@ -161,6 +180,7 @@ const applyDiff = (fs, outputPath, dry, logger, diff, isKept, callback) => {
|
|
161
180
|
switch (type) {
|
162
181
|
case "check":
|
163
182
|
if (isKept(filename)) {
|
183
|
+
keptAssets.set(filename, 0);
|
164
184
|
// do not decrement parent entry as we don't want to delete the parent
|
165
185
|
log(`${filename} will be kept`);
|
166
186
|
return process.nextTick(callback);
|
@@ -247,7 +267,10 @@ const applyDiff = (fs, outputPath, dry, logger, diff, isKept, callback) => {
|
|
247
267
|
break;
|
248
268
|
}
|
249
269
|
},
|
250
|
-
|
270
|
+
err => {
|
271
|
+
if (err) return callback(err);
|
272
|
+
callback(undefined, keptAssets);
|
273
|
+
}
|
251
274
|
);
|
252
275
|
};
|
253
276
|
|
@@ -302,6 +325,7 @@ class CleanPlugin {
|
|
302
325
|
// We assume that no external modification happens while the compiler is active
|
303
326
|
// So we can store the old assets and only diff to them to avoid fs access on
|
304
327
|
// incremental builds
|
328
|
+
/** @type {undefined|Assets} */
|
305
329
|
let oldAssets;
|
306
330
|
|
307
331
|
compiler.hooks.emit.tapAsync(
|
@@ -322,7 +346,9 @@ class CleanPlugin {
|
|
322
346
|
);
|
323
347
|
}
|
324
348
|
|
325
|
-
|
349
|
+
/** @type {Assets} */
|
350
|
+
const currentAssets = new Map();
|
351
|
+
const now = Date.now();
|
326
352
|
for (const asset of Object.keys(compilation.assets)) {
|
327
353
|
if (/^[A-Za-z]:\\|^\/|^\\\\/.test(asset)) continue;
|
328
354
|
let normalizedAsset;
|
@@ -335,7 +361,12 @@ class CleanPlugin {
|
|
335
361
|
);
|
336
362
|
} while (newNormalizedAsset !== normalizedAsset);
|
337
363
|
if (normalizedAsset.startsWith("../")) continue;
|
338
|
-
|
364
|
+
const assetInfo = compilation.assetsInfo.get(asset);
|
365
|
+
if (assetInfo && assetInfo.hotModuleReplacement) {
|
366
|
+
currentAssets.set(normalizedAsset, now + _10sec);
|
367
|
+
} else {
|
368
|
+
currentAssets.set(normalizedAsset, 0);
|
369
|
+
}
|
339
370
|
}
|
340
371
|
|
341
372
|
const outputPath = compilation.getPath(compiler.outputPath, {});
|
@@ -346,19 +377,34 @@ class CleanPlugin {
|
|
346
377
|
return keepFn(path);
|
347
378
|
};
|
348
379
|
|
380
|
+
/**
|
381
|
+
* @param {Error=} err err
|
382
|
+
* @param {Set<string>=} diff diff
|
383
|
+
*/
|
349
384
|
const diffCallback = (err, diff) => {
|
350
385
|
if (err) {
|
351
386
|
oldAssets = undefined;
|
352
|
-
|
387
|
+
callback(err);
|
388
|
+
return;
|
353
389
|
}
|
354
|
-
applyDiff(
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
390
|
+
applyDiff(
|
391
|
+
fs,
|
392
|
+
outputPath,
|
393
|
+
dry,
|
394
|
+
logger,
|
395
|
+
diff,
|
396
|
+
isKept,
|
397
|
+
(err, keptAssets) => {
|
398
|
+
if (err) {
|
399
|
+
oldAssets = undefined;
|
400
|
+
} else {
|
401
|
+
if (oldAssets) mergeAssets(currentAssets, oldAssets);
|
402
|
+
oldAssets = currentAssets;
|
403
|
+
if (keptAssets) mergeAssets(oldAssets, keptAssets);
|
404
|
+
}
|
405
|
+
callback(err);
|
359
406
|
}
|
360
|
-
|
361
|
-
});
|
407
|
+
);
|
362
408
|
};
|
363
409
|
|
364
410
|
if (oldAssets) {
|
package/lib/Compilation.js
CHANGED
@@ -43,6 +43,7 @@ const Module = require("./Module");
|
|
43
43
|
const ModuleDependencyError = require("./ModuleDependencyError");
|
44
44
|
const ModuleDependencyWarning = require("./ModuleDependencyWarning");
|
45
45
|
const ModuleGraph = require("./ModuleGraph");
|
46
|
+
const ModuleHashingError = require("./ModuleHashingError");
|
46
47
|
const ModuleNotFoundError = require("./ModuleNotFoundError");
|
47
48
|
const ModuleProfile = require("./ModuleProfile");
|
48
49
|
const ModuleRestoreError = require("./ModuleRestoreError");
|
@@ -3883,6 +3884,7 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
|
|
3883
3884
|
let statModulesFromCache = 0;
|
3884
3885
|
const { chunkGraph, runtimeTemplate, moduleMemCaches2 } = this;
|
3885
3886
|
const { hashFunction, hashDigest, hashDigestLength } = this.outputOptions;
|
3887
|
+
const errors = [];
|
3886
3888
|
for (const module of this.modules) {
|
3887
3889
|
const memCache = moduleMemCaches2 && moduleMemCaches2.get(module);
|
3888
3890
|
for (const runtime of chunkGraph.getModuleRuntimes(module)) {
|
@@ -3907,13 +3909,20 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
|
|
3907
3909
|
hashFunction,
|
3908
3910
|
runtimeTemplate,
|
3909
3911
|
hashDigest,
|
3910
|
-
hashDigestLength
|
3912
|
+
hashDigestLength,
|
3913
|
+
errors
|
3911
3914
|
);
|
3912
3915
|
if (memCache) {
|
3913
3916
|
memCache.set(`moduleHash-${getRuntimeKey(runtime)}`, digest);
|
3914
3917
|
}
|
3915
3918
|
}
|
3916
3919
|
}
|
3920
|
+
if (errors.length > 0) {
|
3921
|
+
errors.sort(compareSelect(err => err.module, compareModulesByIdentifier));
|
3922
|
+
for (const error of errors) {
|
3923
|
+
this.errors.push(error);
|
3924
|
+
}
|
3925
|
+
}
|
3917
3926
|
this.logger.log(
|
3918
3927
|
`${statModulesHashed} modules hashed, ${statModulesFromCache} from cache (${
|
3919
3928
|
Math.round(
|
@@ -3930,17 +3939,22 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
|
|
3930
3939
|
hashFunction,
|
3931
3940
|
runtimeTemplate,
|
3932
3941
|
hashDigest,
|
3933
|
-
hashDigestLength
|
3942
|
+
hashDigestLength,
|
3943
|
+
errors
|
3934
3944
|
) {
|
3935
|
-
|
3936
|
-
|
3937
|
-
|
3938
|
-
|
3939
|
-
|
3940
|
-
|
3941
|
-
|
3942
|
-
|
3943
|
-
|
3945
|
+
let moduleHashDigest;
|
3946
|
+
try {
|
3947
|
+
const moduleHash = createHash(hashFunction);
|
3948
|
+
module.updateHash(moduleHash, {
|
3949
|
+
chunkGraph,
|
3950
|
+
runtime,
|
3951
|
+
runtimeTemplate
|
3952
|
+
});
|
3953
|
+
moduleHashDigest = /** @type {string} */ (moduleHash.digest(hashDigest));
|
3954
|
+
} catch (err) {
|
3955
|
+
errors.push(new ModuleHashingError(module, err));
|
3956
|
+
moduleHashDigest = "XXXXXX";
|
3957
|
+
}
|
3944
3958
|
chunkGraph.setModuleHashes(
|
3945
3959
|
module,
|
3946
3960
|
runtime,
|
@@ -4091,6 +4105,7 @@ This prevents using hashes of each other and should be avoided.`);
|
|
4091
4105
|
const codeGenerationJobs = [];
|
4092
4106
|
/** @type {Map<string, Map<Module, {module: Module, hash: string, runtime: RuntimeSpec, runtimes: RuntimeSpec[]}>>} */
|
4093
4107
|
const codeGenerationJobsMap = new Map();
|
4108
|
+
const errors = [];
|
4094
4109
|
|
4095
4110
|
const processChunk = chunk => {
|
4096
4111
|
// Last minute module hash generation for modules that depend on chunk hashes
|
@@ -4105,7 +4120,8 @@ This prevents using hashes of each other and should be avoided.`);
|
|
4105
4120
|
hashFunction,
|
4106
4121
|
runtimeTemplate,
|
4107
4122
|
hashDigest,
|
4108
|
-
hashDigestLength
|
4123
|
+
hashDigestLength,
|
4124
|
+
errors
|
4109
4125
|
);
|
4110
4126
|
let hashMap = codeGenerationJobsMap.get(hash);
|
4111
4127
|
if (hashMap) {
|
@@ -4129,9 +4145,9 @@ This prevents using hashes of each other and should be avoided.`);
|
|
4129
4145
|
}
|
4130
4146
|
}
|
4131
4147
|
this.logger.timeAggregate("hashing: hash runtime modules");
|
4132
|
-
this.logger.time("hashing: hash chunks");
|
4133
|
-
const chunkHash = createHash(hashFunction);
|
4134
4148
|
try {
|
4149
|
+
this.logger.time("hashing: hash chunks");
|
4150
|
+
const chunkHash = createHash(hashFunction);
|
4135
4151
|
if (outputOptions.hashSalt) {
|
4136
4152
|
chunkHash.update(outputOptions.hashSalt);
|
4137
4153
|
}
|
@@ -4162,6 +4178,12 @@ This prevents using hashes of each other and should be avoided.`);
|
|
4162
4178
|
};
|
4163
4179
|
otherChunks.forEach(processChunk);
|
4164
4180
|
for (const chunk of runtimeChunks) processChunk(chunk);
|
4181
|
+
if (errors.length > 0) {
|
4182
|
+
errors.sort(compareSelect(err => err.module, compareModulesByIdentifier));
|
4183
|
+
for (const error of errors) {
|
4184
|
+
this.errors.push(error);
|
4185
|
+
}
|
4186
|
+
}
|
4165
4187
|
|
4166
4188
|
this.logger.timeAggregateEnd("hashing: hash runtime modules");
|
4167
4189
|
this.logger.timeAggregateEnd("hashing: hash chunks");
|
@@ -4801,6 +4823,9 @@ This prevents using hashes of each other and should be avoided.`);
|
|
4801
4823
|
chunkGraph.connectChunkAndModule(chunk, module);
|
4802
4824
|
}
|
4803
4825
|
|
4826
|
+
/** @type {WebpackError[]} */
|
4827
|
+
const errors = [];
|
4828
|
+
|
4804
4829
|
// Hash modules
|
4805
4830
|
for (const module of modules) {
|
4806
4831
|
this._createModuleHash(
|
@@ -4810,15 +4835,14 @@ This prevents using hashes of each other and should be avoided.`);
|
|
4810
4835
|
hashFunction,
|
4811
4836
|
runtimeTemplate,
|
4812
4837
|
hashDigest,
|
4813
|
-
hashDigestLength
|
4838
|
+
hashDigestLength,
|
4839
|
+
errors
|
4814
4840
|
);
|
4815
4841
|
}
|
4816
4842
|
|
4817
4843
|
const codeGenerationResults = new CodeGenerationResults(
|
4818
4844
|
this.outputOptions.hashFunction
|
4819
4845
|
);
|
4820
|
-
/** @type {WebpackError[]} */
|
4821
|
-
const errors = [];
|
4822
4846
|
/**
|
4823
4847
|
* @param {Module} module the module
|
4824
4848
|
* @param {Callback} callback callback
|
package/lib/ContextModule.js
CHANGED
@@ -61,7 +61,7 @@ const makeSerializable = require("./util/makeSerializable");
|
|
61
61
|
|
62
62
|
/**
|
63
63
|
* @typedef {Object} ContextModuleOptionsExtras
|
64
|
-
* @property {string} resource
|
64
|
+
* @property {false|string|string[]} resource
|
65
65
|
* @property {string=} resourceQuery
|
66
66
|
* @property {string=} resourceFragment
|
67
67
|
* @property {TODO} resolveOptions
|
@@ -92,23 +92,36 @@ class ContextModule extends Module {
|
|
92
92
|
* @param {ContextModuleOptions} options options object
|
93
93
|
*/
|
94
94
|
constructor(resolveDependencies, options) {
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
95
|
+
if (!options || typeof options.resource === "string") {
|
96
|
+
const parsed = parseResource(
|
97
|
+
options ? /** @type {string} */ (options.resource) : ""
|
98
|
+
);
|
99
|
+
const resource = parsed.path;
|
100
|
+
const resourceQuery = (options && options.resourceQuery) || parsed.query;
|
101
|
+
const resourceFragment =
|
102
|
+
(options && options.resourceFragment) || parsed.fragment;
|
103
|
+
|
104
|
+
super("javascript/dynamic", resource);
|
105
|
+
/** @type {ContextModuleOptions} */
|
106
|
+
this.options = {
|
107
|
+
...options,
|
108
|
+
resource,
|
109
|
+
resourceQuery,
|
110
|
+
resourceFragment
|
111
|
+
};
|
112
|
+
} else {
|
113
|
+
super("javascript/dynamic");
|
114
|
+
/** @type {ContextModuleOptions} */
|
115
|
+
this.options = {
|
116
|
+
...options,
|
117
|
+
resource: options.resource,
|
118
|
+
resourceQuery: options.resourceQuery || "",
|
119
|
+
resourceFragment: options.resourceFragment || ""
|
120
|
+
};
|
121
|
+
}
|
102
122
|
|
103
123
|
// Info from Factory
|
104
124
|
this.resolveDependencies = resolveDependencies;
|
105
|
-
/** @type {ContextModuleOptions} */
|
106
|
-
this.options = {
|
107
|
-
...options,
|
108
|
-
resource,
|
109
|
-
resourceQuery,
|
110
|
-
resourceFragment
|
111
|
-
};
|
112
125
|
if (options && options.resolveOptions !== undefined) {
|
113
126
|
this.resolveOptions = options.resolveOptions;
|
114
127
|
}
|
@@ -155,7 +168,12 @@ class ContextModule extends Module {
|
|
155
168
|
}
|
156
169
|
|
157
170
|
_createIdentifier() {
|
158
|
-
let identifier =
|
171
|
+
let identifier =
|
172
|
+
this.context ||
|
173
|
+
(typeof this.options.resource === "string" ||
|
174
|
+
this.options.resource === false
|
175
|
+
? `${this.options.resource}`
|
176
|
+
: this.options.resource.join("|"));
|
159
177
|
if (this.options.resourceQuery) {
|
160
178
|
identifier += `|${this.options.resourceQuery}`;
|
161
179
|
}
|
@@ -220,7 +238,19 @@ class ContextModule extends Module {
|
|
220
238
|
* @returns {string} a user readable identifier of the module
|
221
239
|
*/
|
222
240
|
readableIdentifier(requestShortener) {
|
223
|
-
let identifier
|
241
|
+
let identifier;
|
242
|
+
if (this.context) {
|
243
|
+
identifier = requestShortener.shorten(this.context) + "/";
|
244
|
+
} else if (
|
245
|
+
typeof this.options.resource === "string" ||
|
246
|
+
this.options.resource === false
|
247
|
+
) {
|
248
|
+
identifier = requestShortener.shorten(`${this.options.resource}`) + "/";
|
249
|
+
} else {
|
250
|
+
identifier = this.options.resource
|
251
|
+
.map(r => requestShortener.shorten(r) + "/")
|
252
|
+
.join(" ");
|
253
|
+
}
|
224
254
|
if (this.options.resourceQuery) {
|
225
255
|
identifier += ` ${this.options.resourceQuery}`;
|
226
256
|
}
|
@@ -270,11 +300,30 @@ class ContextModule extends Module {
|
|
270
300
|
* @returns {string | null} an identifier for library inclusion
|
271
301
|
*/
|
272
302
|
libIdent(options) {
|
273
|
-
let identifier
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
303
|
+
let identifier;
|
304
|
+
|
305
|
+
if (this.context) {
|
306
|
+
identifier = contextify(
|
307
|
+
options.context,
|
308
|
+
this.context,
|
309
|
+
options.associatedObjectForCache
|
310
|
+
);
|
311
|
+
} else if (typeof this.options.resource === "string") {
|
312
|
+
identifier = contextify(
|
313
|
+
options.context,
|
314
|
+
this.options.resource,
|
315
|
+
options.associatedObjectForCache
|
316
|
+
);
|
317
|
+
} else if (this.options.resource === false) {
|
318
|
+
identifier = "false";
|
319
|
+
} else {
|
320
|
+
identifier = this.options.resource
|
321
|
+
.map(res =>
|
322
|
+
contextify(options.context, res, options.associatedObjectForCache)
|
323
|
+
)
|
324
|
+
.join(" ");
|
325
|
+
}
|
326
|
+
|
278
327
|
if (this.layer) identifier = `(${this.layer})/${identifier}`;
|
279
328
|
if (this.options.mode) {
|
280
329
|
identifier += ` ${this.options.mode}`;
|
@@ -323,8 +372,9 @@ class ContextModule extends Module {
|
|
323
372
|
// build if enforced
|
324
373
|
if (this._forceBuild) return callback(null, true);
|
325
374
|
|
326
|
-
// always build when we have no snapshot
|
327
|
-
if (!this.buildInfo.snapshot)
|
375
|
+
// always build when we have no snapshot and context
|
376
|
+
if (!this.buildInfo.snapshot)
|
377
|
+
return callback(null, Boolean(this.context || this.options.resource));
|
328
378
|
|
329
379
|
fileSystemInfo.checkSnapshotValid(this.buildInfo.snapshot, (err, valid) => {
|
330
380
|
callback(err, !valid);
|
@@ -439,10 +489,16 @@ class ContextModule extends Module {
|
|
439
489
|
);
|
440
490
|
return;
|
441
491
|
}
|
492
|
+
if (!this.context && !this.options.resource) return callback();
|
493
|
+
|
442
494
|
compilation.fileSystemInfo.createSnapshot(
|
443
495
|
startTime,
|
444
496
|
null,
|
445
|
-
|
497
|
+
this.context
|
498
|
+
? [this.context]
|
499
|
+
: typeof this.options.resource === "string"
|
500
|
+
? [this.options.resource]
|
501
|
+
: /** @type {string[]} */ (this.options.resource),
|
446
502
|
null,
|
447
503
|
SNAPSHOT_OPTIONS,
|
448
504
|
(err, snapshot) => {
|
@@ -466,7 +522,15 @@ class ContextModule extends Module {
|
|
466
522
|
missingDependencies,
|
467
523
|
buildDependencies
|
468
524
|
) {
|
469
|
-
|
525
|
+
if (this.context) {
|
526
|
+
contextDependencies.add(this.context);
|
527
|
+
} else if (typeof this.options.resource === "string") {
|
528
|
+
contextDependencies.add(this.options.resource);
|
529
|
+
} else if (this.options.resource === false) {
|
530
|
+
return;
|
531
|
+
} else {
|
532
|
+
for (const res of this.options.resource) contextDependencies.add(res);
|
533
|
+
}
|
470
534
|
}
|
471
535
|
|
472
536
|
/**
|
@@ -167,6 +167,9 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
|
|
167
167
|
asyncLib.parallel(
|
168
168
|
[
|
169
169
|
callback => {
|
170
|
+
const results = [];
|
171
|
+
const yield_ = obj => results.push(obj);
|
172
|
+
|
170
173
|
contextResolver.resolve(
|
171
174
|
{},
|
172
175
|
context,
|
@@ -174,11 +177,12 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
|
|
174
177
|
{
|
175
178
|
fileDependencies,
|
176
179
|
missingDependencies,
|
177
|
-
contextDependencies
|
180
|
+
contextDependencies,
|
181
|
+
yield: yield_
|
178
182
|
},
|
179
|
-
|
183
|
+
err => {
|
180
184
|
if (err) return callback(err);
|
181
|
-
callback(null,
|
185
|
+
callback(null, results);
|
182
186
|
}
|
183
187
|
);
|
184
188
|
},
|
@@ -213,15 +217,25 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
|
|
213
217
|
contextDependencies
|
214
218
|
});
|
215
219
|
}
|
216
|
-
|
220
|
+
let [contextResult, loaderResult] = result;
|
221
|
+
if (contextResult.length > 1) {
|
222
|
+
const first = contextResult[0];
|
223
|
+
contextResult = contextResult.filter(r => r.path);
|
224
|
+
if (contextResult.length === 0) contextResult.push(first);
|
225
|
+
}
|
217
226
|
this.hooks.afterResolve.callAsync(
|
218
227
|
{
|
219
228
|
addon:
|
220
229
|
loadersPrefix +
|
221
|
-
|
222
|
-
(
|
223
|
-
resource:
|
230
|
+
loaderResult.join("!") +
|
231
|
+
(loaderResult.length > 0 ? "!" : ""),
|
232
|
+
resource:
|
233
|
+
contextResult.length > 1
|
234
|
+
? contextResult.map(r => r.path)
|
235
|
+
: contextResult[0].path,
|
224
236
|
resolveDependencies: this.resolveDependencies.bind(this),
|
237
|
+
resourceQuery: contextResult[0].query,
|
238
|
+
resourceFragment: contextResult[0].fragment,
|
225
239
|
...beforeResolveResult
|
226
240
|
},
|
227
241
|
(err, result) => {
|
@@ -278,26 +292,28 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
|
|
278
292
|
} = options;
|
279
293
|
if (!regExp || !resource) return callback(null, []);
|
280
294
|
|
281
|
-
|
295
|
+
let severalContexts = false;
|
296
|
+
const addDirectoryChecked = (ctx, directory, visited, callback) => {
|
282
297
|
fs.realpath(directory, (err, realPath) => {
|
283
298
|
if (err) return callback(err);
|
284
299
|
if (visited.has(realPath)) return callback(null, []);
|
285
300
|
let recursionStack;
|
286
301
|
addDirectory(
|
302
|
+
ctx,
|
287
303
|
directory,
|
288
|
-
(dir, callback) => {
|
304
|
+
(_, dir, callback) => {
|
289
305
|
if (recursionStack === undefined) {
|
290
306
|
recursionStack = new Set(visited);
|
291
307
|
recursionStack.add(realPath);
|
292
308
|
}
|
293
|
-
addDirectoryChecked(dir, recursionStack, callback);
|
309
|
+
addDirectoryChecked(ctx, dir, recursionStack, callback);
|
294
310
|
},
|
295
311
|
callback
|
296
312
|
);
|
297
313
|
});
|
298
314
|
};
|
299
315
|
|
300
|
-
const addDirectory = (directory, addSubDirectory, callback) => {
|
316
|
+
const addDirectory = (ctx, directory, addSubDirectory, callback) => {
|
301
317
|
fs.readdir(directory, (err, files) => {
|
302
318
|
if (err) return callback(err);
|
303
319
|
const processedFiles = cmf.hooks.contextModuleFiles.call(
|
@@ -324,16 +340,15 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
|
|
324
340
|
|
325
341
|
if (stat.isDirectory()) {
|
326
342
|
if (!recursive) return callback();
|
327
|
-
addSubDirectory(subResource, callback);
|
343
|
+
addSubDirectory(ctx, subResource, callback);
|
328
344
|
} else if (
|
329
345
|
stat.isFile() &&
|
330
346
|
(!include || subResource.match(include))
|
331
347
|
) {
|
332
348
|
const obj = {
|
333
|
-
context:
|
349
|
+
context: ctx,
|
334
350
|
request:
|
335
|
-
"." +
|
336
|
-
subResource.substr(resource.length).replace(/\\/g, "/")
|
351
|
+
"." + subResource.substr(ctx.length).replace(/\\/g, "/")
|
337
352
|
};
|
338
353
|
|
339
354
|
this.hooks.alternativeRequests.callAsync(
|
@@ -344,8 +359,11 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
|
|
344
359
|
alternatives = alternatives
|
345
360
|
.filter(obj => regExp.test(obj.request))
|
346
361
|
.map(obj => {
|
362
|
+
const request = severalContexts
|
363
|
+
? join(fs, obj.context, obj.request)
|
364
|
+
: obj.request;
|
347
365
|
const dep = new ContextElementDependency(
|
348
|
-
|
366
|
+
request + resourceQuery + resourceFragment,
|
349
367
|
obj.request,
|
350
368
|
typePrefix,
|
351
369
|
category,
|
@@ -382,12 +400,38 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
|
|
382
400
|
});
|
383
401
|
};
|
384
402
|
|
385
|
-
|
386
|
-
|
403
|
+
const addSubDirectory = (ctx, dir, callback) =>
|
404
|
+
addDirectory(ctx, dir, addSubDirectory, callback);
|
405
|
+
|
406
|
+
const visitResource = (resource, callback) => {
|
407
|
+
if (typeof fs.realpath === "function") {
|
408
|
+
addDirectoryChecked(resource, resource, new Set(), callback);
|
409
|
+
} else {
|
410
|
+
addDirectory(resource, resource, addSubDirectory, callback);
|
411
|
+
}
|
412
|
+
};
|
413
|
+
|
414
|
+
if (typeof resource === "string") {
|
415
|
+
visitResource(resource, callback);
|
387
416
|
} else {
|
388
|
-
|
389
|
-
|
390
|
-
|
417
|
+
severalContexts = true;
|
418
|
+
asyncLib.map(resource, visitResource, (err, result) => {
|
419
|
+
if (err) return callback(err);
|
420
|
+
|
421
|
+
// result dependencies should have unique userRequest
|
422
|
+
// ordered by resolve result
|
423
|
+
const temp = new Set();
|
424
|
+
const res = [];
|
425
|
+
for (let i = 0; i < result.length; i++) {
|
426
|
+
const inner = result[i];
|
427
|
+
for (const el of inner) {
|
428
|
+
if (temp.has(el.userRequest)) continue;
|
429
|
+
res.push(el);
|
430
|
+
temp.add(el.userRequest);
|
431
|
+
}
|
432
|
+
}
|
433
|
+
callback(null, res);
|
434
|
+
});
|
391
435
|
}
|
392
436
|
}
|
393
437
|
};
|
package/lib/EntryOptionPlugin.js
CHANGED