diff --git a/changelogs/CHANGELOG_alpha.md b/changelogs/CHANGELOG_alpha.md index 37689852aa..818f6e47b4 100644 --- a/changelogs/CHANGELOG_alpha.md +++ b/changelogs/CHANGELOG_alpha.md @@ -1,3 +1,10 @@ +## [9.1.1-alpha.1](https://github.com/parse-community/parse-dashboard/compare/9.1.0...9.1.1-alpha.1) (2026-04-07) + + +### Bug Fixes + +* Broken CSS styling for components with underscore class names ([#3328](https://github.com/parse-community/parse-dashboard/issues/3328)) ([2048abe](https://github.com/parse-community/parse-dashboard/commit/2048abe1322f27f08497d62f141c2540cf7a4eb6)) + # [9.1.0-alpha.12](https://github.com/parse-community/parse-dashboard/compare/9.1.0-alpha.11...9.1.0-alpha.12) (2026-04-07) diff --git a/changelogs/CHANGELOG_release.md b/changelogs/CHANGELOG_release.md index c40927e234..0f167168f7 100644 --- a/changelogs/CHANGELOG_release.md +++ b/changelogs/CHANGELOG_release.md @@ -1,3 +1,10 @@ +## [9.1.1](https://github.com/parse-community/parse-dashboard/compare/9.1.0...9.1.1) (2026-04-07) + + +### Bug Fixes + +* Broken CSS styling for components with underscore class names ([#3328](https://github.com/parse-community/parse-dashboard/issues/3328)) ([2048abe](https://github.com/parse-community/parse-dashboard/commit/2048abe1322f27f08497d62f141c2540cf7a4eb6)) + # [9.1.0](https://github.com/parse-community/parse-dashboard/compare/9.0.0...9.1.0) (2026-04-07) diff --git a/package-lock.json b/package-lock.json index 6889b43046..b5a3b26063 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "parse-dashboard", - "version": "9.1.0", + "version": "9.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "parse-dashboard", - "version": "9.1.0", + "version": "9.1.1", "license": "SEE LICENSE IN LICENSE", "dependencies": { "@babel/runtime": "7.29.2", diff --git a/package.json b/package.json index 23c47d68e0..2529f4af0f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-dashboard", - "version": "9.1.0", + "version": "9.1.1", "repository": { "type": "git", "url": "https://github.com/parse-community/parse-dashboard" diff --git a/src/lib/tests/CssModules.test.js b/src/lib/tests/CssModules.test.js new file mode 100644 index 0000000000..d767c70780 --- /dev/null +++ b/src/lib/tests/CssModules.test.js @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2016-present, Parse, LLC + * All rights reserved. + * + * This source code is licensed under the license found in the LICENSE file in + * the root directory of this source tree. + */ + +const webpack = require('webpack'); +const path = require('path'); +const fs = require('fs'); +const os = require('os'); + +function runWebpack(config) { + return new Promise((resolve, reject) => { + webpack(config, (err, stats) => { + if (err) { + return reject(err); + } + if (stats.hasErrors()) { + return reject(new Error(stats.toJson().errors.map(e => e.message).join('\n'))); + } + resolve(stats); + }); + }); +} + +describe('CSS modules', () => { + let tmpDir; + + beforeAll(() => { + tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'css-modules-test-')); + + fs.writeFileSync( + path.join(tmpDir, 'test.scss'), + '.test_underscore_class { color: red; }\n.testCamelCase { color: blue; }\n' + ); + + fs.writeFileSync( + path.join(tmpDir, 'entry.js'), + 'const styles = require("./test.scss");\n' + ); + }); + + afterAll(() => { + fs.rmSync(tmpDir, { recursive: true, force: true }); + }); + + it('preserves underscore class names in exports', async () => { + const baseConfig = require('../../../webpack/base.config.js'); + const scssRule = baseConfig.module.rules.find(r => r.test.toString().includes('scss')); + + await runWebpack({ + mode: 'production', + entry: path.join(tmpDir, 'entry.js'), + output: { + path: tmpDir, + filename: 'bundle.js', + }, + module: { + rules: [{ test: /\.scss$/, use: scssRule.use }], + }, + }); + + const bundle = fs.readFileSync(path.join(tmpDir, 'bundle.js'), 'utf8'); + + // Class names with underscores must be preserved as-is in the JS exports, + // not converted to camelCase (e.g. testUnderscoreClass). + // This broke when css-loader was bumped from v6 to v7, which changed the + // default exportLocalsConvention from 'asIs' to 'camelCaseOnly'. + expect(bundle).toContain('test_underscore_class'); + expect(bundle).toContain('testCamelCase'); + }, 30000); +}); diff --git a/webpack/base.config.js b/webpack/base.config.js index a91a1af961..f4fedef00c 100644 --- a/webpack/base.config.js +++ b/webpack/base.config.js @@ -50,6 +50,7 @@ module.exports = { options: { modules: { namedExport: false, + exportLocalsConvention: 'as-is', }, importLoaders: 2, },