[heft-sass-plugin] Add preserveIcssExports option#5762
Merged
iclanton merged 10 commits intomicrosoft:mainfrom Apr 9, 2026
Merged
[heft-sass-plugin] Add preserveIcssExports option#5762iclanton merged 10 commits intomicrosoft:mainfrom
preserveIcssExports option#5762iclanton merged 10 commits intomicrosoft:mainfrom
Conversation
daa8bde to
0daa4e6
Compare
dmichon-msft
approved these changes
Apr 9, 2026
Contributor
dmichon-msft
left a comment
There was a problem hiding this comment.
Generally not a fan of file system crawls to find files at static known locations. Could also probably read this from an environment variable? We should consider making that be part of the environment for heft-jest-plugin if it isn't already.
Add a new `preserveIcssExports` option to `sass.json` that preserves the ICSS `:export` block in the emitted CSS output. When false (the default), `postcss-modules` strips `:export` from the CSS as before. When true, the CSS is left unchanged so that downstream webpack loaders (e.g. css-loader's icssParser) can extract the `:export` values at bundle time to generate JavaScript module exports.
Tests cover CSS output (preserveIcssExports true/false), .d.ts generation, Sass-specific features (variables + nesting, @mixin, @extend + placeholders), JS shim generation (commonjs/esnext, module/global), multiple output folders, postProcessCssAsync callback, exportAsDefault: false, and error reporting. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…option Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
8bbc7f6 to
89665b5
Compare
On Windows, path.resolve('/fake/output/css', ...) prepends the drive
letter and uses backslashes. Normalize paths in the FileSystem mock to
forward slashes with no drive letter so that map lookups and snapshots
are consistent across platforms.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…or tests" This reverts commit ce1b26c.
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
When
cssOutputFoldersis configured to emit CSS files for consumption by a webpack loader, the ICSS:exportblock was being stripped from the output. This broke downstream loaders such ascss-loader'sicssParserthat depend on the:exportblock being present in the CSS file to generate JavaScript module exports at bundle time.A new
preserveIcssExportsboolean option (defaultfalse) is added tosass.json. When set totrue, the CSS is written to disk unchanged so that the:exportblock is available for downstream processing.Details
postcss-modulesis run on CSS module files to extract class names and:exportvalues for.d.tsgeneration. As a side effect it strips the:exportblock from the CSS output — this is correct behavior in a traditional CSS Modules pipeline wherecss-loaderconsumes the CSS directly and generates JS inline, but is incorrect when heft-sass-plugin emits CSS files to disk for a separate webpack pass to consume.The fix runs
postcss-modulespurely for its side effect of populating the module map via thegetJSONcallback, then conditionally discards the transformed CSS in favor of the original whenpreserveIcssExports: true. The:exportblock is the only thingpostcss-modulesremoves from the CSS for standard compiled SCSS (class name scoping with the identitygenerateScopedNameis a no-op round-trip).The option defaults to
falseto preserve backwards compatibility.How it was tested
Verified by building a project with
.module.scssfiles containing only an:exportblock and confirming the emitted.cssfile contains the block, allowing the downstream webpack bundle to correctly export the values as a JavaScript default export.