Skip to content

Added app name as hash salt for css modules ident #12013

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 51 additions & 3 deletions packages/react-dev-utils/__tests__/getCSSModuleLocalIdent.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With ccs-loader v6 / webpack v5 hashPrefix was removed in favor of hashSalt. hashSalt is undefined by default.


const tests = [
{
Expand All @@ -26,16 +30,60 @@ 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',
},
},
{
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', () => {
tests.forEach(test => {
const { className = defaultClassName, expected, resourcePath } = test;
it(JSON.stringify({ resourcePath, className }), () => {
const {
className = defaultClassName,
expected,
resourcePath,
options = defaultOptions,
description,
} = test;
const testDescription =
description || JSON.stringify({ resourcePath, className });

it(testDescription, () => {
const ident = getCSSModuleLocalIdent(
{
resourcePath,
Expand Down
10 changes: 7 additions & 3 deletions packages/react-dev-utils/getCSSModuleLocalIdent.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,15 @@ 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',
'base64url',
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixes #11775. base64url encoding (introduced in node 14) prevents + and / in generated hashes.

5
);
// Use loaderUtils to find the file or folder name
Expand Down
4 changes: 4 additions & 0 deletions packages/react-scripts/config/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -537,6 +539,7 @@ module.exports = function (webpackEnv) {
modules: {
mode: 'local',
getLocalIdent: getCSSModuleLocalIdent,
localIdentHashSalt: appName,
},
}),
},
Expand Down Expand Up @@ -577,6 +580,7 @@ module.exports = function (webpackEnv) {
modules: {
mode: 'local',
getLocalIdent: getCSSModuleLocalIdent,
localIdentHashSalt: appName,
},
},
'sass-loader'
Expand Down