Skip to content

Commit 8e05ef2

Browse files
authored
Add include and exclude globs for CSS modules (#9301)
1 parent 1a3a254 commit 8e05ef2

File tree

2 files changed

+94
-9
lines changed

2 files changed

+94
-9
lines changed

packages/core/integration-tests/test/css-modules.js

+43
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
assertBundles,
88
distDir,
99
outputFS,
10+
overlayFS,
11+
fsFixture,
1012
} from '@parcel/test-utils';
1113
import postcss from 'postcss';
1214

@@ -776,4 +778,45 @@ describe('css modules', () => {
776778
},
777779
]);
778780
});
781+
782+
it('should support the "include" and "exclude" options', async function () {
783+
await fsFixture(overlayFS, __dirname)`
784+
css-module-include
785+
a.css:
786+
.foo { color: red }
787+
modules/b.css:
788+
.bar { color: yellow }
789+
modules/_c.css:
790+
.baz { color: pink }
791+
index.js:
792+
import './a.css';
793+
import {bar} from './modules/b.css';
794+
import './modules/_c.css';
795+
export default bar;
796+
797+
package.json:
798+
{
799+
"@parcel/transformer-css": {
800+
"cssModules": {
801+
"include": "modules/*.css",
802+
"exclude": "modules/_*.css"
803+
}
804+
}
805+
}
806+
807+
yarn.lock:`;
808+
809+
let b = await bundle(path.join(__dirname, 'css-module-include/index.js'), {
810+
mode: 'production',
811+
inputFS: overlayFS,
812+
});
813+
814+
let contents = await outputFS.readFile(
815+
b.getBundles().find(b => b.type === 'css').filePath,
816+
'utf8',
817+
);
818+
assert(contents.includes('.foo'));
819+
assert(contents.includes('.rp85ja_bar'));
820+
assert(contents.includes('.baz'));
821+
});
779822
});

packages/transformers/css/src/CSSTransformer.js

+51-9
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@ import {
1111
browserslistToTargets,
1212
type SourceLocation as LightningSourceLocation,
1313
} from 'lightningcss';
14-
import {remapSourceLocation, relativePath} from '@parcel/utils';
14+
import {
15+
remapSourceLocation,
16+
relativePath,
17+
globToRegex,
18+
normalizeSeparators,
19+
} from '@parcel/utils';
1520
import browserslist from 'browserslist';
1621
import nullthrows from 'nullthrows';
1722
import ThrowableDiagnostic, {errorToDiagnostic} from '@parcel/diagnostic';
@@ -21,7 +26,22 @@ export default (new Transformer({
2126
let conf = await config.getConfigFrom(options.projectRoot + '/index', [], {
2227
packageKey: '@parcel/transformer-css',
2328
});
24-
return conf?.contents;
29+
let contents = conf?.contents;
30+
if (typeof contents?.cssModules?.include === 'string') {
31+
contents.cssModules.include = [globToRegex(contents.cssModules.include)];
32+
} else if (Array.isArray(contents?.cssModules?.include)) {
33+
contents.cssModules.include = contents.cssModules.include.map(include =>
34+
typeof include === 'string' ? globToRegex(include) : include,
35+
);
36+
}
37+
if (typeof contents?.cssModules?.exclude === 'string') {
38+
contents.cssModules.exclude = [globToRegex(contents.cssModules.exclude)];
39+
} else if (Array.isArray(contents?.cssModules?.exclude)) {
40+
contents.cssModules.exclude = contents.cssModules.exclude.map(exclude =>
41+
typeof exclude === 'string' ? globToRegex(exclude) : exclude,
42+
);
43+
}
44+
return contents;
2545
},
2646
async transform({asset, config, options, logger}) {
2747
// Normalize the asset's environment so that properties that only affect JS don't cause CSS to be duplicated.
@@ -59,12 +79,32 @@ export default (new Transformer({
5979
asset.meta.cssModulesCompiled == null
6080
) {
6181
let cssModulesConfig = config?.cssModules;
62-
if (
63-
(asset.isSource &&
64-
(typeof cssModulesConfig === 'boolean' ||
65-
cssModulesConfig?.global)) ||
66-
/\.module\./.test(asset.filePath)
67-
) {
82+
let isCSSModule = /\.module\./.test(asset.filePath);
83+
if (asset.isSource) {
84+
let projectRootPath = path.relative(
85+
options.projectRoot,
86+
asset.filePath,
87+
);
88+
if (typeof cssModulesConfig === 'boolean') {
89+
isCSSModule = true;
90+
} else if (cssModulesConfig?.include) {
91+
isCSSModule = cssModulesConfig.include.some(include =>
92+
include.test(projectRootPath),
93+
);
94+
} else if (cssModulesConfig?.global) {
95+
isCSSModule = true;
96+
}
97+
98+
if (
99+
cssModulesConfig?.exclude?.some(exclude =>
100+
exclude.test(projectRootPath),
101+
)
102+
) {
103+
isCSSModule = false;
104+
}
105+
}
106+
107+
if (isCSSModule) {
68108
if (cssModulesConfig?.dashedIdents && !asset.isSource) {
69109
cssModulesConfig.dashedIdents = false;
70110
}
@@ -74,7 +114,9 @@ export default (new Transformer({
74114
}
75115

76116
res = transform({
77-
filename: path.relative(options.projectRoot, asset.filePath),
117+
filename: normalizeSeparators(
118+
path.relative(options.projectRoot, asset.filePath),
119+
),
78120
code,
79121
cssModules,
80122
analyzeDependencies: asset.meta.hasDependencies !== false,

0 commit comments

Comments
 (0)