Skip to content

Commit

Permalink
fix: automatically rename class default to _default when named ex…
Browse files Browse the repository at this point in the history
…port is enabled (#1590)
  • Loading branch information
alexander-akait committed Apr 10, 2024
1 parent b162e25 commit d6c31a1
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 2 deletions.
8 changes: 7 additions & 1 deletion README.md
Expand Up @@ -1156,7 +1156,7 @@ Enables/disables ES modules named export for locals.

> **Warning**
>
> It is not allowed to use the `default` reserved word in css classes.
> Because it is not allowed to use the `default` class in CSS when the `namedExport` is `true` (since ECMA modules have a reserved keyword `default` for default export), it will be automatically renamed to the `_default` class.
**styles.css**

Expand All @@ -1167,6 +1167,9 @@ Enables/disables ES modules named export for locals.
.bar {
color: blue;
}
.default {
color: green;
}
```

**index.js**
Expand All @@ -1179,6 +1182,9 @@ console.log(styles["foo-baz"], styles.bar);

// If using `exportLocalsConvention: "camel-case-only"`:
console.log(styles.fooBaz, styles.bar);

// For the `default` classname
console.log(styles["_default"]);
```

You can enable a ES module named export using:
Expand Down
6 changes: 5 additions & 1 deletion src/utils.js
Expand Up @@ -1184,12 +1184,16 @@ function getExportCode(
? new Set(names)
: new Set([names]);

for (const name of normalizedNames) {
for (let name of normalizedNames) {
const serializedValue = isTemplateLiteralSupported
? convertToTemplateLiteral(value)
: JSON.stringify(value);

if (options.modules.namedExport) {
if (name === "default") {
name = `_${name}`;
}

if (!validIdentifier.test(name) || keywords.has(name)) {
identifierId += 1;

Expand Down
68 changes: 68 additions & 0 deletions test/__snapshots__/modules-option.test.js.snap
Expand Up @@ -12317,6 +12317,74 @@ exports[`"modules" option should work with \`@scope\` at-rule: result 1`] = `

exports[`"modules" option should work with \`@scope\` at-rule: warnings 1`] = `[]`;

exports[`"modules" option should work with \`default\` class and with named export: errors 1`] = `[]`;

exports[`"modules" option should work with \`default\` class and with named export: module 1`] = `
"// Imports
import ___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___ from "../../../../src/runtime/noSourceMaps.js";
import ___CSS_LOADER_API_IMPORT___ from "../../../../src/runtime/api.js";
var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___);
// Module
___CSS_LOADER_EXPORT___.push([module.id, \`.VP7CYSvMVRONwmJxbckO {
background: red
}
\`, ""]);
// Exports
export var _default = \`VP7CYSvMVRONwmJxbckO\`;
export default ___CSS_LOADER_EXPORT___;
"
`;

exports[`"modules" option should work with \`default\` class and with named export: result 1`] = `
[
[
"./modules/issue-1589/source.css",
".VP7CYSvMVRONwmJxbckO {
background: red
}
",
"",
],
]
`;

exports[`"modules" option should work with \`default\` class and with named export: warnings 1`] = `[]`;

exports[`"modules" option should work with \`default\` class and without named export: errors 1`] = `[]`;

exports[`"modules" option should work with \`default\` class and without named export: module 1`] = `
"// Imports
import ___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___ from "../../../../src/runtime/noSourceMaps.js";
import ___CSS_LOADER_API_IMPORT___ from "../../../../src/runtime/api.js";
var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___);
// Module
___CSS_LOADER_EXPORT___.push([module.id, \`.VP7CYSvMVRONwmJxbckO {
background: red
}
\`, ""]);
// Exports
___CSS_LOADER_EXPORT___.locals = {
"default": \`VP7CYSvMVRONwmJxbckO\`
};
export default ___CSS_LOADER_EXPORT___;
"
`;

exports[`"modules" option should work with \`default\` class and without named export: result 1`] = `
[
[
"./modules/issue-1589/source.css",
".VP7CYSvMVRONwmJxbckO {
background: red
}
",
"",
],
]
`;

exports[`"modules" option should work with \`default\` class and without named export: warnings 1`] = `[]`;

exports[`"modules" option should work with CSS nesting: errors 1`] = `[]`;

exports[`"modules" option should work with CSS nesting: module 1`] = `
Expand Down
3 changes: 3 additions & 0 deletions test/fixtures/modules/issue-1589/source.css
@@ -0,0 +1,3 @@
.default {
background: red
}
5 changes: 5 additions & 0 deletions test/fixtures/modules/issue-1589/source.js
@@ -0,0 +1,5 @@
import * as css from './source.css';

__export__ = css.default;

export default css;
35 changes: 35 additions & 0 deletions test/modules-option.test.js
Expand Up @@ -2657,4 +2657,39 @@ describe('"modules" option', () => {
expect(getWarnings(stats)).toMatchSnapshot("warnings");
expect(getErrors(stats)).toMatchSnapshot("errors");
});

it("should work with `default` class and without named export", async () => {
const compiler = getCompiler("./modules/issue-1589/source.js", {
modules: {
exportLocalsConvention: "as-is",
namedExport: false,
},
});
const stats = await compile(compiler);

expect(
getModuleSource("./modules/issue-1589/source.css", stats),
).toMatchSnapshot("module");
expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot(
"result",
);
expect(getWarnings(stats)).toMatchSnapshot("warnings");
expect(getErrors(stats)).toMatchSnapshot("errors");
});

it("should work with `default` class and with named export", async () => {
const compiler = getCompiler("./modules/issue-1589/source.js", {
modules: true,
});
const stats = await compile(compiler);

expect(
getModuleSource("./modules/issue-1589/source.css", stats),
).toMatchSnapshot("module");
expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot(
"result",
);
expect(getWarnings(stats)).toMatchSnapshot("warnings");
expect(getErrors(stats)).toMatchSnapshot("errors");
});
});

0 comments on commit d6c31a1

Please sign in to comment.