mirror of https://github.com/webpack/webpack.git
fix: `css/auto` considers a module depending on its filename as `css` (pure CSS) or `css/local`
This commit is contained in:
commit
94feb93752
|
|
@ -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", () => {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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} */
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
body {
|
||||
background: red;
|
||||
}
|
||||
|
||||
:local(.baz) {
|
||||
color: red;
|
||||
}
|
||||
|
||||
:global(.qux) {
|
||||
color: green;
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
.class3 {
|
||||
color: red;
|
||||
}
|
||||
:global(.class4) {
|
||||
background: green;
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue