@depup/webpack 5.109.0-depup.0 → 5.109.2-depup.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.
- package/README.md +4 -4
- package/bin/webpack.js +12 -0
- package/changes.json +4 -4
- package/lib/ChunkGraph.js +17 -15
- package/lib/CleanPlugin.js +11 -9
- package/lib/CompatibilityPlugin.js +31 -0
- package/lib/Compilation.js +21 -5
- package/lib/Compiler.js +16 -4
- package/lib/DefinePlugin.js +47 -20
- package/lib/ExportsInfo.js +22 -5
- package/lib/ExternalModule.js +10 -7
- package/lib/FileSystemInfo.js +126 -26
- package/lib/FlagDependencyUsagePlugin.js +33 -12
- package/lib/InitFragment.js +20 -32
- package/lib/ModuleFilenameHelpers.js +13 -2
- package/lib/NormalModule.js +80 -71
- package/lib/NormalModuleFactory.js +8 -2
- package/lib/RuntimePlugin.js +40 -113
- package/lib/Template.js +23 -3
- package/lib/cache/PackFileCacheStrategy.js +259 -5
- package/lib/config/defaults.js +21 -2
- package/lib/container/HoistContainerReferencesPlugin.js +47 -55
- package/lib/container/ModuleFederationPlugin.js +15 -9
- package/lib/css/CssGenerator.js +8 -2
- package/lib/css/CssLoadingRuntimeModule.js +25 -12
- package/lib/css/CssModulesPlugin.js +29 -18
- package/lib/css/CssParser.js +135 -50
- package/lib/css/syntax.js +862 -765
- package/lib/dependencies/CommonJsExportRequireDependency.js +19 -0
- package/lib/dependencies/CommonJsFullRequireDependency.js +33 -4
- package/lib/dependencies/CommonJsImportsParserPlugin.js +2 -0
- package/lib/dependencies/HarmonyEvaluatedImportSpecifierDependency.js +2 -1
- package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +17 -9
- package/lib/dependencies/HarmonyImportDependency.js +1 -1
- package/lib/dependencies/HarmonyImportGuard.js +2 -1
- package/lib/dependencies/HarmonyImportSpecifierDependency.js +10 -7
- package/lib/esm/ModuleChunkLoadingRuntimeModule.js +15 -9
- package/lib/hmr/lazyCompilationBackend.js +19 -4
- package/lib/html/HtmlGenerator.js +23 -3
- package/lib/html/HtmlModulesPlugin.js +30 -12
- package/lib/html/syntax.js +2485 -2399
- package/lib/ids/IdHelpers.js +24 -10
- package/lib/javascript/JavascriptModulesPlugin.js +83 -49
- package/lib/javascript/JavascriptParser.js +49 -13
- package/lib/javascript/syntax.js +700 -43
- package/lib/node/ReadFileCompileAsyncWasmPlugin.js +10 -2
- package/lib/node/ReadFileCompileWasmPlugin.js +10 -2
- package/lib/optimize/AggressiveMergingPlugin.js +19 -15
- package/lib/optimize/ConcatenatedModule.js +19 -15
- package/lib/optimize/ModuleConcatenationPlugin.js +73 -24
- package/lib/optimize/RealContentHashPlugin.js +10 -7
- package/lib/optimize/SplitChunksPlugin.js +146 -44
- package/lib/prefetch/ResourceHintPlugin.js +96 -72
- package/lib/serialization/BinaryMiddleware.js +270 -938
- package/lib/serialization/FileMiddleware.js +299 -60
- package/lib/stats/DefaultStatsFactoryPlugin.js +204 -198
- package/lib/stats/DefaultStatsPrinterPlugin.js +24 -166
- package/lib/stats/StatsFactory.js +31 -9
- package/lib/util/identifier.js +21 -1
- package/package.json +10 -10
- package/schemas/WebpackOptions.json +110 -55
- package/types.d.ts +832 -247
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
const FileSystemInfo = require("../FileSystemInfo");
|
|
9
9
|
const ProgressPlugin = require("../ProgressPlugin");
|
|
10
|
+
const { getReferencedFilenames } = require("../serialization/FileMiddleware");
|
|
10
11
|
const SerializerMiddleware = require("../serialization/SerializerMiddleware");
|
|
11
12
|
const LazySet = require("../util/LazySet");
|
|
12
13
|
const formatSize = require("../util/formatSize");
|
|
@@ -34,6 +35,17 @@ const {
|
|
|
34
35
|
/** @typedef {Set<string>} Items */
|
|
35
36
|
/** @typedef {Set<string>} BuildDependencies */
|
|
36
37
|
/** @typedef {Map<string, PackItemInfo>} ItemInfo */
|
|
38
|
+
/** @typedef {{ firstSeen: number, size: number }} UnreferencedFile */
|
|
39
|
+
/** @typedef {Map<string, UnreferencedFile>} UnreferencedFiles */
|
|
40
|
+
|
|
41
|
+
// Unreferenced files are kept for this long to not race concurrent builds sharing the cache directory.
|
|
42
|
+
const CLEANUP_GRACE_PERIOD = 30 * 60 * 1000;
|
|
43
|
+
// Records when each unreferenced file was first seen. Aging by recorded time keeps
|
|
44
|
+
// orphans expiring across caches restored with refreshed modification times.
|
|
45
|
+
const UNREFERENCED_FILE = "unreferenced.json";
|
|
46
|
+
// A file written this recently may belong to a concurrent build that reused the name,
|
|
47
|
+
// in which case the recorded time describes the previous file and must not be trusted.
|
|
48
|
+
const CLEANUP_RECENT_WRITE_PERIOD = 60 * 1000;
|
|
37
49
|
|
|
38
50
|
class PackContainer {
|
|
39
51
|
/**
|
|
@@ -569,6 +581,41 @@ class Pack {
|
|
|
569
581
|
}
|
|
570
582
|
}
|
|
571
583
|
|
|
584
|
+
/**
|
|
585
|
+
* Drops every content whose items all expired. Unlike a partial collection this
|
|
586
|
+
* never unpacks, so it is not limited to a single content per store and lets a
|
|
587
|
+
* long unused cache shrink in one go instead of one pack per build.
|
|
588
|
+
*/
|
|
589
|
+
_gcExpiredContent() {
|
|
590
|
+
const now = Date.now();
|
|
591
|
+
let packCount = 0;
|
|
592
|
+
let itemCount = 0;
|
|
593
|
+
for (let loc = 0; loc < this.content.length; loc++) {
|
|
594
|
+
const content = this.content[loc];
|
|
595
|
+
if (!content) continue;
|
|
596
|
+
let expired = true;
|
|
597
|
+
for (const identifier of content.items) {
|
|
598
|
+
const info = this.itemInfo.get(identifier);
|
|
599
|
+
if (info !== undefined && now - info.lastAccess <= this.maxAge) {
|
|
600
|
+
expired = false;
|
|
601
|
+
break;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
if (!expired) continue;
|
|
605
|
+
for (const identifier of content.items) this.itemInfo.delete(identifier);
|
|
606
|
+
this.content[loc] = undefined;
|
|
607
|
+
packCount++;
|
|
608
|
+
itemCount += content.items.size;
|
|
609
|
+
}
|
|
610
|
+
if (packCount > 0) {
|
|
611
|
+
this.logger.log(
|
|
612
|
+
"Garbage Collected %d completely expired packs with %d items",
|
|
613
|
+
packCount,
|
|
614
|
+
itemCount
|
|
615
|
+
);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
572
619
|
/**
|
|
573
620
|
* Find the content with the oldest item and run GC on that.
|
|
574
621
|
* Only runs for one content to avoid large invalidation.
|
|
@@ -581,11 +628,10 @@ class Pack {
|
|
|
581
628
|
oldest = info;
|
|
582
629
|
}
|
|
583
630
|
}
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
const loc = /** @type {PackItemInfo} */ (oldest).location;
|
|
631
|
+
// collecting expired content may have left no items at all
|
|
632
|
+
if (oldest === undefined) return;
|
|
633
|
+
if (Date.now() - oldest.lastAccess > this.maxAge) {
|
|
634
|
+
const loc = oldest.location;
|
|
589
635
|
if (loc < 0) return;
|
|
590
636
|
const content = /** @type {PackContent} */ (this.content[loc]);
|
|
591
637
|
const items = new Set(content.items);
|
|
@@ -621,6 +667,7 @@ class Pack {
|
|
|
621
667
|
this._persistFreshContent();
|
|
622
668
|
this._optimizeSmallContent();
|
|
623
669
|
this._optimizeUnusedContent();
|
|
670
|
+
this._gcExpiredContent();
|
|
624
671
|
this._gcOldestContent();
|
|
625
672
|
for (const identifier of this.itemInfo.keys()) {
|
|
626
673
|
write(identifier);
|
|
@@ -1166,6 +1213,8 @@ class PackFileCacheStrategy {
|
|
|
1166
1213
|
});
|
|
1167
1214
|
/** @type {Compiler} */
|
|
1168
1215
|
this.compiler = compiler;
|
|
1216
|
+
/** @type {IntermediateFileSystem} */
|
|
1217
|
+
this.fs = fs;
|
|
1169
1218
|
/** @type {string} */
|
|
1170
1219
|
this.context = context;
|
|
1171
1220
|
/** @type {string} */
|
|
@@ -1182,6 +1231,10 @@ class PackFileCacheStrategy {
|
|
|
1182
1231
|
this.readonly = readonly;
|
|
1183
1232
|
/** @type {boolean | undefined} */
|
|
1184
1233
|
this.allowCollectingMemory = allowCollectingMemory;
|
|
1234
|
+
// referenced names per on-disk file, versioned by mtime since concurrent
|
|
1235
|
+
// processes may rewrite packs in place under the same name
|
|
1236
|
+
/** @type {Map<string, { mtimeMs: number, referenced: string[] }>} */
|
|
1237
|
+
this._referencedFilesCache = new Map();
|
|
1185
1238
|
/** @type {false | "gzip" | "brotli" | "zstd" | undefined} */
|
|
1186
1239
|
this.compression = compression;
|
|
1187
1240
|
// eslint-disable-next-line n/no-unsupported-features/node-builtins
|
|
@@ -1588,10 +1641,17 @@ class PackFileCacheStrategy {
|
|
|
1588
1641
|
/** @type {Snapshot} */
|
|
1589
1642
|
(this.resolveBuildDependenciesSnapshot)
|
|
1590
1643
|
);
|
|
1644
|
+
const cleanup = this.fs.unlink !== undefined;
|
|
1645
|
+
/** @type {Set<string> | undefined} */
|
|
1646
|
+
const writtenFiles = cleanup ? new Set() : undefined;
|
|
1647
|
+
/** @type {Set<string> | undefined} */
|
|
1648
|
+
const retainedFiles = cleanup ? new Set() : undefined;
|
|
1591
1649
|
return this.fileSerializer
|
|
1592
1650
|
.serialize(content, {
|
|
1593
1651
|
filename: `${this.cacheLocation}/index${this._extension}`,
|
|
1594
1652
|
extension: `${this._extension}`,
|
|
1653
|
+
writtenFiles,
|
|
1654
|
+
retainedFiles,
|
|
1595
1655
|
logger: this.logger,
|
|
1596
1656
|
profile: this.profile
|
|
1597
1657
|
})
|
|
@@ -1608,9 +1668,17 @@ class PackFileCacheStrategy {
|
|
|
1608
1668
|
stats.count,
|
|
1609
1669
|
Math.round(stats.size / 1024 / 1024)
|
|
1610
1670
|
);
|
|
1671
|
+
if (writtenFiles !== undefined) {
|
|
1672
|
+
return this._cleanupUnusedFiles(
|
|
1673
|
+
writtenFiles,
|
|
1674
|
+
/** @type {Set<string>} */ (retainedFiles)
|
|
1675
|
+
);
|
|
1676
|
+
}
|
|
1611
1677
|
})
|
|
1612
1678
|
.catch((err) => {
|
|
1613
1679
|
this.logger.timeEnd("store pack");
|
|
1680
|
+
// files may be in an unknown state after a failed store
|
|
1681
|
+
this._referencedFilesCache.clear();
|
|
1614
1682
|
this.logger.warn(`Caching failed for pack: ${err}`);
|
|
1615
1683
|
this.logger.debug(err.stack);
|
|
1616
1684
|
});
|
|
@@ -1622,6 +1690,192 @@ class PackFileCacheStrategy {
|
|
|
1622
1690
|
}));
|
|
1623
1691
|
}
|
|
1624
1692
|
|
|
1693
|
+
/**
|
|
1694
|
+
* Reads when the currently unreferenced files were first seen. A missing or
|
|
1695
|
+
* unreadable file just restarts the grace period for every orphan.
|
|
1696
|
+
* @returns {Promise<UnreferencedFiles>} first seen time and size per file name
|
|
1697
|
+
*/
|
|
1698
|
+
_readUnreferencedFiles() {
|
|
1699
|
+
return new Promise((resolve) => {
|
|
1700
|
+
this.fs.readFile(
|
|
1701
|
+
`${this.cacheLocation}/${UNREFERENCED_FILE}`,
|
|
1702
|
+
(err, content) => {
|
|
1703
|
+
/** @type {UnreferencedFiles} */
|
|
1704
|
+
const result = new Map();
|
|
1705
|
+
if (err) return resolve(result);
|
|
1706
|
+
try {
|
|
1707
|
+
const data = JSON.parse(
|
|
1708
|
+
/** @type {Buffer} */ (content).toString("utf8")
|
|
1709
|
+
);
|
|
1710
|
+
for (const [file, entry] of Object.entries(data)) {
|
|
1711
|
+
const { firstSeen, size } = /** @type {UnreferencedFile} */ (
|
|
1712
|
+
entry
|
|
1713
|
+
);
|
|
1714
|
+
if (typeof firstSeen === "number" && typeof size === "number") {
|
|
1715
|
+
result.set(file, { firstSeen, size });
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
} catch (_err) {
|
|
1719
|
+
result.clear();
|
|
1720
|
+
}
|
|
1721
|
+
resolve(result);
|
|
1722
|
+
}
|
|
1723
|
+
);
|
|
1724
|
+
});
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
/**
|
|
1728
|
+
* Persists when the still unreferenced files were first seen. Failing to write
|
|
1729
|
+
* only costs the orphans another grace period, so errors are ignored.
|
|
1730
|
+
* @param {UnreferencedFiles} unreferenced first seen time and size per file name
|
|
1731
|
+
* @param {boolean} hadEntries whether a previous state exists that must be replaced
|
|
1732
|
+
* @returns {Promise<void>} promise
|
|
1733
|
+
*/
|
|
1734
|
+
_writeUnreferencedFiles(unreferenced, hadEntries) {
|
|
1735
|
+
if (unreferenced.size === 0 && !hadEntries) return Promise.resolve();
|
|
1736
|
+
/** @type {Record<string, UnreferencedFile>} */
|
|
1737
|
+
const data = {};
|
|
1738
|
+
for (const [file, entry] of unreferenced) data[file] = entry;
|
|
1739
|
+
return new Promise((resolve) => {
|
|
1740
|
+
this.fs.writeFile(
|
|
1741
|
+
`${this.cacheLocation}/${UNREFERENCED_FILE}`,
|
|
1742
|
+
JSON.stringify(data),
|
|
1743
|
+
() => resolve()
|
|
1744
|
+
);
|
|
1745
|
+
});
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
/**
|
|
1749
|
+
* Deletes files from the cache directory that are no longer referenced by the
|
|
1750
|
+
* stored pack. Retained files are walked on disk since nested lazy segments
|
|
1751
|
+
* reference files not visible during serialization. Errors only log a warning.
|
|
1752
|
+
* @param {Set<string>} writtenNames names (without extension) written by this store
|
|
1753
|
+
* @param {Set<string>} retainedNames names (without extension) referenced but not rewritten
|
|
1754
|
+
* @returns {Promise<void>} promise
|
|
1755
|
+
*/
|
|
1756
|
+
async _cleanupUnusedFiles(writtenNames, retainedNames) {
|
|
1757
|
+
this.logger.time("cleanup unused cache files");
|
|
1758
|
+
const fs = this.fs;
|
|
1759
|
+
const extension = this._extension;
|
|
1760
|
+
const cacheLocation = this.cacheLocation;
|
|
1761
|
+
const referencedFilesCache = this._referencedFilesCache;
|
|
1762
|
+
try {
|
|
1763
|
+
// rewritten files may reference different names now
|
|
1764
|
+
for (const name of writtenNames) referencedFilesCache.delete(name);
|
|
1765
|
+
/** @type {Set<string>} */
|
|
1766
|
+
const liveFiles = new Set([`index${extension}`, UNREFERENCED_FILE]);
|
|
1767
|
+
for (const name of writtenNames) liveFiles.add(`${name}${extension}`);
|
|
1768
|
+
/** @type {string[]} */
|
|
1769
|
+
const queue = [];
|
|
1770
|
+
/**
|
|
1771
|
+
* Marks a file live and queues it for walking its references.
|
|
1772
|
+
* @param {string} name file name without extension
|
|
1773
|
+
*/
|
|
1774
|
+
const enqueue = (name) => {
|
|
1775
|
+
const file = `${name}${extension}`;
|
|
1776
|
+
if (liveFiles.has(file)) return;
|
|
1777
|
+
liveFiles.add(file);
|
|
1778
|
+
queue.push(name);
|
|
1779
|
+
};
|
|
1780
|
+
for (const name of retainedNames) enqueue(name);
|
|
1781
|
+
while (queue.length > 0) {
|
|
1782
|
+
const name = /** @type {string} */ (queue.pop());
|
|
1783
|
+
const file = `${cacheLocation}/${name}${extension}`;
|
|
1784
|
+
// an unchanged mtime proves the memo entry still matches the disk
|
|
1785
|
+
const mtimeMs = await new Promise((resolve, reject) => {
|
|
1786
|
+
fs.stat(file, (err, stats) => {
|
|
1787
|
+
if (err) return reject(err);
|
|
1788
|
+
resolve(
|
|
1789
|
+
/** @type {number} */ (
|
|
1790
|
+
/** @type {import("../util/fs").IStats} */ (stats).mtimeMs
|
|
1791
|
+
)
|
|
1792
|
+
);
|
|
1793
|
+
});
|
|
1794
|
+
});
|
|
1795
|
+
const entry = referencedFilesCache.get(name);
|
|
1796
|
+
let referenced;
|
|
1797
|
+
if (entry !== undefined && entry.mtimeMs === mtimeMs) {
|
|
1798
|
+
referenced = entry.referenced;
|
|
1799
|
+
} else {
|
|
1800
|
+
referenced = await getReferencedFilenames(fs, file);
|
|
1801
|
+
referencedFilesCache.set(name, { mtimeMs, referenced });
|
|
1802
|
+
}
|
|
1803
|
+
for (const referencedName of referenced) enqueue(referencedName);
|
|
1804
|
+
}
|
|
1805
|
+
const files = await new Promise((resolve, reject) => {
|
|
1806
|
+
fs.readdir(cacheLocation, (err, files) => {
|
|
1807
|
+
if (err) return reject(err);
|
|
1808
|
+
resolve(/** @type {string[]} */ (files));
|
|
1809
|
+
});
|
|
1810
|
+
});
|
|
1811
|
+
const seenFiles = await this._readUnreferencedFiles();
|
|
1812
|
+
const now = Date.now();
|
|
1813
|
+
// every store rewrites the index backup, so a recorded time would age a file
|
|
1814
|
+
// that is in fact new; renaming carries the previous index mtime onto it
|
|
1815
|
+
const indexBackup = `index${extension}.old`;
|
|
1816
|
+
/** @type {UnreferencedFiles} */
|
|
1817
|
+
const stillUnreferenced = new Map();
|
|
1818
|
+
let deletedCount = 0;
|
|
1819
|
+
for (const file of files) {
|
|
1820
|
+
if (typeof file !== "string" || liveFiles.has(file)) continue;
|
|
1821
|
+
const path = `${cacheLocation}/${file}`;
|
|
1822
|
+
const stats = await new Promise((resolve) => {
|
|
1823
|
+
fs.stat(path, (err, stats) => {
|
|
1824
|
+
resolve(
|
|
1825
|
+
err
|
|
1826
|
+
? undefined
|
|
1827
|
+
: /** @type {import("../util/fs").IStats} */ (stats)
|
|
1828
|
+
);
|
|
1829
|
+
});
|
|
1830
|
+
});
|
|
1831
|
+
if (stats === undefined || !stats.isFile()) continue;
|
|
1832
|
+
const size = /** @type {number} */ (stats.size);
|
|
1833
|
+
const seen = seenFiles.get(file);
|
|
1834
|
+
// a differing size means the name was rewritten, so it is a new orphan
|
|
1835
|
+
const firstSeen =
|
|
1836
|
+
seen !== undefined && seen.size === size ? seen.firstSeen : now;
|
|
1837
|
+
const expireTime = now - CLEANUP_GRACE_PERIOD;
|
|
1838
|
+
const mtimeMs = /** @type {number} */ (stats.mtimeMs);
|
|
1839
|
+
// either signal is enough: modification times are lost when a cache is
|
|
1840
|
+
// restored, and recorded times are lost when the cache directory is new
|
|
1841
|
+
const expired =
|
|
1842
|
+
mtimeMs <= expireTime ||
|
|
1843
|
+
(file !== indexBackup &&
|
|
1844
|
+
firstSeen <= expireTime &&
|
|
1845
|
+
mtimeMs <= now - CLEANUP_RECENT_WRITE_PERIOD);
|
|
1846
|
+
if (expired) {
|
|
1847
|
+
const deleted = await new Promise((resolve) => {
|
|
1848
|
+
/** @type {NonNullable<IntermediateFileSystem["unlink"]>} */
|
|
1849
|
+
(fs.unlink)(path, (err) => resolve(!err));
|
|
1850
|
+
});
|
|
1851
|
+
if (deleted) {
|
|
1852
|
+
deletedCount++;
|
|
1853
|
+
continue;
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
if (file !== indexBackup) {
|
|
1857
|
+
stillUnreferenced.set(file, { firstSeen, size });
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
await this._writeUnreferencedFiles(stillUnreferenced, seenFiles.size > 0);
|
|
1861
|
+
// drop entries of files that are no longer alive
|
|
1862
|
+
for (const name of referencedFilesCache.keys()) {
|
|
1863
|
+
if (!liveFiles.has(`${name}${extension}`)) {
|
|
1864
|
+
referencedFilesCache.delete(name);
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
if (deletedCount > 0) {
|
|
1868
|
+
this.logger.log("Deleted %d unused cache files", deletedCount);
|
|
1869
|
+
}
|
|
1870
|
+
} catch (err) {
|
|
1871
|
+
this.logger.warn(
|
|
1872
|
+
`Cleanup of unused cache files failed: ${/** @type {Error} */ (err)}`
|
|
1873
|
+
);
|
|
1874
|
+
this.logger.debug(/** @type {Error} */ (err).stack);
|
|
1875
|
+
}
|
|
1876
|
+
this.logger.timeEnd("cleanup unused cache files");
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1625
1879
|
clear() {
|
|
1626
1880
|
this.fileSystemInfo.clear();
|
|
1627
1881
|
this.buildDependencies.clear();
|
package/lib/config/defaults.js
CHANGED
|
@@ -511,7 +511,13 @@ const applyWebpackOptionsDefaults = (options, compilerIndex) => {
|
|
|
511
511
|
/** @type {NonNullable<WebpackOptionsNormalized["loader"]>} */ (
|
|
512
512
|
options.loader
|
|
513
513
|
),
|
|
514
|
-
{
|
|
514
|
+
{
|
|
515
|
+
targetProperties,
|
|
516
|
+
environment: options.output.environment,
|
|
517
|
+
outputModule:
|
|
518
|
+
/** @type {NonNullable<WebpackOptionsNormalized["output"]["module"]>} */
|
|
519
|
+
(options.output.module)
|
|
520
|
+
}
|
|
515
521
|
);
|
|
516
522
|
|
|
517
523
|
F(options, "externalsType", () => {
|
|
@@ -2251,9 +2257,13 @@ const applyExternalsPresetsDefaults = (
|
|
|
2251
2257
|
* @param {object} options options
|
|
2252
2258
|
* @param {TargetProperties | false} options.targetProperties target properties
|
|
2253
2259
|
* @param {Environment} options.environment environment
|
|
2260
|
+
* @param {boolean} options.outputModule is output type is module
|
|
2254
2261
|
* @returns {void}
|
|
2255
2262
|
*/
|
|
2256
|
-
const applyLoaderDefaults = (
|
|
2263
|
+
const applyLoaderDefaults = (
|
|
2264
|
+
loader,
|
|
2265
|
+
{ targetProperties, environment, outputModule }
|
|
2266
|
+
) => {
|
|
2257
2267
|
F(loader, "target", () => {
|
|
2258
2268
|
if (targetProperties) {
|
|
2259
2269
|
if (targetProperties.electron) {
|
|
@@ -2267,6 +2277,15 @@ const applyLoaderDefaults = (loader, { targetProperties, environment }) => {
|
|
|
2267
2277
|
if (targetProperties.bun) return "bun";
|
|
2268
2278
|
if (targetProperties.node) return "node";
|
|
2269
2279
|
if (targetProperties.web) return "web";
|
|
2280
|
+
// no single platform to report: the bundle runs on both (target
|
|
2281
|
+
// `"universal"` / `["web", "node"]`), so loaders get `"universal"`
|
|
2282
|
+
if (
|
|
2283
|
+
outputModule &&
|
|
2284
|
+
targetProperties.node === null &&
|
|
2285
|
+
targetProperties.web === null
|
|
2286
|
+
) {
|
|
2287
|
+
return "universal";
|
|
2288
|
+
}
|
|
2270
2289
|
}
|
|
2271
2290
|
});
|
|
2272
2291
|
D(loader, "environment", environment);
|
|
@@ -38,12 +38,13 @@ class HoistContainerReferences {
|
|
|
38
38
|
const depsToTrace = new Set();
|
|
39
39
|
/** @type {Set<Dependency>} */
|
|
40
40
|
const entryExternalsToHoist = new Set();
|
|
41
|
-
hooks
|
|
41
|
+
// Both hooks feed the same trace set, so they share one callback.
|
|
42
|
+
/** @type {(dep: Dependency) => void} */
|
|
43
|
+
const traceDep = (dep) => {
|
|
42
44
|
depsToTrace.add(dep);
|
|
43
|
-
}
|
|
44
|
-
hooks.
|
|
45
|
-
|
|
46
|
-
});
|
|
45
|
+
};
|
|
46
|
+
hooks.addContainerEntryDependency.tap(PLUGIN_NAME, traceDep);
|
|
47
|
+
hooks.addFederationRuntimeDependency.tap(PLUGIN_NAME, traceDep);
|
|
47
48
|
|
|
48
49
|
compilation.hooks.addEntry.tap(PLUGIN_NAME, (entryDep) => {
|
|
49
50
|
if (entryDep.type === "entry") {
|
|
@@ -76,46 +77,26 @@ class HoistContainerReferences {
|
|
|
76
77
|
* @param {Set<Dependency>} entryExternalsToHoist Set of container entry dependencies to hoist.
|
|
77
78
|
*/
|
|
78
79
|
hoistModulesInChunks(compilation, depsToTrace, entryExternalsToHoist) {
|
|
79
|
-
const {
|
|
80
|
+
const { moduleGraph } = compilation;
|
|
80
81
|
|
|
81
|
-
//
|
|
82
|
+
// Entry externals: hoist the external modules (e.g. RemoteModule) they reference.
|
|
82
83
|
for (const dep of entryExternalsToHoist) {
|
|
83
84
|
const entryModule = moduleGraph.getModule(dep);
|
|
84
85
|
if (!entryModule) continue;
|
|
85
|
-
// get all the external module types and hoist them to the runtime chunk, this will get RemoteModule externals
|
|
86
86
|
const allReferencedModules = getAllReferencedModules(
|
|
87
87
|
compilation,
|
|
88
88
|
entryModule,
|
|
89
89
|
"external",
|
|
90
90
|
false
|
|
91
91
|
);
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
for (const runtimeSpec of containerRuntimes) {
|
|
98
|
-
forEachRuntime(runtimeSpec, (runtimeKey) => {
|
|
99
|
-
if (runtimeKey) {
|
|
100
|
-
runtimes.add(runtimeKey);
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
for (const runtime of runtimes) {
|
|
106
|
-
const runtimeChunk = compilation.namedChunks.get(runtime);
|
|
107
|
-
if (!runtimeChunk) continue;
|
|
108
|
-
|
|
109
|
-
for (const module of allReferencedModules) {
|
|
110
|
-
if (!chunkGraph.isModuleInChunk(module, runtimeChunk)) {
|
|
111
|
-
chunkGraph.connectChunkAndModule(runtimeChunk, module);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
this.cleanUpChunks(compilation, allReferencedModules);
|
|
92
|
+
this.hoistReferencedModules(
|
|
93
|
+
compilation,
|
|
94
|
+
entryModule,
|
|
95
|
+
allReferencedModules
|
|
96
|
+
);
|
|
116
97
|
}
|
|
117
98
|
|
|
118
|
-
//
|
|
99
|
+
// Container entries: hoist the initial graph plus its external references.
|
|
119
100
|
for (const dep of depsToTrace) {
|
|
120
101
|
const containerEntryModule = moduleGraph.getModule(dep);
|
|
121
102
|
if (!containerEntryModule) continue;
|
|
@@ -125,43 +106,54 @@ class HoistContainerReferences {
|
|
|
125
106
|
"initial",
|
|
126
107
|
false
|
|
127
108
|
);
|
|
128
|
-
|
|
129
109
|
const allRemoteReferences = getAllReferencedModules(
|
|
130
110
|
compilation,
|
|
131
111
|
containerEntryModule,
|
|
132
112
|
"external",
|
|
133
113
|
false
|
|
134
114
|
);
|
|
135
|
-
|
|
136
115
|
for (const remote of allRemoteReferences) {
|
|
137
116
|
allReferencedModules.add(remote);
|
|
138
117
|
}
|
|
118
|
+
this.hoistReferencedModules(
|
|
119
|
+
compilation,
|
|
120
|
+
containerEntryModule,
|
|
121
|
+
allReferencedModules
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
139
125
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
126
|
+
/**
|
|
127
|
+
* Connect `referencedModules` into each runtime chunk of `entryModule`, then
|
|
128
|
+
* prune the chunks they were hoisted out of. The two passes above build
|
|
129
|
+
* `referencedModules` differently but hoist them identically.
|
|
130
|
+
* @param {Compilation} compilation The webpack compilation instance.
|
|
131
|
+
* @param {Module} entryModule The module whose runtimes receive the modules.
|
|
132
|
+
* @param {Set<Module>} referencedModules The modules to hoist.
|
|
133
|
+
*/
|
|
134
|
+
hoistReferencedModules(compilation, entryModule, referencedModules) {
|
|
135
|
+
const { chunkGraph } = compilation;
|
|
136
|
+
/** @type {Set<string>} */
|
|
137
|
+
const runtimes = new Set();
|
|
138
|
+
for (const runtimeSpec of chunkGraph.getModuleRuntimes(entryModule)) {
|
|
139
|
+
forEachRuntime(runtimeSpec, (runtimeKey) => {
|
|
140
|
+
if (runtimeKey) {
|
|
141
|
+
runtimes.add(runtimeKey);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
}
|
|
152
145
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
146
|
+
for (const runtime of runtimes) {
|
|
147
|
+
const runtimeChunk = compilation.namedChunks.get(runtime);
|
|
148
|
+
if (!runtimeChunk) continue;
|
|
156
149
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
150
|
+
for (const module of referencedModules) {
|
|
151
|
+
if (!chunkGraph.isModuleInChunk(module, runtimeChunk)) {
|
|
152
|
+
chunkGraph.connectChunkAndModule(runtimeChunk, module);
|
|
161
153
|
}
|
|
162
154
|
}
|
|
163
|
-
this.cleanUpChunks(compilation, allReferencedModules);
|
|
164
155
|
}
|
|
156
|
+
this.cleanUpChunks(compilation, referencedModules);
|
|
165
157
|
}
|
|
166
158
|
|
|
167
159
|
/**
|
|
@@ -18,11 +18,21 @@ const HoistContainerReferences = require("./HoistContainerReferencesPlugin");
|
|
|
18
18
|
/** @typedef {import("../Compiler")} Compiler */
|
|
19
19
|
/** @typedef {import("../Dependency")} Dependency */
|
|
20
20
|
|
|
21
|
+
const createCompilationHooks = () => ({
|
|
22
|
+
/**
|
|
23
|
+
* @type {SyncHook<Dependency>}
|
|
24
|
+
* @since 5.96.0
|
|
25
|
+
*/
|
|
26
|
+
addContainerEntryDependency: new SyncHook(["dependency"]),
|
|
27
|
+
/**
|
|
28
|
+
* @type {SyncHook<Dependency>}
|
|
29
|
+
* @since 5.96.0
|
|
30
|
+
*/
|
|
31
|
+
addFederationRuntimeDependency: new SyncHook(["dependency"])
|
|
32
|
+
});
|
|
33
|
+
|
|
21
34
|
/**
|
|
22
|
-
*
|
|
23
|
-
* @typedef {object} CompilationHooks
|
|
24
|
-
* @property {SyncHook<Dependency>} addContainerEntryDependency
|
|
25
|
-
* @property {SyncHook<Dependency>} addFederationRuntimeDependency
|
|
35
|
+
* @typedef {ReturnType<typeof createCompilationHooks>} CompilationHooks
|
|
26
36
|
*/
|
|
27
37
|
|
|
28
38
|
const PLUGIN_NAME = "ModuleFederationPlugin";
|
|
@@ -111,11 +121,7 @@ class ModuleFederationPlugin {
|
|
|
111
121
|
}
|
|
112
122
|
|
|
113
123
|
ModuleFederationPlugin.getCompilationHooks = createHooksRegistry(
|
|
114
|
-
|
|
115
|
-
/** @type {CompilationHooks} */ ({
|
|
116
|
-
addContainerEntryDependency: new SyncHook(["dependency"]),
|
|
117
|
-
addFederationRuntimeDependency: new SyncHook(["dependency"])
|
|
118
|
-
})
|
|
124
|
+
createCompilationHooks
|
|
119
125
|
);
|
|
120
126
|
|
|
121
127
|
module.exports = ModuleFederationPlugin;
|
package/lib/css/CssGenerator.js
CHANGED
|
@@ -33,6 +33,7 @@ const CssImportDependency = require("../dependencies/CssImportDependency");
|
|
|
33
33
|
const HarmonyImportSideEffectDependency = require("../dependencies/HarmonyImportSideEffectDependency");
|
|
34
34
|
|
|
35
35
|
const { encodeMappings } = require("../util/createMappings");
|
|
36
|
+
const { contextifySourceUrl } = require("../util/identifier");
|
|
36
37
|
const memoize = require("../util/memoize");
|
|
37
38
|
const {
|
|
38
39
|
PUBLIC_PATH_FULL_HASH,
|
|
@@ -549,8 +550,13 @@ class CssGenerator extends Generator {
|
|
|
549
550
|
}
|
|
550
551
|
|
|
551
552
|
const generatedJs = /** @type {string} */ (source.source());
|
|
552
|
-
|
|
553
|
-
|
|
553
|
+
// Context-relative identifier, like `NormalModule.createSource` — so
|
|
554
|
+
// `SourceMapDevToolPlugin` can match the module and apply the
|
|
555
|
+
// devtool filename template instead of leaking this raw name
|
|
556
|
+
const sourceName = contextifySourceUrl(
|
|
557
|
+
/** @type {string} */ (compilation.options.context),
|
|
558
|
+
module.identifier(),
|
|
559
|
+
compilation.compiler.root
|
|
554
560
|
);
|
|
555
561
|
|
|
556
562
|
if (
|
|
@@ -20,12 +20,31 @@ const { chunkHasCss } = require("./CssModulesPlugin");
|
|
|
20
20
|
/** @typedef {import("../ChunkGraph")} ChunkGraph */
|
|
21
21
|
/** @typedef {import("../Module").ReadOnlyRuntimeRequirements} ReadOnlyRuntimeRequirements */
|
|
22
22
|
|
|
23
|
+
const createCompilationHooks = () => ({
|
|
24
|
+
/**
|
|
25
|
+
* @type {SyncWaterfallHook<[string, Chunk]>}
|
|
26
|
+
* @since 5.66.0
|
|
27
|
+
*/
|
|
28
|
+
createStylesheet: new SyncWaterfallHook(["source", "chunk"]),
|
|
29
|
+
/**
|
|
30
|
+
* @type {SyncWaterfallHook<[string, Chunk]>}
|
|
31
|
+
* @since 5.91.0
|
|
32
|
+
*/
|
|
33
|
+
linkPreload: new SyncWaterfallHook(["source", "chunk"]),
|
|
34
|
+
/**
|
|
35
|
+
* @type {SyncWaterfallHook<[string, Chunk]>}
|
|
36
|
+
* @since 5.91.0
|
|
37
|
+
*/
|
|
38
|
+
linkPrefetch: new SyncWaterfallHook(["source", "chunk"]),
|
|
39
|
+
/**
|
|
40
|
+
* @type {SyncWaterfallHook<[string, Chunk]>}
|
|
41
|
+
* @since 5.107.0
|
|
42
|
+
*/
|
|
43
|
+
linkInsert: new SyncWaterfallHook(["source", "chunk"])
|
|
44
|
+
});
|
|
45
|
+
|
|
23
46
|
/**
|
|
24
|
-
* @typedef {
|
|
25
|
-
* @property {SyncWaterfallHook<[string, Chunk]>} createStylesheet
|
|
26
|
-
* @property {SyncWaterfallHook<[string, Chunk]>} linkPreload
|
|
27
|
-
* @property {SyncWaterfallHook<[string, Chunk]>} linkPrefetch
|
|
28
|
-
* @property {SyncWaterfallHook<[string, Chunk]>} linkInsert
|
|
47
|
+
* @typedef {ReturnType<typeof createCompilationHooks>} CssLoadingRuntimeModulePluginHooks
|
|
29
48
|
*/
|
|
30
49
|
|
|
31
50
|
class CssLoadingRuntimeModule extends RuntimeModule {
|
|
@@ -577,13 +596,7 @@ class CssLoadingRuntimeModule extends RuntimeModule {
|
|
|
577
596
|
}
|
|
578
597
|
|
|
579
598
|
CssLoadingRuntimeModule.getCompilationHooks = createHooksRegistry(
|
|
580
|
-
|
|
581
|
-
/** @type {CssLoadingRuntimeModulePluginHooks} */ ({
|
|
582
|
-
createStylesheet: new SyncWaterfallHook(["source", "chunk"]),
|
|
583
|
-
linkPreload: new SyncWaterfallHook(["source", "chunk"]),
|
|
584
|
-
linkPrefetch: new SyncWaterfallHook(["source", "chunk"]),
|
|
585
|
-
linkInsert: new SyncWaterfallHook(["source", "chunk"])
|
|
586
|
-
})
|
|
599
|
+
createCompilationHooks
|
|
587
600
|
);
|
|
588
601
|
|
|
589
602
|
module.exports = CssLoadingRuntimeModule;
|