diff --git a/.changeset/cyan-tomatoes-count.md b/.changeset/cyan-tomatoes-count.md new file mode 100644 index 000000000..5a82bcac3 --- /dev/null +++ b/.changeset/cyan-tomatoes-count.md @@ -0,0 +1,11 @@ +--- +'preact-cli': major +--- + +Alters CSS Module detection to instead rely upon file names, rather than directory names. + +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. + +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`. + +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. diff --git a/packages/cli/global.d.ts b/packages/cli/global.d.ts index babb3438b..d45a4fcaf 100644 --- a/packages/cli/global.d.ts +++ b/packages/cli/global.d.ts @@ -15,3 +15,16 @@ declare module 'shelljs' { }; export = shell; } + +declare module '*.module.css' { + const classes: { [key: string]: string }; + export default classes; +} +declare module '*.module.sass' { + const classes: { [key: string]: string }; + export default classes; +} +declare module '*.module.scss' { + const classes: { [key: string]: string }; + export default classes; +} diff --git a/packages/cli/src/commands/create.js b/packages/cli/src/commands/create.js index 3b6f781a4..c01978d99 100644 --- a/packages/cli/src/commands/create.js +++ b/packages/cli/src/commands/create.js @@ -221,6 +221,11 @@ exports.create = async function createCommand(repo, dest, argv) { if (!repo.includes('/')) { repo = `${ORG}/${repo}`; info(`Assuming you meant ${repo}...`); + + // TODO: Remove this after updating all templates + if (repo.endsWith('default') || repo.endsWith('typescript')) { + repo += '#next'; + } } if (!existsSync(resolve(cwd, dest, 'src'))) { diff --git a/packages/cli/src/lib/webpack/run-webpack.js b/packages/cli/src/lib/webpack/run-webpack.js index 989303532..161848e3e 100644 --- a/packages/cli/src/lib/webpack/run-webpack.js +++ b/packages/cli/src/lib/webpack/run-webpack.js @@ -142,7 +142,7 @@ function writeJsonStats(cwd, stats) { function allFields(stats, field, fields = [], name = null) { const info = stats.toJson({ errors: true, - warnings: false, + warnings: true, errorDetails: false, }); const addCompilerPrefix = msg => diff --git a/packages/cli/src/lib/webpack/webpack-base-config.js b/packages/cli/src/lib/webpack/webpack-base-config.js index 8b76df71c..dde37df83 100644 --- a/packages/cli/src/lib/webpack/webpack-base-config.js +++ b/packages/cli/src/lib/webpack/webpack-base-config.js @@ -49,7 +49,7 @@ function resolveTsconfig(cwd, isProd) { * @returns {import('webpack').Configuration} */ module.exports = function createBaseConfig(env) { - const { cwd, isProd, isWatch, src, source } = env; + const { cwd, isProd, src, source } = env; const IS_SOURCE_PREACT_X_OR_ABOVE = isInstalledVersionPreactXOrAbove(cwd); // Apply base-level `env` values env.dest = resolve(cwd, env.dest || 'build'); @@ -214,20 +214,15 @@ module.exports = function createBaseConfig(env) { ], }, { - // User styles test: /\.(p?css|less|s[ac]ss|styl)$/, - include: [source('components'), source('routes')], + exclude: /\.module\.(p?css|less|s[ac]ss|styl)$/, use: [ - isWatch - ? require.resolve('style-loader') - : MiniCssExtractPlugin.loader, + isProd + ? MiniCssExtractPlugin.loader + : require.resolve('style-loader'), { loader: require.resolve('css-loader'), options: { - modules: { - localIdentName: '[local]__[hash:base64:5]', - }, - importLoaders: 1, sourceMap: true, }, }, @@ -241,18 +236,25 @@ module.exports = function createBaseConfig(env) { }, }, ], + // Don't consider CSS imports dead code even if the + // containing package claims to have no side effects. + // Remove this when webpack adds a warning or an error for this. + // See https://github.com/webpack/webpack/issues/6571 + sideEffects: true, }, { - // External / `node_module` styles - test: /\.(p?css|less|s[ac]ss|styl)$/, - exclude: [source('components'), source('routes')], + test: /\.module\.(p?css|less|s[ac]ss|styl)$/, use: [ - isWatch - ? require.resolve('style-loader') - : MiniCssExtractPlugin.loader, + isProd + ? MiniCssExtractPlugin.loader + : require.resolve('style-loader'), { loader: require.resolve('css-loader'), options: { + modules: { + localIdentName: '[local]__[hash:base64:5]', + }, + importLoaders: 1, sourceMap: true, }, }, @@ -266,11 +268,6 @@ module.exports = function createBaseConfig(env) { }, }, ], - // Don't consider CSS imports dead code even if the - // containing package claims to have no side effects. - // Remove this when webpack adds a warning or an error for this. - // See https://github.com/webpack/webpack/issues/6571 - sideEffects: true, }, { test: /\.(xml|html|txt|md)$/, @@ -349,7 +346,7 @@ module.exports = function createBaseConfig(env) { mode: isProd ? 'production' : 'development', - devtool: isWatch ? 'eval-cheap-module-source-map' : 'source-map', + devtool: isProd ? 'source-map' : 'eval-cheap-module-source-map', node: { __filename: false, diff --git a/packages/cli/tests/build.test.js b/packages/cli/tests/build.test.js index 650e18421..316de7e35 100644 --- a/packages/cli/tests/build.test.js +++ b/packages/cli/tests/build.test.js @@ -177,7 +177,9 @@ describe('preact build', () => { await rename(join(dir, 'index.js'), join(dir, 'renamed-src/index.js')); await rename(join(dir, 'style.css'), join(dir, 'renamed-src/style.css')); - await expect(buildFast(dir, { src: 'renamed-src' })).resolves.not.toThrow(); + await expect( + buildFast(dir, { src: 'renamed-src' }) + ).resolves.not.toThrow(); }); it('--dest', async () => { @@ -361,18 +363,13 @@ describe('preact build', () => { expect(builtStylesheet).toMatch('h2{color:green}'); }); - it('should use CSS Modules in `routes` and `components` directories', async () => { - let dir = await subject('css-auto-modules'); + it('should use plain CSS & CSS Modules together, determining loading method by filename', async () => { + let dir = await subject('css-modules'); await buildFast(dir); const builtStylesheet = await getOutputFile(dir, /bundle\.\w{5}\.css$/); - const builtSplitStylesheet = await getOutputFile( - dir, - /route-index\.chunk\.\w{5}\.css$/ - ); expect(builtStylesheet).toMatch('h1{color:red}'); - expect(builtStylesheet).toMatch(/\.text__\w{5}{color:tan}/); - expect(builtSplitStylesheet).toMatch(/\.text__\w{5}{color:red}/); + expect(builtStylesheet).toMatch(/\.text__\w{5}{color:blue}/); }); it('should inline critical CSS only', async () => { @@ -394,12 +391,14 @@ describe('preact build', () => { expect(builtStylesheet).toMatch('h1{background:#673ab8}'); }); - it('should use SASS styles', async () => { + it('should use SASS, SCSS, and CSS Modules for each', async () => { let dir = await subject('css-sass'); await buildFast(dir); + const builtStylesheet = await getOutputFile(dir, /bundle\.\w{5}\.css$/); - let body = await getBody(dir); - looksLike(body, images.sass); + expect(builtStylesheet).toMatch('h1{background:blue;color:red}'); + expect(builtStylesheet).toMatch(/\.text__\w{5}{color:blue}/); + expect(builtStylesheet).toMatch(/\.text__\w{5}{background:red}/); }); }); diff --git a/packages/cli/tests/images/build.js b/packages/cli/tests/images/build.js index 671fdb3aa..2a110cb65 100644 --- a/packages/cli/tests/images/build.js +++ b/packages/cli/tests/images/build.js @@ -46,16 +46,6 @@ exports.default = { 'route-profile.chunk.4de97.legacy.js.map': 15421, }; -exports.sass = ` -
-Paragraph on background
-Paragraph on background
-