From 0f9584135e63f9f354043e7f414e0c1aad0edc6e Mon Sep 17 00:00:00 2001 From: Brent Schmidt Date: Wed, 23 Sep 2020 10:05:22 -0400 Subject: [PATCH] feat: add fallback if custom getLocalIdent returns null (#1193) --- README.md | 4 +- src/utils.js | 31 ++++++++++--- .../__snapshots__/modules-option.test.js.snap | 43 +++++++++++++++++++ .../modules/issue-1191/issue-1191-custom.css | 3 ++ .../modules/issue-1191/issue-1191.css | 3 ++ .../fixtures/modules/issue-1191/issue-1191.js | 8 ++++ test/modules-option.test.js | 22 ++++++++++ 7 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 test/fixtures/modules/issue-1191/issue-1191-custom.css create mode 100644 test/fixtures/modules/issue-1191/issue-1191.css create mode 100644 test/fixtures/modules/issue-1191/issue-1191.js diff --git a/README.md b/README.md index ce5984a6..9eaae51d 100644 --- a/README.md +++ b/README.md @@ -848,6 +848,8 @@ Default: `undefined` Allows to specify a function to generate the classname. By default we use built-in function to generate a classname. +If the custom function returns `null` or `undefined`, we fallback to the +built-in function to generate the classname. **webpack.config.js** @@ -1245,7 +1247,7 @@ module.exports = { ### Separating `Interoperable CSS`-only and `CSS Module` features -The following setup is an example of allowing `Interoperable CSS` features only (such as `:import` and `:export`) without using further `CSS Module` functionality by setting `compileType` option for all files that do not match `*.module.scss` naming convention. This is for reference as having `ICSS` features applied to all files was default `css-loader` behavior before v4. +The following setup is an example of allowing `Interoperable CSS` features only (such as `:import` and `:export`) without using further `CSS Module` functionality by setting `compileType` option for all files that do not match `*.module.scss` naming convention. This is for reference as having `ICSS` features applied to all files was default `css-loader` behavior before v4. Meanwhile all files matching `*.module.scss` are treated as `CSS Modules` in this example. An example case is assumed where a project requires canvas drawing variables to be synchronized with CSS - canvas drawing uses the same color (set by color name in JavaScript) as HTML background (set by class name in CSS). diff --git a/src/utils.js b/src/utils.js index ca167e22..218c0b73 100644 --- a/src/utils.js +++ b/src/utils.js @@ -281,11 +281,32 @@ function getModulesPlugins(options, loaderContext) { extractImports(), modulesScope({ generateScopedName(exportName) { - return getLocalIdent(loaderContext, localIdentName, exportName, { - context: localIdentContext, - hashPrefix: localIdentHashPrefix, - regExp: localIdentRegExp, - }); + let localIdent = getLocalIdent( + loaderContext, + localIdentName, + exportName, + { + context: localIdentContext, + hashPrefix: localIdentHashPrefix, + regExp: localIdentRegExp, + } + ); + + // A null/undefined value signals that we should invoke the default + // getLocalIdent method. + if (localIdent == null) { + localIdent = defaultGetLocalIdent( + loaderContext, + localIdentName, + exportName, + { + context: localIdentContext, + hashPrefix: localIdentHashPrefix, + regExp: localIdentRegExp, + } + ); + } + return localIdent; }, exportGlobals: options.modules.exportGlobals, }), diff --git a/test/__snapshots__/modules-option.test.js.snap b/test/__snapshots__/modules-option.test.js.snap index b57716f7..da337d58 100644 --- a/test/__snapshots__/modules-option.test.js.snap +++ b/test/__snapshots__/modules-option.test.js.snap @@ -487,6 +487,49 @@ exports[`"modules" option issue #1063: result 1`] = ` exports[`"modules" option issue #1063: warnings 1`] = `Array []`; +exports[`"modules" option issue #1191 - fallback to default getLocalIdent: errors 1`] = `Array []`; + +exports[`"modules" option issue #1191 - fallback to default getLocalIdent: module 1`] = ` +"// Imports +import ___CSS_LOADER_API_IMPORT___ from \\"../../../../src/runtime/api.js\\"; +var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(false); +// Module +___CSS_LOADER_EXPORT___.push([module.id, \\".some-class {\\\\n color: red;\\\\n}\\\\n\\", \\"\\"]); +// Exports +___CSS_LOADER_EXPORT___.locals = { + \\"some-class\\": \\"some-class\\" +}; +export default ___CSS_LOADER_EXPORT___; +" +`; + +exports[`"modules" option issue #1191 - fallback to default getLocalIdent: result 1`] = ` +Object { + "css1": Array [ + Array [ + "./modules/issue-1191/issue-1191.css", + ".some-class { + color: red; +} +", + "", + ], + ], + "css2": Array [ + Array [ + "./modules/issue-1191/issue-1191-custom.css", + ".custom-some-class { + color: red; +} +", + "", + ], + ], +} +`; + +exports[`"modules" option issue #1191 - fallback to default getLocalIdent: warnings 1`] = `Array []`; + exports[`"modules" option should avoid unnecessary "require": errors 1`] = `Array []`; exports[`"modules" option should avoid unnecessary "require": module 1`] = ` diff --git a/test/fixtures/modules/issue-1191/issue-1191-custom.css b/test/fixtures/modules/issue-1191/issue-1191-custom.css new file mode 100644 index 00000000..b58cc07a --- /dev/null +++ b/test/fixtures/modules/issue-1191/issue-1191-custom.css @@ -0,0 +1,3 @@ +.some-class { + color: red; +} diff --git a/test/fixtures/modules/issue-1191/issue-1191.css b/test/fixtures/modules/issue-1191/issue-1191.css new file mode 100644 index 00000000..b58cc07a --- /dev/null +++ b/test/fixtures/modules/issue-1191/issue-1191.css @@ -0,0 +1,3 @@ +.some-class { + color: red; +} diff --git a/test/fixtures/modules/issue-1191/issue-1191.js b/test/fixtures/modules/issue-1191/issue-1191.js new file mode 100644 index 00000000..940dbfb1 --- /dev/null +++ b/test/fixtures/modules/issue-1191/issue-1191.js @@ -0,0 +1,8 @@ +import css1 from './issue-1191.css'; +import css2 from './issue-1191-custom.css'; + +const wrapper = { css1, css2 } + +__export__ = wrapper; + +export default wrapper; diff --git a/test/modules-option.test.js b/test/modules-option.test.js index a31c2f19..0a7f4b02 100644 --- a/test/modules-option.test.js +++ b/test/modules-option.test.js @@ -657,6 +657,28 @@ describe('"modules" option', () => { expect(getErrors(stats)).toMatchSnapshot('errors'); }); + it('issue #1191 - fallback to default getLocalIdent', async () => { + const compiler = getCompiler('./modules/issue-1191/issue-1191.js', { + modules: { + getLocalIdent: (ctx, localIdentName, localName) => + ctx.resourcePath.includes('custom') ? `custom-${localName}` : null, + localIdentName: '[local]', + }, + }); + const stats = await compile(compiler); + + expect( + getModuleSource('./modules/issue-1191/issue-1191.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 the `exportGlobals` option (the `mode` option is `global`)', async () => { const compiler = getCompiler( './modules/exportGlobals-global/exportGlobals.js',