Target SharePoint environment: SharePoint Online
Framework: SharePoint Framework
Additional environment details:
- SPFx version: 1.23.0 (GA)
- Node.js version: >= 22.14.0
- Developer OS: macOS / Windows
@microsoft/spfx-heft-plugins: 1.23.0
@microsoft/sp-css-loader: 1.23.0
@rushstack/heft-sass-plugin: 1.3.8
Describe the bug / error
CSS and SCSS source maps are not functional in development (heft start) mode in SPFx 1.23.0 (GA).
This is a continuation of the regression introduced with the Heft toolchain migration in SPFx 1.22.
TypeScript/TSX source maps still work. This regression is CSS/SCSS-only.
The SPFx team explicitly committed to fixing this in the 1.23 release (see #10490), but the GA
ships with @rushstack/heft-sass-plugin at the same version (1.3.8) as the RC, with no changes
to the source map chain.
Related:
Steps to reproduce
- Scaffold a new SPFx 1.23.0 web part project
- Run
heft start --clean
- Open the workbench in a browser and open DevTools
- Inspect any CSS rule applied by your web part
- Click the source link in the Styles panel
Expected behavior
When running heft start, the source link in DevTools should trace back to the original
.scss source file:
src/webparts/myWebPart/components/MyWebPart.module.scss <- expected
This worked in SPFx 1.20-1.21 (Gulp toolchain).
Actual behaviour
Source maps for CSS/SCSS point to the intermediate compiled .css file in lib/, not the
original .scss source. In the generated dist/one-22-web-part.js.map:
"sources": [
"webpack:///.././lib/webparts/one22/components/One22.module.scss.css",
...
]
- No
.scss paths appear in the bundle source map.
- No
.map files are generated in lib/ alongside the compiled CSS.
sourcesContent embeds the compiled intermediate JS module, not the original SCSS.
Root Cause Analysis
The Heft-based build chain has three independent points where the source map chain is broken.
Point 1 — @rushstack/heft-sass-plugin (v1.3.8): No .map output
The Sass compilation step outputs compiled CSS to lib/ but generates no .map files.
The SassProcessor does not pass source map options to sass-embedded, and no sourceMap
option is exposed in the plugin's configuration schema or ISassProcessorOptions interface.
One22.module.scss
-> [heft-sass-plugin]
-> lib/webparts/one22/components/One22.module.scss.css <- no .map generated
Point 2 — @microsoft/sp-css-loader (v1.23.0): No source map support
sp-css-loader is an independent reimplementation — not a wrapper around css-loader. It
runs PostCSS directly but passes no map option to processor.process():
sp-css-loader/lib-commonjs/index.js ~line 87:
result = await processor.process(content, {
from: resourcePath,
to: resourcePath
// No map option
});
The webpack loader chain is also built without a sourceMap option:
WebpackConfigurationGenerator.js ~line 264:
const simpleCssLoaderOptions = {
async: true,
loadThemedStylesImportPath: options.loadThemedStylesImportPath,
production: options.production
// No sourceMap option
};
Compare to how sourceMap is correctly forwarded to ModuleMinifierPlugin for JS (~line 519):
sourceMap: !!devtool // exists for JS minifier, absent for CSS loader
Point 3 — source-map-loader only processes .js files
Even in dev mode where devtool: 'source-map' is set, the source-map-loader is registered
only for .js files:
WebpackConfigurationGenerator.js ~line 528:
config.module.rules.push({
test: /\.js$/, // JS only; CSS never processed
enforce: 'pre',
use: { loader: 'source-map-loader', ... }
});
CSS files are never processed by source-map-loader. And since Point 1 produces no .map
files anyway, there is nothing to pick up even if the rule were widened.
Resulting chain vs. TypeScript (comparison)
CSS/SCSS — broken:
One22.module.scss
-> [heft-sass-plugin, no map output]
-> lib/One22.module.scss.css (no .map)
-> [sp-css-loader, no sourceMap option]
-> webpack bundle
-> dist/bundle.js.map
sources: ["webpack:///../lib/.../One22.module.scss.css"] <- points to lib/, not src/
TypeScript — working:
One22WebPart.ts
-> [tsc, sourceMap: true + inlineSources: true]
-> lib/One22WebPart.js + One22WebPart.js.map (-> src/)
-> [source-map-loader, resolves chain]
-> dist/bundle.js.map
sources: ["webpack:///../src/.../One22WebPart.ts"] <- correct!
sourcesContent: [embedded TypeScript source]
History
| SPFx Version |
Toolchain |
CSS Source Maps |
| <= 1.18 |
Gulp |
Not working |
| 1.19.0 |
Gulp |
Partial / unreliable |
| 1.20.x - 1.21.x |
Gulp |
Working |
| 1.22.x (beta -> GA) |
Heft |
Broken (regression) |
| 1.23.0 (GA) |
Heft |
Still broken — commitment missed |
Reference: Improved CSS debugging in SharePoint 1.20
documents the working state and why CSS source maps matter for debugging complex SPFx solutions.
Missed Commitment
During the SPFx 1.22.0-rc.0 release cycle, the SPFx team explicitly committed to delivering
SASS source map support in the 1.23 release. From the opening post of discussion #10490:
"SASS Sourcemaps are not currently supported by Heft SASS plugin at this time. We will work
to get this added to Heft, and it will be included in 1.23 release."
— @nick-pape, 2025-11-19
SPFx 1.23.0 GA has shipped and — as the technical analysis above confirms — this commitment
has not been met. @rushstack/heft-sass-plugin ships at the same version (1.3.8) as it did
during the RC cycle. The three broken points in the chain remain unchanged.
Fix Required
Restoring CSS/SCSS source maps requires addressing all three points in the chain:
-
@rushstack/heft-sass-plugin: Add sourceMap option and emit .map files alongside
compiled CSS output in cssOutputFolders.
-
@microsoft/sp-css-loader: Expose and forward a sourceMap option to the PostCSS
pipeline (map option on processor.process()).
-
@microsoft/spfx-heft-plugins webpack config: Pass sourceMap: !!devtool to the CSS
loader options in WebpackConfigurationGenerator.js (mirroring what already exists for
ModuleMinifierPlugin).
Target SharePoint environment: SharePoint Online
Framework: SharePoint Framework
Additional environment details:
@microsoft/spfx-heft-plugins: 1.23.0@microsoft/sp-css-loader: 1.23.0@rushstack/heft-sass-plugin: 1.3.8Describe the bug / error
CSS and SCSS source maps are not functional in development (
heft start) mode in SPFx 1.23.0 (GA).This is a continuation of the regression introduced with the Heft toolchain migration in SPFx 1.22.
TypeScript/TSX source maps still work. This regression is CSS/SCSS-only.
The SPFx team explicitly committed to fixing this in the 1.23 release (see #10490), but the GA
ships with
@rushstack/heft-sass-pluginat the same version (1.3.8) as the RC, with no changesto the source map chain.
Related:
Steps to reproduce
heft start --cleanExpected behavior
When running
heft start, the source link in DevTools should trace back to the original.scsssource file:This worked in SPFx 1.20-1.21 (Gulp toolchain).
Actual behaviour
Source maps for CSS/SCSS point to the intermediate compiled
.cssfile inlib/, not theoriginal
.scsssource. In the generateddist/one-22-web-part.js.map:.scsspaths appear in the bundle source map..mapfiles are generated inlib/alongside the compiled CSS.sourcesContentembeds the compiled intermediate JS module, not the original SCSS.Root Cause Analysis
The Heft-based build chain has three independent points where the source map chain is broken.
Point 1 —
@rushstack/heft-sass-plugin(v1.3.8): No.mapoutputThe Sass compilation step outputs compiled CSS to
lib/but generates no.mapfiles.The
SassProcessordoes not pass source map options tosass-embedded, and nosourceMapoption is exposed in the plugin's configuration schema or
ISassProcessorOptionsinterface.Point 2 —
@microsoft/sp-css-loader(v1.23.0): No source map supportsp-css-loaderis an independent reimplementation — not a wrapper aroundcss-loader. Itruns PostCSS directly but passes no
mapoption toprocessor.process():sp-css-loader/lib-commonjs/index.js~line 87:The webpack loader chain is also built without a
sourceMapoption:WebpackConfigurationGenerator.js~line 264:Compare to how
sourceMapis correctly forwarded toModuleMinifierPluginfor JS (~line 519):Point 3 —
source-map-loaderonly processes.jsfilesEven in dev mode where
devtool: 'source-map'is set, thesource-map-loaderis registeredonly for
.jsfiles:WebpackConfigurationGenerator.js~line 528:CSS files are never processed by
source-map-loader. And since Point 1 produces no.mapfiles anyway, there is nothing to pick up even if the rule were widened.
Resulting chain vs. TypeScript (comparison)
CSS/SCSS — broken:
TypeScript — working:
History
Reference: Improved CSS debugging in SharePoint 1.20
documents the working state and why CSS source maps matter for debugging complex SPFx solutions.
Missed Commitment
During the SPFx 1.22.0-rc.0 release cycle, the SPFx team explicitly committed to delivering
SASS source map support in the 1.23 release. From the opening post of discussion #10490:
SPFx 1.23.0 GA has shipped and — as the technical analysis above confirms — this commitment
has not been met.
@rushstack/heft-sass-pluginships at the same version (1.3.8) as it didduring the RC cycle. The three broken points in the chain remain unchanged.
Fix Required
Restoring CSS/SCSS source maps requires addressing all three points in the chain:
@rushstack/heft-sass-plugin: AddsourceMapoption and emit.mapfiles alongsidecompiled CSS output in
cssOutputFolders.@microsoft/sp-css-loader: Expose and forward asourceMapoption to the PostCSSpipeline (
mapoption onprocessor.process()).@microsoft/spfx-heft-pluginswebpack config: PasssourceMap: !!devtoolto the CSSloader options in
WebpackConfigurationGenerator.js(mirroring what already exists forModuleMinifierPlugin).