From 62440a8e46065c3960534ea2d4ebe66ae59e0fd8 Mon Sep 17 00:00:00 2001 From: pstrh <16498471+pstrh@users.noreply.github.com> Date: Tue, 1 Feb 2022 08:38:29 +0100 Subject: [PATCH 1/2] Added app name as hash salt for css modules ident --- .../__tests__/getCSSModuleLocalIdent.test.js | 34 +++++++++++++++++-- .../react-dev-utils/getCSSModuleLocalIdent.js | 8 +++-- .../react-scripts/config/webpack.config.js | 4 +++ 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/packages/react-dev-utils/__tests__/getCSSModuleLocalIdent.test.js b/packages/react-dev-utils/__tests__/getCSSModuleLocalIdent.test.js index 6eb189eef85..51502a10290 100644 --- a/packages/react-dev-utils/__tests__/getCSSModuleLocalIdent.test.js +++ b/packages/react-dev-utils/__tests__/getCSSModuleLocalIdent.test.js @@ -11,7 +11,11 @@ const getCSSModuleLocalIdent = require('../getCSSModuleLocalIdent'); const rootContext = '/path'; const defaultClassName = 'class'; -const options = { context: undefined, hashPrefix: '', regExp: null }; +const defaultOptions = { + context: undefined, + hashSalt: undefined, + regExp: null, +}; const tests = [ { @@ -26,15 +30,41 @@ const tests = [ resourcePath: '/path/to/file.module.sass', expected: 'file_class__dINZX', }, + { + resourcePath: '/path/to/file.module.sass', + expected: 'file_class__9vVbt', + options: { + hashSalt: 'my-app', + }, + }, { resourcePath: '/path/to/file.name.module.css', expected: 'file_name_class__XpUJW', }, + { + resourcePath: '/path/to/file.name.module.css', + expected: 'file_name_class__OS1Yg', + options: { + hashSalt: 'my-app', + }, + }, + { + resourcePath: '/path/to/file.name.module.css', + expected: 'file_name_class__uMbcn', + options: { + hashSalt: 'my-app-123', + }, + }, ]; describe('getCSSModuleLocalIdent', () => { tests.forEach(test => { - const { className = defaultClassName, expected, resourcePath } = test; + const { + className = defaultClassName, + expected, + resourcePath, + options = defaultOptions, + } = test; it(JSON.stringify({ resourcePath, className }), () => { const ident = getCSSModuleLocalIdent( { diff --git a/packages/react-dev-utils/getCSSModuleLocalIdent.js b/packages/react-dev-utils/getCSSModuleLocalIdent.js index ce25305e7ef..843f7078b28 100644 --- a/packages/react-dev-utils/getCSSModuleLocalIdent.js +++ b/packages/react-dev-utils/getCSSModuleLocalIdent.js @@ -22,9 +22,13 @@ module.exports = function getLocalIdent( ) ? '[folder]' : '[name]'; - // Create a hash based on a the file location and class name. Will be unique across a project, and close to globally unique. + // Create a hash based on the relative file location, class name and hashSalt (if given). + // Will be unique across a project and globally unique with a suitable hashSalt. + const hashSalt = options.hashSalt || ''; const hash = loaderUtils.getHashDigest( - path.posix.relative(context.rootContext, context.resourcePath) + localName, + hashSalt + + path.posix.relative(context.rootContext, context.resourcePath) + + localName, 'md5', 'base64', 5 diff --git a/packages/react-scripts/config/webpack.config.js b/packages/react-scripts/config/webpack.config.js index 2b1b3bbd47d..034c8024722 100644 --- a/packages/react-scripts/config/webpack.config.js +++ b/packages/react-scripts/config/webpack.config.js @@ -95,6 +95,8 @@ const hasJsxRuntime = (() => { } })(); +const appName = require(paths.appPackageJson).name; + // This is the production and development configuration. // It is focused on developer experience, fast rebuilds, and a minimal bundle. module.exports = function (webpackEnv) { @@ -537,6 +539,7 @@ module.exports = function (webpackEnv) { modules: { mode: 'local', getLocalIdent: getCSSModuleLocalIdent, + localIdentHashSalt: appName, }, }), }, @@ -577,6 +580,7 @@ module.exports = function (webpackEnv) { modules: { mode: 'local', getLocalIdent: getCSSModuleLocalIdent, + localIdentHashSalt: appName, }, }, 'sass-loader' From 1781157b88d1132b541c8d8ff53a9a0efeafcb8b Mon Sep 17 00:00:00 2001 From: pstrh <16498471+pstrh@users.noreply.github.com> Date: Thu, 10 Feb 2022 16:59:38 +0100 Subject: [PATCH 2/2] Use base64url encoding for css modules local ident --- .../__tests__/getCSSModuleLocalIdent.test.js | 20 ++++++++++++++++++- .../react-dev-utils/getCSSModuleLocalIdent.js | 2 +- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/react-dev-utils/__tests__/getCSSModuleLocalIdent.test.js b/packages/react-dev-utils/__tests__/getCSSModuleLocalIdent.test.js index 51502a10290..a0b6c3661dc 100644 --- a/packages/react-dev-utils/__tests__/getCSSModuleLocalIdent.test.js +++ b/packages/react-dev-utils/__tests__/getCSSModuleLocalIdent.test.js @@ -55,6 +55,20 @@ const tests = [ hashSalt: 'my-app-123', }, }, + { + resourcePath: '/path/a/b/c/file.name.module.css', + className: 'test', + expected: 'file_name_test__2F_aq', + description: + 'Verifies that hash is encoded with base64url (2F_aq instead of 2F/aq)', + }, + { + resourcePath: '/path/a/b/file.name.module.css', + className: 'test', + expected: 'file_name_test__58Gc-', + description: + 'Verifies that hash is encoded with base64url (58Gc- instead of 58Gc+)', + }, ]; describe('getCSSModuleLocalIdent', () => { @@ -64,8 +78,12 @@ describe('getCSSModuleLocalIdent', () => { expected, resourcePath, options = defaultOptions, + description, } = test; - it(JSON.stringify({ resourcePath, className }), () => { + const testDescription = + description || JSON.stringify({ resourcePath, className }); + + it(testDescription, () => { const ident = getCSSModuleLocalIdent( { resourcePath, diff --git a/packages/react-dev-utils/getCSSModuleLocalIdent.js b/packages/react-dev-utils/getCSSModuleLocalIdent.js index 843f7078b28..944b9634de6 100644 --- a/packages/react-dev-utils/getCSSModuleLocalIdent.js +++ b/packages/react-dev-utils/getCSSModuleLocalIdent.js @@ -30,7 +30,7 @@ module.exports = function getLocalIdent( path.posix.relative(context.rootContext, context.resourcePath) + localName, 'md5', - 'base64', + 'base64url', 5 ); // Use loaderUtils to find the file or folder name