Skip to content

Commit 36a976b

Browse files
feat: added the deferImport option to parser options (#19737)
1 parent 92304df commit 36a976b

15 files changed

+108
-45
lines changed

declarations/WebpackOptions.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3287,6 +3287,10 @@ export interface JavascriptParserOptions {
32873287
* Enable/disable parsing "import { createRequire } from "module"" and evaluating createRequire().
32883288
*/
32893289
createRequire?: boolean | string;
3290+
/**
3291+
* Enable experimental tc39 proposal https://github.com/tc39/proposal-defer-import-eval. This allows to defer execution of a module until it's first use.
3292+
*/
3293+
deferImport?: boolean;
32903294
/**
32913295
* Specifies global fetchPriority for dynamic import.
32923296
*/

lib/RuntimeTemplate.js

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -829,13 +829,6 @@ class RuntimeTemplate {
829829
];
830830
}
831831

832-
defer = defer && (module.buildMeta ? !module.buildMeta.async : true);
833-
834-
/** @type {Set<Module>} */
835-
const outgoingAsyncModules = defer
836-
? getOutgoingAsyncModules(moduleGraph, module)
837-
: new Set();
838-
839832
if (chunkGraph.getModuleId(module) === null) {
840833
if (weak) {
841834
// only weak referenced modules don't get an id
@@ -872,7 +865,10 @@ class RuntimeTemplate {
872865
);
873866
runtimeRequirements.add(RuntimeGlobals.require);
874867
let importContent;
875-
if (defer) {
868+
if (defer && !(/** @type {BuildMeta} */ (module.buildMeta).async)) {
869+
/** @type {Set<Module>} */
870+
const outgoingAsyncModules = getOutgoingAsyncModules(moduleGraph, module);
871+
876872
importContent = `/* deferred harmony import */ ${optDeclaration}${importVar} = ${getOptimizedDeferredModule(
877873
this,
878874
exportsType,
@@ -936,8 +932,6 @@ class RuntimeTemplate {
936932
request
937933
});
938934
}
939-
940-
defer = defer && (module.buildMeta ? !module.buildMeta.async : true);
941935
if (!Array.isArray(exportName)) {
942936
exportName = exportName ? [exportName] : [];
943937
}
@@ -947,10 +941,13 @@ class RuntimeTemplate {
947941
(originModule.buildMeta).strictHarmonyModule
948942
);
949943

944+
const isDeferred =
945+
defer && !(/** @type {BuildMeta} */ (module.buildMeta).async);
946+
950947
if (defaultInterop) {
951948
// when the defaultInterop is used (when a ESM imports a CJS module),
952949
if (exportName.length > 0 && exportName[0] === "default") {
953-
if (defer && exportsType !== "namespace") {
950+
if (isDeferred && exportsType !== "namespace") {
954951
const access = `${importVar}.a${propertyAccess(exportName, 1)}`;
955952
if (isCall || asiSafe === undefined) {
956953
return access;
@@ -995,7 +992,7 @@ class RuntimeTemplate {
995992
) {
996993
return "/* __esModule */true";
997994
}
998-
} else if (defer) {
995+
} else if (isDeferred) {
999996
// now exportName.length is 0
1000997
// fall through to the end of this function, create the namespace there.
1001998
} else if (
@@ -1038,7 +1035,7 @@ class RuntimeTemplate {
10381035
? ""
10391036
: `${Template.toNormalComment(propertyAccess(exportName))} `;
10401037
const access = `${importVar}${
1041-
defer ? ".a" : ""
1038+
isDeferred ? ".a" : ""
10421039
}${comment}${propertyAccess(used)}`;
10431040
if (isCall && callContext === false) {
10441041
return asiSafe
@@ -1049,7 +1046,7 @@ class RuntimeTemplate {
10491046
}
10501047
return access;
10511048
}
1052-
if (defer) {
1049+
if (isDeferred) {
10531050
initFragments.push(
10541051
new InitFragment(
10551052
`var ${importVar}_deferred_namespace_cache;\n`,

lib/config/defaults.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,9 @@ const applyWebpackOptionsDefaults = (options, compilerIndex) => {
265265
css:
266266
/** @type {NonNullable<ExperimentsNormalized["css"]>} */
267267
(options.experiments.css),
268+
deferImport:
269+
/** @type {NonNullable<ExperimentsNormalized["deferImport"]>} */
270+
(options.experiments.deferImport),
268271
futureDefaults,
269272
isNode: targetProperties && targetProperties.node === true,
270273
uniqueName: /** @type {string} */ (options.output.uniqueName),
@@ -562,12 +565,13 @@ const applySnapshotDefaults = (snapshot, { production, futureDefaults }) => {
562565
* @param {JavascriptParserOptions} parserOptions parser options
563566
* @param {object} options options
564567
* @param {boolean} options.futureDefaults is future defaults enabled
568+
* @param {boolean} options.deferImport is defer import enabled
565569
* @param {boolean} options.isNode is node target platform
566570
* @returns {void}
567571
*/
568572
const applyJavascriptParserOptionsDefaults = (
569573
parserOptions,
570-
{ futureDefaults, isNode }
574+
{ futureDefaults, deferImport, isNode }
571575
) => {
572576
D(parserOptions, "unknownContextRequest", ".");
573577
D(parserOptions, "unknownContextRegExp", false);
@@ -588,6 +592,7 @@ const applyJavascriptParserOptionsDefaults = (
588592
D(parserOptions, "dynamicImportFetchPriority", false);
589593
D(parserOptions, "createRequire", isNode);
590594
D(parserOptions, "dynamicUrl", true);
595+
D(parserOptions, "deferImport", deferImport);
591596
if (futureDefaults) D(parserOptions, "exportsPresence", "error");
592597
};
593598

@@ -627,6 +632,7 @@ const applyCssGeneratorOptionsDefaults = (
627632
* @param {boolean} options.futureDefaults is future defaults enabled
628633
* @param {string} options.uniqueName the unique name
629634
* @param {boolean} options.isNode is node target platform
635+
* @param {boolean} options.deferImport is defer import enabled
630636
* @param {TargetProperties | false} options.targetProperties target properties
631637
* @param {Mode | undefined} options.mode mode
632638
* @returns {void}
@@ -642,7 +648,8 @@ const applyModuleDefaults = (
642648
isNode,
643649
uniqueName,
644650
targetProperties,
645-
mode
651+
mode,
652+
deferImport
646653
}
647654
) => {
648655
if (cache) {
@@ -700,6 +707,7 @@ const applyModuleDefaults = (
700707
(module.parser.javascript),
701708
{
702709
futureDefaults,
710+
deferImport,
703711
isNode
704712
}
705713
);

lib/dependencies/HarmonyExportDependencyParserPlugin.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,8 @@ const PLUGIN_NAME = "HarmonyExportDependencyParserPlugin";
3333
module.exports = class HarmonyExportDependencyParserPlugin {
3434
/**
3535
* @param {import("../../declarations/WebpackOptions").JavascriptParserOptions} options options
36-
* @param {boolean=} deferImport defer import enabled
3736
*/
38-
constructor(options, deferImport) {
37+
constructor(options) {
3938
this.exportPresenceMode =
4039
options.reexportExportsPresence !== undefined
4140
? ExportPresenceModes.fromUserOption(options.reexportExportsPresence)
@@ -44,7 +43,7 @@ module.exports = class HarmonyExportDependencyParserPlugin {
4443
: options.strictExportPresence
4544
? ExportPresenceModes.ERROR
4645
: ExportPresenceModes.AUTO;
47-
this.deferImport = deferImport;
46+
this.deferImport = options.deferImport;
4847
}
4948

5049
/**

lib/dependencies/HarmonyExportImportedSpecifierDependency.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
378378
* @param {ExportPresenceMode} exportPresenceMode mode of checking export names
379379
* @param {HarmonyStarExportsList | null} allStarExports all star exports in the module
380380
* @param {ImportAttributes=} attributes import attributes
381-
* @param {boolean=} deferEvaluation defer evaluation
381+
* @param {boolean=} defer is defer phase
382382
*/
383383
constructor(
384384
request,
@@ -390,17 +390,16 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
390390
exportPresenceMode,
391391
allStarExports,
392392
attributes,
393-
deferEvaluation
393+
defer
394394
) {
395-
super(request, sourceOrder, attributes);
395+
super(request, sourceOrder, attributes, defer);
396396

397397
this.ids = ids;
398398
this.name = name;
399399
this.activeExports = activeExports;
400400
this.otherStarExports = otherStarExports;
401401
this.exportPresenceMode = exportPresenceMode;
402402
this.allStarExports = allStarExports;
403-
this.defer = deferEvaluation;
404403
}
405404

406405
/**

lib/dependencies/HarmonyImportDependency.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,13 @@ class HarmonyImportDependency extends ModuleDependency {
6464
* @param {string} request request string
6565
* @param {number} sourceOrder source order
6666
* @param {ImportAttributes=} attributes import attributes
67+
* @param {boolean=} defer import attributes
6768
*/
68-
constructor(request, sourceOrder, attributes) {
69+
constructor(request, sourceOrder, attributes, defer) {
6970
super(request);
7071
this.sourceOrder = sourceOrder;
7172
this.assertions = attributes;
73+
this.defer = defer;
7274
}
7375

7476
get category() {

lib/dependencies/HarmonyImportDependencyParserPlugin.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,8 @@ const PLUGIN_NAME = "HarmonyImportDependencyParserPlugin";
5959
module.exports = class HarmonyImportDependencyParserPlugin {
6060
/**
6161
* @param {JavascriptParserOptions} options options
62-
* @param {boolean | undefined} deferImport defer import enabled
6362
*/
64-
constructor(options, deferImport) {
63+
constructor(options) {
6564
this.exportPresenceMode =
6665
options.importExportsPresence !== undefined
6766
? ExportPresenceModes.fromUserOption(options.importExportsPresence)
@@ -71,7 +70,7 @@ module.exports = class HarmonyImportDependencyParserPlugin {
7170
? ExportPresenceModes.ERROR
7271
: ExportPresenceModes.AUTO;
7372
this.strictThisContextOnImports = options.strictThisContextOnImports;
74-
this.deferImport = deferImport;
73+
this.deferImport = options.deferImport;
7574
}
7675

7776
/**

lib/dependencies/HarmonyImportSideEffectDependency.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,10 @@ class HarmonyImportSideEffectDependency extends HarmonyImportDependency {
2626
* @param {string} request the request string
2727
* @param {number} sourceOrder source order
2828
* @param {ImportAttributes=} attributes import attributes
29-
* @param {boolean=} deferred deferred
29+
* @param {boolean=} defer is defer phase
3030
*/
31-
constructor(request, sourceOrder, attributes, deferred) {
32-
super(request, sourceOrder, attributes);
33-
this.defer = deferred;
31+
constructor(request, sourceOrder, attributes, defer) {
32+
super(request, sourceOrder, attributes, defer);
3433
}
3534

3635
get type() {

lib/dependencies/HarmonyImportSpecifierDependency.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
5151
* @param {ExportPresenceMode} exportPresenceMode export presence mode
5252
* @param {ImportAttributes | undefined} attributes import attributes
5353
* @param {Range[] | undefined} idRanges ranges for members of ids; the two arrays are right-aligned
54-
* @param {boolean=} deferred deferred
54+
* @param {boolean=} defer is defer phase
5555
*/
5656
constructor(
5757
request,
@@ -62,9 +62,9 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
6262
exportPresenceMode,
6363
attributes,
6464
idRanges, // TODO webpack 6 make this non-optional. It must always be set to properly trim ids.
65-
deferred
65+
defer
6666
) {
67-
super(request, sourceOrder, attributes);
67+
super(request, sourceOrder, attributes, defer);
6868
this.ids = ids;
6969
this.name = name;
7070
this.range = range;
@@ -79,7 +79,6 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
7979
this.usedByExports = undefined;
8080
/** @type {Set<DestructuringAssignmentProperty> | undefined} */
8181
this.referencedPropertiesInDestructuring = undefined;
82-
this.defer = deferred;
8382
}
8483

8584
// TODO webpack 6 remove

lib/dependencies/HarmonyModulesPlugin.js

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -135,14 +135,8 @@ class HarmonyModulesPlugin {
135135
}
136136

137137
new HarmonyDetectionParserPlugin(this.options).apply(parser);
138-
new HarmonyImportDependencyParserPlugin(
139-
parserOptions,
140-
this.options.deferImport
141-
).apply(parser);
142-
new HarmonyExportDependencyParserPlugin(
143-
parserOptions,
144-
this.options.deferImport
145-
).apply(parser);
138+
new HarmonyImportDependencyParserPlugin(parserOptions).apply(parser);
139+
new HarmonyExportDependencyParserPlugin(parserOptions).apply(parser);
146140
new HarmonyTopLevelThisParserPlugin().apply(parser);
147141
};
148142

0 commit comments

Comments
 (0)