[heft-sass-plugin] Fix JS shims and .d.ts for .module.scss files with only :global styles#5766
Merged
iclanton merged 1 commit intomicrosoft:mainfrom Apr 10, 2026
Merged
Conversation
… only :global styles
When a .module.scss file contains only :global selectors (no local CSS
class names), postcss-modules produces an empty moduleMap. The plugin
was still generating `export { default } from "./file.css"` shims and
`export default styles` .d.ts declarations for these files, but the
downstream CSS loader emits no default export when there are no local
classes, causing webpack to warn "export 'default' was not found
(module has no exports)".
Fix: treat an empty moduleMap the same as a non-module file — emit
side-effect-only shims (`import "./file.css"; export {}` / `require(...)`)
and `export {};` in the .d.ts. Adds a global-only.module.scss fixture
and four new tests covering this pattern.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
dmichon-msft
approved these changes
Apr 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
heft-sass-plugingenerates JS shim files (.scss.js) and TypeScriptdeclarations (
.scss.d.ts) alongside each compiled CSS file. For.module.scssfiles the shim re-exports the CSS module's
defaultexport so that bundlers likewebpack can resolve the class-name mapping object at runtime.
This breaks when a
.module.scssfile contains only:globalstyles — i.e.no locally-scoped CSS class names. In that case downstream CSS loaders (such as
SharePoint's
sp-css-loader) emit no default export from the compiled CSSfile, because there is nothing to map. The generated ESM shim
export { default } from "./file.css"therefore causes webpack to warn:The
.d.tshad the same bug: it emitted the fullIStylesboilerplate(
declare interface IStyles {}/export default styles) even when the modulemap was empty, falsely advertising a default export that does not exist at
runtime.
Details
The root cause is that both the shim generator and
_createDTSkeyed offrecord.isModule(file-extension classification) rather than whetherpostcss-modulesactually found any locally-scoped class names._processScssFileAsync(shim generation): Replaced therecord.isModuleflag with
hasModuleExports, which is onlytruewhenrecord.isModuleistrueand themoduleMapproduced bypostcss-modulesis non-empty:When
hasModuleExportsisfalse, the shim falls through to the side-effectform (
import "./file.css"; export {}/require("./file.css")), which iscorrect — the CSS still loads, it just carries no named class exports.
_createDTS(.d.ts generation): Extended theexport {};guard to alsofire when the module map is defined but empty:
This has no backwards-compatibility impact: any
.module.scssfile thatpreviously worked (i.e. had local class names) still produces the same output.
Files with only
:globalstyles previously produced broken output; they nowproduce correct side-effect-only output.
How it was tested
Added a new fixture
global-only.module.scss(a.module.scssfile whoseentire body is wrapped in
:global {}) and four new unit tests inSassProcessor.test.ts:.d.tsisexport {};when all styles are:globalimport "./global-only.module.css"; export {};require("./global-only.module.css");All pre-existing tests continue to pass.