Skip to content

Commit 02d68ef

Browse files
committed
refactor: Determine CSS module by filename, not directory (#1714)
* refactor: Determine CSS module by filename, not directory * docs: Adding changeset * refactor: Project creation pull from templates 'main' branch * test: Updating tests * revert: Accidentally removed log message
1 parent 6fd8b4e commit 02d68ef

File tree

23 files changed

+94
-82
lines changed

23 files changed

+94
-82
lines changed

.changeset/cyan-tomatoes-count.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'preact-cli': major
3+
---
4+
5+
Alters CSS Module detection to instead rely upon file names, rather than directory names.
6+
7+
Treating all CSS files found within `routes/` and `components/` as CSS Modules was not obvious, nor did it offer an easy way to opt out (or in) without editing the Webpack config itself.
8+
9+
This change makes is so that users can opt into CSS Modules from anywhere in their app by instead naming their CSS files according to the pattern `*.module.css`.
10+
11+
Anyone using CSS Modules within `routes/` or `components/` will need to alter their CSS files to be `x.module.css`. If you've disabled CSS Modules in your `preact.config.js`, you can remove that bit of configuration and use file names to instead determine behavior.

packages/cli/global.d.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,16 @@ declare module 'shelljs' {
1515
};
1616
export = shell;
1717
}
18+
19+
declare module '*.module.css' {
20+
const classes: { [key: string]: string };
21+
export default classes;
22+
}
23+
declare module '*.module.sass' {
24+
const classes: { [key: string]: string };
25+
export default classes;
26+
}
27+
declare module '*.module.scss' {
28+
const classes: { [key: string]: string };
29+
export default classes;
30+
}

packages/cli/src/commands/create.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,11 @@ exports.create = async function createCommand(repo, dest, argv) {
221221
if (!repo.includes('/')) {
222222
repo = `${ORG}/${repo}`;
223223
info(`Assuming you meant ${repo}...`);
224+
225+
// TODO: Remove this after updating all templates
226+
if (repo.endsWith('default') || repo.endsWith('typescript')) {
227+
repo += '#next';
228+
}
224229
}
225230

226231
if (!existsSync(resolve(cwd, dest, 'src'))) {

packages/cli/src/lib/webpack/run-webpack.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ function writeJsonStats(cwd, stats) {
142142
function allFields(stats, field, fields = [], name = null) {
143143
const info = stats.toJson({
144144
errors: true,
145-
warnings: false,
145+
warnings: true,
146146
errorDetails: false,
147147
});
148148
const addCompilerPrefix = msg =>

packages/cli/src/lib/webpack/webpack-base-config.js

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ function resolveTsconfig(cwd, isProd) {
4949
* @returns {import('webpack').Configuration}
5050
*/
5151
module.exports = function createBaseConfig(env) {
52-
const { cwd, isProd, isWatch, src, source } = env;
52+
const { cwd, isProd, src, source } = env;
5353
const IS_SOURCE_PREACT_X_OR_ABOVE = isInstalledVersionPreactXOrAbove(cwd);
5454
// Apply base-level `env` values
5555
env.dest = resolve(cwd, env.dest || 'build');
@@ -214,20 +214,15 @@ module.exports = function createBaseConfig(env) {
214214
],
215215
},
216216
{
217-
// User styles
218217
test: /\.(p?css|less|s[ac]ss|styl)$/,
219-
include: [source('components'), source('routes')],
218+
exclude: /\.module\.(p?css|less|s[ac]ss|styl)$/,
220219
use: [
221-
isWatch
222-
? require.resolve('style-loader')
223-
: MiniCssExtractPlugin.loader,
220+
isProd
221+
? MiniCssExtractPlugin.loader
222+
: require.resolve('style-loader'),
224223
{
225224
loader: require.resolve('css-loader'),
226225
options: {
227-
modules: {
228-
localIdentName: '[local]__[hash:base64:5]',
229-
},
230-
importLoaders: 1,
231226
sourceMap: true,
232227
},
233228
},
@@ -241,18 +236,25 @@ module.exports = function createBaseConfig(env) {
241236
},
242237
},
243238
],
239+
// Don't consider CSS imports dead code even if the
240+
// containing package claims to have no side effects.
241+
// Remove this when webpack adds a warning or an error for this.
242+
// See https://github.com/webpack/webpack/issues/6571
243+
sideEffects: true,
244244
},
245245
{
246-
// External / `node_module` styles
247-
test: /\.(p?css|less|s[ac]ss|styl)$/,
248-
exclude: [source('components'), source('routes')],
246+
test: /\.module\.(p?css|less|s[ac]ss|styl)$/,
249247
use: [
250-
isWatch
251-
? require.resolve('style-loader')
252-
: MiniCssExtractPlugin.loader,
248+
isProd
249+
? MiniCssExtractPlugin.loader
250+
: require.resolve('style-loader'),
253251
{
254252
loader: require.resolve('css-loader'),
255253
options: {
254+
modules: {
255+
localIdentName: '[local]__[hash:base64:5]',
256+
},
257+
importLoaders: 1,
256258
sourceMap: true,
257259
},
258260
},
@@ -266,11 +268,6 @@ module.exports = function createBaseConfig(env) {
266268
},
267269
},
268270
],
269-
// Don't consider CSS imports dead code even if the
270-
// containing package claims to have no side effects.
271-
// Remove this when webpack adds a warning or an error for this.
272-
// See https://github.com/webpack/webpack/issues/6571
273-
sideEffects: true,
274271
},
275272
{
276273
test: /\.(xml|html|txt|md)$/,
@@ -349,7 +346,7 @@ module.exports = function createBaseConfig(env) {
349346

350347
mode: isProd ? 'production' : 'development',
351348

352-
devtool: isWatch ? 'eval-cheap-module-source-map' : 'source-map',
349+
devtool: isProd ? 'source-map' : 'eval-cheap-module-source-map',
353350

354351
node: {
355352
__filename: false,

packages/cli/tests/build.test.js

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,9 @@ describe('preact build', () => {
177177
await rename(join(dir, 'index.js'), join(dir, 'renamed-src/index.js'));
178178
await rename(join(dir, 'style.css'), join(dir, 'renamed-src/style.css'));
179179

180-
await expect(buildFast(dir, { src: 'renamed-src' })).resolves.not.toThrow();
180+
await expect(
181+
buildFast(dir, { src: 'renamed-src' })
182+
).resolves.not.toThrow();
181183
});
182184

183185
it('--dest', async () => {
@@ -361,18 +363,13 @@ describe('preact build', () => {
361363
expect(builtStylesheet).toMatch('h2{color:green}');
362364
});
363365

364-
it('should use CSS Modules in `routes` and `components` directories', async () => {
365-
let dir = await subject('css-auto-modules');
366+
it('should use plain CSS & CSS Modules together, determining loading method by filename', async () => {
367+
let dir = await subject('css-modules');
366368
await buildFast(dir);
367369
const builtStylesheet = await getOutputFile(dir, /bundle\.\w{5}\.css$/);
368-
const builtSplitStylesheet = await getOutputFile(
369-
dir,
370-
/route-index\.chunk\.\w{5}\.css$/
371-
);
372370

373371
expect(builtStylesheet).toMatch('h1{color:red}');
374-
expect(builtStylesheet).toMatch(/\.text__\w{5}{color:tan}/);
375-
expect(builtSplitStylesheet).toMatch(/\.text__\w{5}{color:red}/);
372+
expect(builtStylesheet).toMatch(/\.text__\w{5}{color:blue}/);
376373
});
377374

378375
it('should inline critical CSS only', async () => {
@@ -394,12 +391,14 @@ describe('preact build', () => {
394391
expect(builtStylesheet).toMatch('h1{background:#673ab8}');
395392
});
396393

397-
it('should use SASS styles', async () => {
394+
it('should use SASS, SCSS, and CSS Modules for each', async () => {
398395
let dir = await subject('css-sass');
399396
await buildFast(dir);
397+
const builtStylesheet = await getOutputFile(dir, /bundle\.\w{5}\.css$/);
400398

401-
let body = await getBody(dir);
402-
looksLike(body, images.sass);
399+
expect(builtStylesheet).toMatch('h1{background:blue;color:red}');
400+
expect(builtStylesheet).toMatch(/\.text__\w{5}{color:blue}/);
401+
expect(builtStylesheet).toMatch(/\.text__\w{5}{background:red}/);
403402
});
404403
});
405404

packages/cli/tests/images/build.js

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,6 @@ exports.default = {
4646
'route-profile.chunk.4de97.legacy.js.map': 15421,
4747
};
4848

49-
exports.sass = `
50-
<body>
51-
<div class="background__sL1ip">
52-
<h1>Header on background</h1>
53-
<p>Paragraph on background</p>
54-
</div>
55-
{{ ... }}
56-
</body>
57-
`;
58-
5949
exports.prerender = {};
6050

6151
exports.prerender.heads = {};

packages/cli/tests/images/create.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ exports.default = [
1515
'src/assets/preact-logo.svg',
1616
'src/components/app.js',
1717
'src/components/header/index.js',
18-
'src/components/header/style.css',
18+
'src/components/header/style.module.css',
1919
'src/index.js',
2020
'src/manifest.json',
2121
'src/routes/home/index.js',
22-
'src/routes/home/style.css',
22+
'src/routes/home/style.module.css',
2323
'src/routes/profile/index.js',
2424
'src/style/index.css',
2525
'src/sw.js',

packages/cli/tests/subjects/css-auto-modules/components/index.js

Lines changed: 0 additions & 4 deletions
This file was deleted.

packages/cli/tests/subjects/css-auto-modules/components/style.css

Lines changed: 0 additions & 3 deletions
This file was deleted.

0 commit comments

Comments
 (0)