fix: `css/auto` considers a module depending on its filename as `css` (pure CSS) or `css/local`

This commit is contained in:
Alexander Akait 2024-10-08 16:52:23 +03:00 committed by GitHub
commit 94feb93752
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 99 additions and 55 deletions

View File

@ -17,7 +17,8 @@ const {
ASSET_MODULE_TYPE,
CSS_MODULE_TYPE_AUTO,
CSS_MODULE_TYPE,
CSS_MODULE_TYPE_MODULE
CSS_MODULE_TYPE_MODULE,
CSS_MODULE_TYPE_GLOBAL
} = require("../ModuleTypeConstants");
const Template = require("../Template");
const { cleverMerge } = require("../util/cleverMerge");
@ -633,19 +634,19 @@ const applyModuleDefaults = (
F(module.parser, ASSET_MODULE_TYPE, () => ({}));
F(
/** @type {NonNullable<ParserOptionsByModuleTypeKnown["asset"]>} */
(module.parser.asset),
(module.parser[ASSET_MODULE_TYPE]),
"dataUrlCondition",
() => ({})
);
if (
typeof (
/** @type {NonNullable<ParserOptionsByModuleTypeKnown["asset"]>} */
(module.parser.asset).dataUrlCondition
(module.parser[ASSET_MODULE_TYPE]).dataUrlCondition
) === "object"
) {
D(
/** @type {NonNullable<ParserOptionsByModuleTypeKnown["asset"]>} */
(module.parser.asset).dataUrlCondition,
(module.parser[ASSET_MODULE_TYPE]).dataUrlCondition,
"maxSize",
8096
);
@ -663,41 +664,41 @@ const applyModuleDefaults = (
);
if (css) {
F(module.parser, "css", () => ({}));
F(module.parser, CSS_MODULE_TYPE, () => ({}));
D(module.parser.css, "namedExports", true);
D(module.parser[CSS_MODULE_TYPE], "namedExports", true);
F(module.generator, "css", () => ({}));
F(module.generator, CSS_MODULE_TYPE, () => ({}));
applyCssGeneratorOptionsDefaults(
/** @type {NonNullable<GeneratorOptionsByModuleTypeKnown["css"]>} */
(module.generator.css),
(module.generator[CSS_MODULE_TYPE]),
{ targetProperties }
);
F(module.generator, "css/auto", () => ({}));
F(module.generator, CSS_MODULE_TYPE_AUTO, () => ({}));
D(
module.generator["css/auto"],
module.generator[CSS_MODULE_TYPE_AUTO],
"localIdentName",
"[uniqueName]-[id]-[local]"
);
D(module.generator["css/auto"], "exportsConvention", "as-is");
D(module.generator[CSS_MODULE_TYPE_AUTO], "exportsConvention", "as-is");
F(module.generator, "css/module", () => ({}));
F(module.generator, CSS_MODULE_TYPE_MODULE, () => ({}));
D(
module.generator["css/module"],
module.generator[CSS_MODULE_TYPE_MODULE],
"localIdentName",
"[uniqueName]-[id]-[local]"
);
D(module.generator["css/module"], "exportsConvention", "as-is");
D(module.generator[CSS_MODULE_TYPE_MODULE], "exportsConvention", "as-is");
F(module.generator, "css/global", () => ({}));
F(module.generator, CSS_MODULE_TYPE_GLOBAL, () => ({}));
D(
module.generator["css/global"],
module.generator[CSS_MODULE_TYPE_GLOBAL],
"localIdentName",
"[uniqueName]-[id]-[local]"
);
D(module.generator["css/global"], "exportsConvention", "as-is");
D(module.generator[CSS_MODULE_TYPE_GLOBAL], "exportsConvention", "as-is");
}
A(module, "defaultRules", () => {

View File

@ -278,14 +278,13 @@ class CssModulesPlugin {
const { namedExports } = parserOptions;
switch (type) {
case CSS_MODULE_TYPE_GLOBAL:
case CSS_MODULE_TYPE_AUTO:
case CSS_MODULE_TYPE:
return new CssParser({
namedExports
});
case CSS_MODULE_TYPE:
case CSS_MODULE_TYPE_GLOBAL:
return new CssParser({
allowModeSwitch: false,
defaultMode: "global",
namedExports
});
case CSS_MODULE_TYPE_MODULE:
@ -293,6 +292,11 @@ class CssModulesPlugin {
defaultMode: "local",
namedExports
});
case CSS_MODULE_TYPE_AUTO:
return new CssParser({
defaultMode: "auto",
namedExports
});
}
});
normalModuleFactory.hooks.createGenerator

View File

@ -38,7 +38,8 @@ const STRING_MULTILINE = /\\[\n\r\f]/g;
// https://www.w3.org/TR/css-syntax-3/#whitespace
const TRIM_WHITE_SPACES = /(^[ \t\n\r\f]*|[ \t\n\r\f]*$)/g;
const UNESCAPE = /\\([0-9a-fA-F]{1,6}[ \t\n\r\f]?|[\s\S])/g;
const IMAGE_SET_FUNCTION = /^(-\w+-)?image-set$/i;
// TODO fix tokens
const IMAGE_SET_FUNCTION = /^:?(-\w+-)?image-set$/i;
const OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE = /^@(-\w+-)?keyframes$/;
const OPTIONALLY_VENDOR_PREFIXED_ANIMATION_PROPERTY =
/^(-\w+-)?animation(-name)?$/i;
@ -133,13 +134,13 @@ const CSS_MODE_AT_IMPORT_INVALID = 3;
const CSS_MODE_AT_NAMESPACE_INVALID = 4;
class CssParser extends Parser {
constructor({
allowModeSwitch = true,
defaultMode = "global",
namedExports = true
} = {}) {
/**
* @param {object} options options
* @param {("pure" | "global" | "local" | "auto")=} options.defaultMode default mode
* @param {boolean=} options.namedExports is named exports
*/
constructor({ defaultMode = "pure", namedExports = true } = {}) {
super();
this.allowModeSwitch = allowModeSwitch;
this.defaultMode = defaultMode;
this.namedExports = namedExports;
}
@ -178,22 +179,22 @@ class CssParser extends Parser {
source = source.slice(1);
}
let mode = this.defaultMode;
const module = state.module;
/** @type {string | undefined} */
let oldDefaultMode;
if (
mode === "auto" &&
module.type === CSS_MODULE_TYPE_AUTO &&
IS_MODULES.test(
parseResource(module.matchResource || module.resource).path
)
) {
oldDefaultMode = this.defaultMode;
this.defaultMode = "local";
mode = "local";
}
const isModules = mode === "global" || mode === "local";
const locConverter = new LocConverter(source);
/** @type {Set<string>} */
const declaredCssVariables = new Set();
@ -239,8 +240,7 @@ class CssParser extends Parser {
* @returns {boolean} true, when in local scope
*/
const isLocalMode = () =>
modeData === "local" ||
(this.defaultMode === "local" && modeData === undefined);
modeData === "local" || (mode === "local" && modeData === undefined);
/**
* @param {string} chars characters
* @returns {(input: string, pos: number) => number} function to eat characters
@ -586,7 +586,7 @@ class CssParser extends Parser {
scope = CSS_MODE_IN_AT_IMPORT;
importData = { start };
} else if (
this.allowModeSwitch &&
isModules &&
OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE.test(name)
) {
let pos = end;
@ -614,7 +614,7 @@ class CssParser extends Parser {
}
pos = newPos;
return pos + 1;
} else if (this.allowModeSwitch && name === "@property") {
} else if (isModules && name === "@property") {
let pos = end;
pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
if (pos === input.length) return pos;
@ -661,7 +661,7 @@ class CssParser extends Parser {
modeData = isLocalMode() ? "local" : "global";
isNextRulePrelude = true;
return end;
} else if (this.allowModeSwitch) {
} else if (isModules) {
modeData = "global";
isNextRulePrelude = false;
}
@ -765,7 +765,7 @@ class CssParser extends Parser {
break;
}
case CSS_MODE_IN_BLOCK: {
if (this.allowModeSwitch) {
if (isModules) {
processDeclarationValueDone(input);
inAnimationProperty = false;
isNextRulePrelude = isNextNestedSyntax(input, end);
@ -782,7 +782,7 @@ class CssParser extends Parser {
scope = CSS_MODE_IN_BLOCK;
blockNestingLevel = 1;
if (this.allowModeSwitch) {
if (isModules) {
isNextRulePrelude = isNextNestedSyntax(input, end);
}
@ -791,7 +791,7 @@ class CssParser extends Parser {
case CSS_MODE_IN_BLOCK: {
blockNestingLevel++;
if (this.allowModeSwitch) {
if (isModules) {
isNextRulePrelude = isNextNestedSyntax(input, end);
}
break;
@ -809,11 +809,11 @@ class CssParser extends Parser {
if (--blockNestingLevel === 0) {
scope = CSS_MODE_TOP_LEVEL;
if (this.allowModeSwitch) {
if (isModules) {
isNextRulePrelude = true;
modeData = undefined;
}
} else if (this.allowModeSwitch) {
} else if (isModules) {
isNextRulePrelude = isNextNestedSyntax(input, end);
}
break;
@ -919,7 +919,7 @@ class CssParser extends Parser {
const popped = balanced.pop();
if (
this.allowModeSwitch &&
isModules &&
popped &&
(popped[0] === ":local" || popped[0] === ":global")
) {
@ -959,7 +959,7 @@ class CssParser extends Parser {
return end;
},
pseudoClass: (input, start, end) => {
if (this.allowModeSwitch) {
if (isModules) {
const name = input.slice(start, end).toLowerCase();
if (name === ":global") {
@ -998,7 +998,7 @@ class CssParser extends Parser {
balanced.push([name, start, end]);
if (this.allowModeSwitch) {
if (isModules) {
name = name.toLowerCase();
if (name === ":global") {
@ -1015,7 +1015,7 @@ class CssParser extends Parser {
return end;
},
comma: (input, start, end) => {
if (this.allowModeSwitch) {
if (isModules) {
// Reset stack for `:global .class :local .class-other` selector after
modeData = undefined;
@ -1033,10 +1033,6 @@ class CssParser extends Parser {
}
});
if (oldDefaultMode) {
this.defaultMode = oldDefaultMode;
}
/** @type {BuildInfo} */
(module.buildInfo).strict = true;
/** @type {BuildMeta} */

View File

@ -1,6 +1,8 @@
import './style.css';
import * as style1 from './style1.local.css'
import * as style2 from './style2.global.css'
import './style3.auto.css';
import * as style3 from './style4.modules.css'
it("should not parse css modules in type: css", () => {
const style = getComputedStyle(document.body);
@ -10,14 +12,14 @@ it("should not parse css modules in type: css", () => {
expect(css).toMatch(/\:local\(\.foo\)/);
expect(css).toMatch(/\:global\(\.bar\)/);
})
});
it("should compile type: css/module", () => {
const element = document.createElement(".class2");
const style = getComputedStyle(element);
expect(style.getPropertyValue("background")).toBe(" green");
expect(style1.class1).toBe('-_style1_local_css-class1');
})
});
it("should compile type: css/global", (done) => {
const element = document.createElement(".class3");
@ -25,4 +27,20 @@ it("should compile type: css/global", (done) => {
expect(style.getPropertyValue("color")).toBe(" red");
expect(style2.class4).toBe('-_style2_global_css-class4');
done()
})
});
it("should not parse css modules in type: css/auto", () => {
const style = getComputedStyle(document.body);
expect(style.getPropertyValue("background")).toBe(" red");
const links = document.getElementsByTagName("link");
const css = links[1].sheet.css;
expect(css).toMatch(/\:local\(\.baz\)/);
expect(css).toMatch(/\:global\(\.qux\)/);
});
it("should parse css modules in type: css/auto", () => {
const element = document.createElement(".class3");
const style = getComputedStyle(element);
expect(style.getPropertyValue("color")).toBe(" red");
expect(style3.class3).toBe('-_style4_modules_css-class3');
});

View File

@ -0,0 +1,11 @@
body {
background: red;
}
:local(.baz) {
color: red;
}
:global(.qux) {
color: green;
}

View File

@ -0,0 +1,6 @@
.class3 {
color: red;
}
:global(.class4) {
background: green;
}

View File

@ -15,6 +15,14 @@ module.exports = {
{
test: /\.global\.css$/i,
type: "css/global"
},
{
test: /\.auto\.css$/i,
type: "css/auto"
},
{
test: /\.modules\.css$/i,
type: "css/auto"
}
]
},