From 0902353c328d4d18e8ed2755fe9c83c03c53df81 Mon Sep 17 00:00:00 2001 From: Ben Scott <227292+BPScott@users.noreply.github.com> Date: Wed, 3 Jun 2020 10:20:50 -0700 Subject: [PATCH] feat: allow modules.auto to be a filter function (#1086) --- README.md | 28 +++++- src/options.json | 3 + src/utils.js | 4 + .../__snapshots__/modules-option.test.js.snap | 91 +++++++++++++++---- .../validate-options.test.js.snap | 14 +++ test/modules-option.test.js | 44 ++++++++- test/validate-options.test.js | 5 + 7 files changed, 167 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index d1b58a34..3b43ea6d 100644 --- a/README.md +++ b/README.md @@ -542,7 +542,7 @@ module.exports = { ##### `auto` -Type: `Boolean|RegExp` +Type: `Boolean|RegExp|Function` Default: `'undefined'` Allows auto enable css modules based on filename. @@ -576,7 +576,7 @@ module.exports = { ###### `RegExp` -Enable css modules for files based on a filename and satisfying your regex. +Enable css modules for files based on the filename satisfying your regex check. **webpack.config.js** @@ -598,6 +598,30 @@ module.exports = { }; ``` +###### `Function` + +Enable css modules for files based on the filename satisfying your filter function check. + +**webpack.config.js** + +```js +module.exports = { + module: { + rules: [ + { + test: /\.css$/i, + loader: 'css-loader', + options: { + modules: { + auto: (resourcePath) => resourcePath.endsWith('.custom-module.css'), + }, + }, + }, + ], + }, +}; +``` + ##### `mode` Type: `String|Function` diff --git a/src/options.json b/src/options.json index 6c8409b9..43ac0f9c 100644 --- a/src/options.json +++ b/src/options.json @@ -41,6 +41,9 @@ { "instanceof": "RegExp" }, + { + "instanceof": "Function" + }, { "type": "boolean" } diff --git a/src/utils.js b/src/utils.js index 45e8f7a9..8bc0a625 100644 --- a/src/utils.js +++ b/src/utils.js @@ -117,6 +117,10 @@ function shouldUseModulesPlugins(modules, resourcePath) { return modules.auto.test(resourcePath); } + if (typeof modules.auto === 'function') { + return modules.auto(resourcePath); + } + return true; } diff --git a/test/__snapshots__/modules-option.test.js.snap b/test/__snapshots__/modules-option.test.js.snap index 216b4ead..03f8436c 100644 --- a/test/__snapshots__/modules-option.test.js.snap +++ b/test/__snapshots__/modules-option.test.js.snap @@ -3148,9 +3148,9 @@ Array [ exports[`"modules" option should work when the "getLocalIdent" option returns "false": warnings 1`] = `Array []`; -exports[`"modules" option should work with a modules.auto equal "false": errors 1`] = `Array []`; +exports[`"modules" option should work with a modules.auto Boolean that is "false": errors 1`] = `Array []`; -exports[`"modules" option should work with a modules.auto equal "false": module 1`] = ` +exports[`"modules" option should work with a modules.auto Boolean that is "false": module 1`] = ` "// Imports var ___CSS_LOADER_API_IMPORT___ = require(\\"../../../../src/runtime/api.js\\"); exports = ___CSS_LOADER_API_IMPORT___(false); @@ -3161,7 +3161,7 @@ module.exports = exports; " `; -exports[`"modules" option should work with a modules.auto equal "false": result 1`] = ` +exports[`"modules" option should work with a modules.auto Boolean that is "false": result 1`] = ` Array [ Array [ "./modules/mode/relative.module.css", @@ -3174,11 +3174,11 @@ Array [ ] `; -exports[`"modules" option should work with a modules.auto equal "false": warnings 1`] = `Array []`; +exports[`"modules" option should work with a modules.auto Boolean that is "false": warnings 1`] = `Array []`; -exports[`"modules" option should work with a modules.auto equal "true": errors 1`] = `Array []`; +exports[`"modules" option should work with a modules.auto Boolean that is "true": errors 1`] = `Array []`; -exports[`"modules" option should work with a modules.auto equal "true": module 1`] = ` +exports[`"modules" option should work with a modules.auto Boolean that is "true": module 1`] = ` "// Imports var ___CSS_LOADER_API_IMPORT___ = require(\\"../../../../src/runtime/api.js\\"); exports = ___CSS_LOADER_API_IMPORT___(false); @@ -3192,7 +3192,7 @@ module.exports = exports; " `; -exports[`"modules" option should work with a modules.auto equal "true": result 1`] = ` +exports[`"modules" option should work with a modules.auto Boolean that is "true": result 1`] = ` Array [ Array [ "./modules/mode/relative.module.css", @@ -3205,11 +3205,11 @@ Array [ ] `; -exports[`"modules" option should work with a modules.auto equal "true": warnings 1`] = `Array []`; +exports[`"modules" option should work with a modules.auto Boolean that is "true": warnings 1`] = `Array []`; -exports[`"modules" option should work with a modules.auto returns "false": errors 1`] = `Array []`; +exports[`"modules" option should work with a modules.auto Function that returns "false": errors 1`] = `Array []`; -exports[`"modules" option should work with a modules.auto returns "false": module 1`] = ` +exports[`"modules" option should work with a modules.auto Function that returns "false": module 1`] = ` "// Imports var ___CSS_LOADER_API_IMPORT___ = require(\\"../../../../src/runtime/api.js\\"); exports = ___CSS_LOADER_API_IMPORT___(false); @@ -3220,7 +3220,7 @@ module.exports = exports; " `; -exports[`"modules" option should work with a modules.auto returns "false": result 1`] = ` +exports[`"modules" option should work with a modules.auto Function that returns "false": result 1`] = ` Array [ Array [ "./modules/mode/relative.module.css", @@ -3233,11 +3233,11 @@ Array [ ] `; -exports[`"modules" option should work with a modules.auto returns "false": warnings 1`] = `Array []`; +exports[`"modules" option should work with a modules.auto Function that returns "false": warnings 1`] = `Array []`; -exports[`"modules" option should work with a modules.auto returns "true": errors 1`] = `Array []`; +exports[`"modules" option should work with a modules.auto Function that returns "true": errors 1`] = `Array []`; -exports[`"modules" option should work with a modules.auto returns "true": module 1`] = ` +exports[`"modules" option should work with a modules.auto Function that returns "true": module 1`] = ` "// Imports var ___CSS_LOADER_API_IMPORT___ = require(\\"../../../../src/runtime/api.js\\"); exports = ___CSS_LOADER_API_IMPORT___(false); @@ -3251,7 +3251,7 @@ module.exports = exports; " `; -exports[`"modules" option should work with a modules.auto returns "true": result 1`] = ` +exports[`"modules" option should work with a modules.auto Function that returns "true": result 1`] = ` Array [ Array [ "./modules/mode/relative.module.css", @@ -3264,7 +3264,66 @@ Array [ ] `; -exports[`"modules" option should work with a modules.auto returns "true": warnings 1`] = `Array []`; +exports[`"modules" option should work with a modules.auto Function that returns "true": warnings 1`] = `Array []`; + +exports[`"modules" option should work with a modules.auto RegExp that returns "false": errors 1`] = `Array []`; + +exports[`"modules" option should work with a modules.auto RegExp that returns "false": module 1`] = ` +"// Imports +var ___CSS_LOADER_API_IMPORT___ = require(\\"../../../../src/runtime/api.js\\"); +exports = ___CSS_LOADER_API_IMPORT___(false); +// Module +exports.push([module.id, \\".relative {\\\\n color: red;\\\\n}\\\\n\\", \\"\\"]); +// Exports +module.exports = exports; +" +`; + +exports[`"modules" option should work with a modules.auto RegExp that returns "false": result 1`] = ` +Array [ + Array [ + "./modules/mode/relative.module.css", + ".relative { + color: red; +} +", + "", + ], +] +`; + +exports[`"modules" option should work with a modules.auto RegExp that returns "false": warnings 1`] = `Array []`; + +exports[`"modules" option should work with a modules.auto RegExp that returns "true": errors 1`] = `Array []`; + +exports[`"modules" option should work with a modules.auto RegExp that returns "true": module 1`] = ` +"// Imports +var ___CSS_LOADER_API_IMPORT___ = require(\\"../../../../src/runtime/api.js\\"); +exports = ___CSS_LOADER_API_IMPORT___(false); +// Module +exports.push([module.id, \\".y35Nud52-ZFXmqL6AWueX {\\\\n color: red;\\\\n}\\\\n\\", \\"\\"]); +// Exports +exports.locals = { + \\"relative\\": \\"y35Nud52-ZFXmqL6AWueX\\" +}; +module.exports = exports; +" +`; + +exports[`"modules" option should work with a modules.auto RegExp that returns "true": result 1`] = ` +Array [ + Array [ + "./modules/mode/relative.module.css", + ".y35Nud52-ZFXmqL6AWueX { + color: red; +} +", + "", + ], +] +`; + +exports[`"modules" option should work with a modules.auto RegExp that returns "true": warnings 1`] = `Array []`; exports[`"modules" option should work with case \`animation\` (\`modules\` value is \`false)\`: errors 1`] = `Array []`; diff --git a/test/__snapshots__/validate-options.test.js.snap b/test/__snapshots__/validate-options.test.js.snap index 08024272..b5e12dc9 100644 --- a/test/__snapshots__/validate-options.test.js.snap +++ b/test/__snapshots__/validate-options.test.js.snap @@ -43,6 +43,20 @@ exports[`validate options should throw an error on the "localsConvention" option -> Style of exported classnames (https://github.com/webpack-contrib/css-loader#localsconvention)." `; +exports[`validate options should throw an error on the "modules" option with "{"auto":"invalid"}" value 1`] = ` +"Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema. + - options.modules should be one of these: + boolean | \\"local\\" | \\"global\\" | \\"pure\\" | object { auto?, mode?, exportGlobals?, localIdentName?, localIdentRegExp?, context?, hashPrefix?, getLocalIdent? } + -> Enables/Disables CSS Modules and their configuration (https://github.com/webpack-contrib/css-loader#modules). + Details: + * options.modules.auto should be one of these: + RegExp | function | boolean + Details: + * options.modules.auto should be an instance of RegExp. + * options.modules.auto should be an instance of function. + * options.modules.auto should be a boolean." +`; + exports[`validate options should throw an error on the "modules" option with "{"context":true}" value 1`] = ` "Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema. - options.modules.context should be a string." diff --git a/test/modules-option.test.js b/test/modules-option.test.js index 23617a33..b26026bd 100644 --- a/test/modules-option.test.js +++ b/test/modules-option.test.js @@ -689,7 +689,7 @@ describe('"modules" option', () => { expect(getErrors(stats)).toMatchSnapshot('errors'); }); - it('should work with a modules.auto equal "false"', async () => { + it('should work with a modules.auto Boolean that is "false"', async () => { const compiler = getCompiler('./modules/mode/modules.js', { modules: { auto: false, @@ -707,7 +707,7 @@ describe('"modules" option', () => { expect(getErrors(stats)).toMatchSnapshot('errors'); }); - it('should work with a modules.auto equal "true"', async () => { + it('should work with a modules.auto Boolean that is "true"', async () => { const compiler = getCompiler('./modules/mode/modules.js', { modules: { auto: true, @@ -725,7 +725,7 @@ describe('"modules" option', () => { expect(getErrors(stats)).toMatchSnapshot('errors'); }); - it('should work with a modules.auto returns "true"', async () => { + it('should work with a modules.auto RegExp that returns "true"', async () => { const compiler = getCompiler('./modules/mode/modules.js', { modules: { auto: /relative.module.css$/, @@ -743,7 +743,7 @@ describe('"modules" option', () => { expect(getErrors(stats)).toMatchSnapshot('errors'); }); - it('should work with a modules.auto returns "false"', async () => { + it('should work with a modules.auto RegExp that returns "false"', async () => { const compiler = getCompiler('./modules/mode/modules.js', { modules: { auto: /will no pass/, @@ -760,4 +760,40 @@ describe('"modules" option', () => { expect(getWarnings(stats)).toMatchSnapshot('warnings'); expect(getErrors(stats)).toMatchSnapshot('errors'); }); + + it('should work with a modules.auto Function that returns "true"', async () => { + const compiler = getCompiler('./modules/mode/modules.js', { + modules: { + auto: (relativePath) => relativePath.endsWith('module.css'), + }, + }); + const stats = await compile(compiler); + + expect( + getModuleSource('./modules/mode/relative.module.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 a modules.auto Function that returns "false"', async () => { + const compiler = getCompiler('./modules/mode/modules.js', { + modules: { + auto: (relativePath) => relativePath.endsWith('will no pass'), + }, + }); + const stats = await compile(compiler); + + expect( + getModuleSource('./modules/mode/relative.module.css', stats) + ).toMatchSnapshot('module'); + expect(getExecutedCode('main.bundle.js', compiler, stats)).toMatchSnapshot( + 'result' + ); + expect(getWarnings(stats)).toMatchSnapshot('warnings'); + expect(getErrors(stats)).toMatchSnapshot('errors'); + }); }); diff --git a/test/validate-options.test.js b/test/validate-options.test.js index 96a595ce..40d5501a 100644 --- a/test/validate-options.test.js +++ b/test/validate-options.test.js @@ -28,6 +28,10 @@ describe('validate options', () => { { localIdentRegExp: 'page-(.*)\\.js' }, { localIdentRegExp: /page-(.*)\.js/ }, { exportGlobals: true }, + { auto: true }, + { auto: false }, + { auto: /custom-regex/ }, + { auto: () => true }, ], failure: [ 'true', @@ -44,6 +48,7 @@ describe('validate options', () => { { getLocalIdent: [] }, { localIdentRegExp: true }, { exportGlobals: 'invalid' }, + { auto: 'invalid' }, ], }, sourceMap: {