Skip to content

Commit

Permalink
Css modules improved support (#2284)
Browse files Browse the repository at this point in the history
* Add CSSModules tests, fix configuration

* Add test cases
  • Loading branch information
onigoetz committed Feb 27, 2024
1 parent 8e8030f commit 4094e92
Show file tree
Hide file tree
Showing 19 changed files with 291 additions and 35 deletions.
31 changes: 15 additions & 16 deletions packages/crafty-preset-postcss/src/webpack-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,22 +70,20 @@ function getCssModuleLocalIdent(context, _, exportName, options) {
);
}

function extractCss(bundle, chain, styleRule) {
// Add this only once per bundle
if (bundle.extractCSSConfigured) {
return;
}
bundle.extractCSSConfigured = true;

function configureMiniCssExtractPlugin(bundle, chain) {
// Initialize extraction plugin
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

// Create a list of loaders that also contains the extraction loader
styleRule.use("style-loader").loader(MiniCssExtractPlugin.loader);
// Add plugin only once per bundle
if (!bundle.extractCSSConfigured) {
chain
.plugin("extractCSS")
.use(MiniCssExtractPlugin, [getExtractConfig(bundle)]);

chain
.plugin("extractCSS")
.use(MiniCssExtractPlugin, [getExtractConfig(bundle)]);
bundle.extractCSSConfigured = true;
}

return MiniCssExtractPlugin.loader;
}

function createRule(crafty, bundle, chain, styleRule, options) {
Expand All @@ -96,14 +94,15 @@ function createRule(crafty, bundle, chain, styleRule, options) {
// "style" loader turns CSS into JS modules that inject <style> tags.
// The "style" loader enables hot editing of CSS.

let styleLoader;
if (crafty.getEnvironment() === "production" && bundle.extractCSS) {
extractCss(bundle, chain, styleRule);
styleLoader = configureMiniCssExtractPlugin(bundle, chain);
} else {
styleRule
.use("style-loader")
.loader(require.resolve("../packages/style-loader.js"));
styleLoader = require.resolve("../packages/style-loader.js");
}

styleRule.use("style-loader").loader(styleLoader);

styleRule
.use("css-loader")
.loader(require.resolve("../packages/css-loader.js"))
Expand Down

Large diffs are not rendered by default.

Binary file not shown.
69 changes: 66 additions & 3 deletions packages/integration/__tests__/crafty-preset-postcss-webpack.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ test.serial(
t.truthy(testUtils.exists(cwd, "dist/js/myBundle-default.min.css"));
t.truthy(testUtils.exists(cwd, "dist/js/myBundle-default.min.css.map"));
t.snapshot(testUtils.readForSnapshot(cwd, BUNDLE));
t.snapshot(testUtils.readForSnapshot(cwd, BUNDLE));
t.snapshot(
testUtils.readForSnapshot(cwd, "dist/js/myBundle-default.min.css")
);
Expand All @@ -76,7 +75,6 @@ test.serial(
t.truthy(testUtils.exists(cwd, "dist/js/myBundle-string.min.css"));
t.truthy(testUtils.exists(cwd, "dist/js/myBundle-string.min.css.map"));

t.snapshot(testUtils.readForSnapshot(cwd, BUNDLE));
t.snapshot(testUtils.readForSnapshot(cwd, BUNDLE));
t.snapshot(
testUtils.readForSnapshot(cwd, "dist/js/myBundle-string.min.css")
Expand All @@ -101,10 +99,75 @@ test.serial(
t.truthy(testUtils.exists(cwd, "dist/js/myBundle-object.min.css"));
t.truthy(testUtils.exists(cwd, "dist/js/myBundle-object.min.css.map"));

t.snapshot(testUtils.readForSnapshot(cwd, BUNDLE));
t.snapshot(testUtils.readForSnapshot(cwd, BUNDLE));
t.snapshot(
testUtils.readForSnapshot(cwd, "dist/js/myBundle-object.min.css")
);
}
);

test.serial("Compiles CSS within webpack, CSS Modules, inline", async t => {
const cwd = await testUtils.getCleanFixtures(
"crafty-preset-postcss-webpack/modules-inline"
);

const result = await testUtils.run(["run", "default"], cwd);

t.snapshot(result);
t.is(result.status, 0);

t.truthy(testUtils.exists(cwd, BUNDLE));
t.truthy(testUtils.exists(cwd, BUNDLE_MAP));

const content = testUtils.readForSnapshot(cwd, BUNDLE);
t.snapshot(content);

t.truthy(content.indexOf(".Button{color") > -1);
t.truthy(content.indexOf(".t-global .app_app__") > -1);
t.truthy(content.indexOf(".t-global .app_app2__") > -1);

const subappContent = testUtils.readForSnapshot(
cwd,
"dist/js/subapp.myBundle.min.js"
);
t.snapshot(subappContent);

t.truthy(subappContent.indexOf("{color:orange}") > -1);
t.truthy(subappContent.indexOf(".subapp_") > -1);
});

test.serial(
"Compiles CSS within webpack, CSS Modules, extracts CSS",
async t => {
const cwd = await testUtils.getCleanFixtures(
"crafty-preset-postcss-webpack/modules-extract"
);

const result = await testUtils.run(["run", "default"], cwd);

t.snapshot(result);
t.is(result.status, 0);

t.truthy(testUtils.exists(cwd, BUNDLE));
t.truthy(testUtils.exists(cwd, BUNDLE_MAP));
t.truthy(testUtils.exists(cwd, "dist/js/default.myBundle.min.css"));
t.truthy(testUtils.exists(cwd, "dist/js/subapp.myBundle.min.css"));

const content = testUtils.readForSnapshot(
cwd,
"dist/js/default.myBundle.min.css"
);
t.snapshot(content);
t.truthy(content.indexOf(".Button{color") > -1);
t.truthy(content.indexOf(".t-global .app_app__") > -1);
t.truthy(content.indexOf(".t-global .app_app2__") > -1);

const subappContent = testUtils.readForSnapshot(
cwd,
"dist/js/subapp.myBundle.min.css"
);
t.snapshot(subappContent);
t.truthy(subappContent.indexOf("{color:orange}") > -1);
t.truthy(subappContent.indexOf(".subapp_") > -1);
}
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module.exports = {
presets: [
"@swissquote/crafty-preset-postcss",
"@swissquote/crafty-runner-webpack"
],
js: {
myBundle: {
source: "js/app.js",
extractCSS: "[name].[bundle].min.css"
}
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
:global .t-global {
:local .app {
color:red;
}
}

:global(.t-global) .app2 {
color: green;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.Button {
color: orange;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.subapp {
color:orange;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import "../css/style";
import style from "../css/app.module.css";

export default function app() {
console.log(style.app);

import(/* webpackChunkName: "subapp" */ "./subapp");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import style from "../css/subapp.module.css";

export default function subapp() {
console.log(style.subapp)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module.exports = {
presets: [
"@swissquote/crafty-preset-postcss",
"@swissquote/crafty-runner-webpack"
],
js: {
myBundle: {
source: "js/app.js",
//extractCSS: "[name].[bundle].min.css"
}
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
:global .t-global {
:local .app {
color:red;
}
}

:global(.t-global) .app2 {
color: green;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.Button {
color: orange;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.subapp {
color:orange;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import "../css/style";
import style from "../css/app.module.css";

export default function app() {
console.log(style.app);

import(/* webpackChunkName: "subapp" */ "./subapp");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import style from "../css/subapp.module.css";

export default function subapp() {
console.log(style.subapp)
}
2 changes: 1 addition & 1 deletion packages/stylelint-config-swissquote/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ module.exports = {
"property-no-unknown": true,
"selector-pseudo-class-no-unknown": [
true,
{ ignorePseudoClasses: ["global"] }
{ ignorePseudoClasses: ["global", "local"] }
],
"selector-pseudo-element-no-unknown": true,
"selector-pseudo-element-colon-notation": "single",
Expand Down
3 changes: 2 additions & 1 deletion packages/stylelint-config-swissquote/recommended.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,9 @@ module.exports = {
rules: {
// In css-modules, naming isn't as important,
// but as it's going to be used in JS, camelCase is best
// But in some cases, you might want to wrap a part in ":global" and this needs to support non-module patterns as well
"selector-class-pattern": [
/^[a-z][a-zA-Z0-9]+$/,
/^(_)?(?:(?:u|t|(?:i|ha)?s)+-[a-z$]+[a-zA-Z0-9$()]*|(?:[a-z$][a-zA-Z0-9$()]+-)?[A-Z$][a-zA-Z0-9$()]*(__[a-z0-9$][a-zA-Z0-9$()]*)*(--[a-z0-9$][a-zA-Z0-9$()]*)*)$|^[a-z][a-zA-Z0-9]+$/,
{
resolveNestedSelectors: true
}
Expand Down
24 changes: 24 additions & 0 deletions packages/stylelint-config-swissquote/src/__tests__/recommended.js
Original file line number Diff line number Diff line change
Expand Up @@ -411,3 +411,27 @@ test("flags warnings when using ids raised one 'selector-max-id' error", t => {
]);
});
});

test("Works with CSS Modules", t => {
const result = stylelint.lint({
code: `/** @define App */
:global .t-global {
:local .app {
color: red;
}
}
:global(.t-global) .app2 {
color: green;
}
`,
codeFilename: "app.module.css",
config
});

return result.then(data => {
t.falsy(data.errored);
t.is(data.results[0].warnings.length, 0);
});
});

0 comments on commit 4094e92

Please sign in to comment.