You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Aug 28, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Aug 28, 2026. It is now read-only.
getLocalIdent function no longer falls back to default implementation #1191
A getLocalIdent function that return a falsy value should fallback to the defaultGetLocalIdent function found in the utils.js.
Actual Behavior
With the 4.x release of css-loader, the behavior introduced in this pull request no longer works. A custom getLocalIdent function can no longer return a falsy value and have the default getLocalIdent function invoked.
I couldn't see any other convenient work arounds, like being able to import that default function and invoking it myself in my custom function.
Do not use getLocalIdent if you don't need custom generated local idents
I did not include the entire function, as to not bloat the issue report. I will say that I do need custom behavior in certain cases, for certain imports, but not always. Can you provide a work around so that I could still access the default getLocalIdent function? Could it just be exported and something I could pull into my custom function?
Alternatively, could having the custom implementation return an empty string be considered for triggering the old behavior that was lost?
No alternatives you should use own function or don't use the getLocalIdent option, in future we will escape returned values from getLocalIdent to avoid break CSS, so empty string will be valid as selector (we escape it)
If you found place where the default function doesn't generate valid CSS classname, please report about it and we will fix it
Nope, that wasn't the case. In this case, we converted an internal library that previously bundled its CSS with very specific class selector names to start shipping that library as a "loose" library, with unbundled CSS files.
To provide more details, we were using the getLocalIdent function to test if the current file was part of that previously bundled library and, if so, use a very specific naming pattern for the selectors. This was to preserve any behaviors consumers of the library were doing that was dependent on those class selectors being named in that fashion. Otherwise, if the currently processed file wasn't a special one, we were falling back to the default ident function.
I think we could accomplish the same behavior with additional rules in the webpack config, it was just very convenient to bundle all that logic into one rule.
We have 2 internal libraries that we consume in our frontend applications. One is a design system library, consisting of styled buttons and components like that. The other is a business-logic component library, one that has components most FE applications need, consisting of components like the user settings menu, log out, things like that.
Previously, we would bundle all the code and css up and have a consuming project use those bundles. In the bundled CSS we would add a very specific prefix to the selectors to namespace them. So button-input would become design-system-button-input. That very specific naming of the selectors was to allow the consuming app to override certain styles if they wanted.
Recently, we introduced tree shaking, so we started shipping unbundled sources in the packages. So now the consuming app is bundling all the CSS and generating the class selector names in its build. To preserve that old behavior of prefixing the design-system / business-logic library class selectors, we provide some Webpack config and utility functions. One such utility function was a custom getLocalIdent method. I've pasted a slightly anonymized version of that function below.
constgetLocalIdent=(context,localIdentName,localName)=>{if(shouldProcessAsDesignSystem(context.resourcePath)){if(context.resourcePath.includes('base.css')){// If using DS as a source library, we need to mangle the base.css names for backward compatibilityif(sourceLibraries.includes('design-system')){return`design-system-${localName}`;}// If using the packaged version, the names are already mangled appropriatelyreturnfalse;}// All other DS CSS uses this patternreturn`design-system-${path.parse(context.resourcePath).name}-${localName}`;}if(shouldProcessAsBusinessLogic(context.resourcePath)){return`business-logic-${path.parse(context.resourcePath).name}-${localName}`;}returnfalse;};
As you can see, we were using the falsy behavior the loader used to support to fall through to the default getLocalIdent function.
I can't say this is the most awesome thing we've ever done, but sometimes you go to production with the code you have! ;)
Activity
alexander-akait commentedon Sep 22, 2020
It is breaking change
getLocalIdentshould always return stringalexander-akait commentedon Sep 22, 2020
Do not use
getLocalIdentif you don't need custom generated local identstvsbrent commentedon Sep 22, 2020
I did not include the entire function, as to not bloat the issue report. I will say that I do need custom behavior in certain cases, for certain imports, but not always. Can you provide a work around so that I could still access the default
getLocalIdentfunction? Could it just be exported and something I could pull into my custom function?Alternatively, could having the custom implementation return an empty string be considered for triggering the old behavior that was lost?
alexander-akait commentedon Sep 22, 2020
No alternatives you should use own function or don't use the
getLocalIdentoption, in future we will escape returned values fromgetLocalIdentto avoid break CSS, so empty string will be valid as selector (we escape it)alexander-akait commentedon Sep 22, 2020
If you found place where the default function doesn't generate valid CSS classname, please report about it and we will fix it
tvsbrent commentedon Sep 22, 2020
Nope, that wasn't the case. In this case, we converted an internal library that previously bundled its CSS with very specific class selector names to start shipping that library as a "loose" library, with unbundled CSS files.
To provide more details, we were using the
getLocalIdentfunction to test if the current file was part of that previously bundled library and, if so, use a very specific naming pattern for the selectors. This was to preserve any behaviors consumers of the library were doing that was dependent on those class selectors being named in that fashion. Otherwise, if the currently processed file wasn't a special one, we were falling back to the default ident function.I think we could accomplish the same behavior with additional rules in the webpack config, it was just very convenient to bundle all that logic into one rule.
Anyway, thanks for the additional details.
alexander-akait commentedon Sep 22, 2020
@tvsbrent What is real use case? Why you need so complex logic?
tvsbrent commentedon Sep 22, 2020
We have 2 internal libraries that we consume in our frontend applications. One is a design system library, consisting of styled buttons and components like that. The other is a business-logic component library, one that has components most FE applications need, consisting of components like the user settings menu, log out, things like that.
Previously, we would bundle all the code and css up and have a consuming project use those bundles. In the bundled CSS we would add a very specific prefix to the selectors to namespace them. So
button-inputwould becomedesign-system-button-input. That very specific naming of the selectors was to allow the consuming app to override certain styles if they wanted.Recently, we introduced tree shaking, so we started shipping unbundled sources in the packages. So now the consuming app is bundling all the CSS and generating the class selector names in its build. To preserve that old behavior of prefixing the design-system / business-logic library class selectors, we provide some Webpack config and utility functions. One such utility function was a custom
getLocalIdentmethod. I've pasted a slightly anonymized version of that function below.As you can see, we were using the
falsybehavior the loader used to support to fall through to the defaultgetLocalIdentfunction.I can't say this is the most awesome thing we've ever done, but sometimes you go to production with the code you have! ;)
alexander-akait commentedon Sep 22, 2020
hm, okay, let's mark it as features, feel free to send a PR
alexander-akait commentedon Sep 22, 2020
Just interesting case what we should do with
truevaluealexander-akait commentedon Sep 23, 2020
Fixed, release will be in near future, we wait PostCSS 8 bugfix with
RootExitand visitors