Skip to content

Commit acf2165

Browse files
authored
feat(css): generate separate CssModule instances per exportType (#20590)
1 parent a511177 commit acf2165

11 files changed

Lines changed: 271 additions & 255 deletions

File tree

.changeset/css-export-types.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"webpack": feat
3+
---
4+
5+
Generate different `CssModule` instances for different `exportType` values.

lib/CssModule.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@ const makeSerializable = require("./util/makeSerializable");
1313
/** @typedef {import("./RequestShortener")} RequestShortener */
1414
/** @typedef {import("./serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
1515
/** @typedef {import("./serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
16+
/** @typedef {import("../declarations/WebpackOptions").CssParserExportType} CssParserExportType */
1617

1718
/** @typedef {string | undefined} CssLayer */
1819
/** @typedef {string | undefined} Supports */
1920
/** @typedef {string | undefined} Media */
2021
/** @typedef {[CssLayer, Supports, Media]} InheritanceItem */
2122
/** @typedef {InheritanceItem[]} Inheritance */
2223

23-
/** @typedef {NormalModuleCreateData & { cssLayer: CssLayer, supports: Supports, media: Media, inheritance?: Inheritance }} CSSModuleCreateData */
24+
/** @typedef {NormalModuleCreateData & { cssLayer: CssLayer, supports: Supports, media: Media, inheritance?: Inheritance, exportType?: CssParserExportType }} CSSModuleCreateData */
2425

2526
class CssModule extends NormalModule {
2627
/**
@@ -38,6 +39,8 @@ class CssModule extends NormalModule {
3839
this.media = options.media;
3940
/** @type {CSSModuleCreateData['inheritance']} */
4041
this.inheritance = options.inheritance;
42+
/** @type {CSSModuleCreateData['exportType']} */
43+
this.exportType = options.exportType;
4144
}
4245

4346
/**
@@ -69,6 +72,10 @@ class CssModule extends NormalModule {
6972
identifier += `|${inheritance.join("|")}`;
7073
}
7174

75+
if (this.exportType) {
76+
identifier += `|${this.exportType}`;
77+
}
78+
7279
// We generate extra code for HMR, so we need to invalidate the module
7380
if (this.hot) {
7481
identifier += `|${this.hot}`;
@@ -98,6 +105,10 @@ class CssModule extends NormalModule {
98105
identifier += ` (media: ${this.media})`;
99106
}
100107

108+
if (this.exportType) {
109+
identifier += ` (exportType: ${this.exportType})`;
110+
}
111+
101112
return identifier;
102113
}
103114

@@ -115,6 +126,7 @@ class CssModule extends NormalModule {
115126
this.supports = m.supports;
116127
this.media = m.media;
117128
this.inheritance = m.inheritance;
129+
this.exportType = m.exportType;
118130
}
119131

120132
/**
@@ -126,6 +138,7 @@ class CssModule extends NormalModule {
126138
write(this.supports);
127139
write(this.media);
128140
write(this.inheritance);
141+
write(this.exportType);
129142
super.serialize(context);
130143
}
131144

@@ -155,7 +168,8 @@ class CssModule extends NormalModule {
155168
supports: /** @type {EXPECTED_ANY} */ (null),
156169
media: /** @type {EXPECTED_ANY} */ (null),
157170
inheritance: /** @type {EXPECTED_ANY} */ (null),
158-
extractSourceMap: /** @type {EXPECTED_ANY} */ (null)
171+
extractSourceMap: /** @type {EXPECTED_ANY} */ (null),
172+
exportType: /** @type {EXPECTED_ANY} */ (null)
159173
});
160174
obj.deserialize(context);
161175
return obj;
@@ -170,6 +184,7 @@ class CssModule extends NormalModule {
170184
this.supports = read();
171185
this.media = read();
172186
this.inheritance = read();
187+
this.exportType = read();
173188
super.deserialize(context);
174189
}
175190
}

lib/Module.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,6 @@ const makeSerializable = require("./util/makeSerializable");
156156
/**
157157
* @typedef {object} KnownBuildMeta
158158
* @property {("default" | "namespace" | "flagged" | "dynamic")=} exportsType
159-
* @property {CssParserExportType=} exportType
160159
* @property {(false | "redirect" | "redirect-warn")=} defaultObject
161160
* @property {boolean=} strictHarmonyModule
162161
* @property {boolean=} treatAsCommonJs

lib/css/CssGenerator.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class CssGenerator extends Generator {
107107
parts.push({
108108
expr: `(${RuntimeGlobals.compatGetDefaultExport}(${importVar})() || "")`,
109109
type: /** @type {CssParserExportType} */ (
110-
/** @type {BuildMeta} */ (depModule.buildMeta).exportType
110+
/** @type {CssModule} */ (depModule).exportType
111111
)
112112
});
113113
}
@@ -263,7 +263,7 @@ class CssGenerator extends Generator {
263263
* @returns {Source | null} generated code
264264
*/
265265
generate(module, generateContext) {
266-
const exportType = /** @type {BuildMeta} */ (module.buildMeta).exportType;
266+
const exportType = /** @type {CssModule} */ (module).exportType || "link";
267267
const source =
268268
generateContext.type === JAVASCRIPT_TYPE
269269
? exportType === "link"
@@ -468,7 +468,7 @@ class CssGenerator extends Generator {
468468
* @returns {SourceTypes} available types (do not mutate)
469469
*/
470470
getTypes(module) {
471-
const exportType = /** @type {BuildMeta} */ (module.buildMeta).exportType;
471+
const exportType = /** @type {CssModule} */ (module).exportType || "link";
472472
const sourceTypes = new Set();
473473

474474
const connections = this._moduleGraph.getIncomingConnections(module);
@@ -495,9 +495,8 @@ class CssGenerator extends Generator {
495495
sourceTypes.add(JAVASCRIPT_TYPE);
496496
} else {
497497
const originModule = /** @type {CssModule} */ connection.originModule;
498-
const originExportType = /** @type {BuildMeta} */ (
499-
originModule.buildMeta
500-
).exportType;
498+
const originExportType = /** @type {CssModule} */ (originModule)
499+
.exportType;
501500
if (
502501
/** @type {boolean} */ (
503502
originExportType && originExportType !== "link"
@@ -574,7 +573,7 @@ class CssGenerator extends Generator {
574573
* @returns {boolean} true if the module only outputs JavaScript
575574
*/
576575
_generatesJsOnly(module) {
577-
const exportType = /** @type {BuildMeta} */ (module.buildMeta).exportType;
576+
const exportType = /** @type {CssModule} */ (module).exportType;
578577
return (
579578
this._exportsOnly ||
580579
/** @type {boolean} */ (exportType && exportType !== "link")

lib/css/CssModulesPlugin.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,9 @@ class CssModulesPlugin {
344344
normalModuleFactory.hooks.createModuleClass
345345
.for(type)
346346
.tap(PLUGIN_NAME, (createData, resolveData) => {
347+
const exportType =
348+
createData.parser &&
349+
/** @type {CssParser} */ (createData.parser).options.exportType;
347350
if (resolveData.dependencies.length > 0) {
348351
// When CSS is imported from CSS there is only one dependency
349352
const dependency = resolveData.dependencies[0];
@@ -388,7 +391,8 @@ class CssModulesPlugin {
388391
cssLayer: dependency.layer,
389392
supports: dependency.supports,
390393
media: dependency.media,
391-
inheritance
394+
inheritance,
395+
exportType: exportType || parent.exportType
392396
})
393397
);
394398
}
@@ -399,15 +403,21 @@ class CssModulesPlugin {
399403
...createData,
400404
cssLayer: dependency.layer,
401405
supports: dependency.supports,
402-
media: dependency.media
406+
media: dependency.media,
407+
exportType
403408
})
404409
);
405410
}
406411
}
407412

408413
return new CssModule(
409414
/** @type {CSSModuleCreateData} */
410-
(createData)
415+
(
416+
/** @type {CSSModuleCreateData} */ ({
417+
...createData,
418+
exportType
419+
})
420+
)
411421
);
412422
});
413423

@@ -429,8 +439,7 @@ class CssModulesPlugin {
429439
compilation
430440
).renderModuleContent.tap(PLUGIN_NAME, (source, module) => {
431441
if (module instanceof CssModule && module.hot) {
432-
const exportType = /** @type {BuildMeta} */ (module.buildMeta)
433-
.exportType;
442+
const exportType = module.exportType;
434443
// When exportType !== "link", modules behave like JavaScript modules
435444
if (exportType && exportType !== "link") {
436445
return source;

lib/css/CssParser.js

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
const vm = require("vm");
99
const CommentCompilationWarning = require("../CommentCompilationWarning");
10-
const CssModule = require("../CssModule");
1110
const ModuleDependencyWarning = require("../ModuleDependencyWarning");
1211
const { CSS_MODULE_TYPE_AUTO } = require("../ModuleTypeConstants");
1312
const Parser = require("../Parser");
@@ -34,6 +33,7 @@ const walkCssTokens = require("./walkCssTokens");
3433
/** @typedef {import("../Parser").PreparsedAst} PreparsedAst */
3534
/** @typedef {import("./walkCssTokens").CssTokenCallbacks} CssTokenCallbacks */
3635
/** @typedef {import("../../declarations/WebpackOptions").CssModuleParserOptions} CssModuleParserOptions */
36+
/** @typedef {import("../CssModule")} CssModule */
3737

3838
/** @typedef {[number, number]} Range */
3939
/** @typedef {{ line: number, column: number }} Position */
@@ -2509,30 +2509,11 @@ class CssParser extends Parser {
25092509
buildMeta.defaultObject = this.options.namedExports
25102510
? false
25112511
: "redirect-warn";
2512-
buildMeta.exportType = this.options.exportType;
2513-
2514-
if (!buildMeta.exportType) {
2515-
// Inherit exportType from parent module to ensure consistency.
2516-
// When a CSS file is imported with syntax like `import "./basic.css" with { type: "css" }`,
2517-
// the parent module's exportType is set to "css-style-sheet".
2518-
// Child modules imported via @import should inherit this exportType
2519-
// instead of using the default "link", ensuring that the entire
2520-
// import chain uses the same export format.
2521-
const parent = state.compilation.moduleGraph.getIssuer(module);
2522-
if (parent instanceof CssModule) {
2523-
buildMeta.exportType = /** @type {BuildMeta} */ (
2524-
parent.buildMeta
2525-
).exportType;
2526-
}
2527-
}
2528-
if (!buildMeta.exportType) {
2529-
buildMeta.exportType = "link";
2530-
}
25312512

25322513
// TODO this.namedExports?
25332514
if (
2534-
buildMeta.exportType === "text" ||
2535-
buildMeta.exportType === "css-style-sheet"
2515+
/** @type {CssModule} */ (module).exportType === "text" ||
2516+
/** @type {CssModule} */ (module).exportType === "css-style-sheet"
25362517
) {
25372518
module.addDependency(new StaticExportsDependency(["default"], true));
25382519
} else {

0 commit comments

Comments
 (0)