SharePoint / SharePoint/sp-dev-docs
[SPFx 1.22β1.23] Sass import resolution changed β `~` breaks in `meta.load-css()`, bare specifiers and `importIncludePaths` no longer work (undocumented)
@Ashlesha-MSFT is already working on this.
Since May 21, 2026.
- Dominant language
- PowerShell
- Stars
- 1.4k
- Forks
- 1.1k
- Avg merge
- 4d 12h
- Merged PRs (30d)
- 12
Description
Target SharePoint environment
SharePoint Online
SharePoint development model
π₯ SharePoint Framework
Developer environment
macOS, windows, linux
Additional environment details
I reproduced this on two SPFx projects β one scaffolded and pinned to the SPFx 1.22 toolchain, one to SPFx 1.23 β and verified the versions from each project's node_modules:
| SPFx 1.22 project | SPFx 1.23 project | |
|---|---|---|
SPFx (@microsoft/spfx-web-build-rig) |
1.22.2 | 1.23.0 |
@rushstack/heft-sass-plugin |
0.15.24 | 1.3.8 |
@rushstack/heft |
1.1.2 | 1.2.17 |
sass-embedded |
1.77.8 | 1.85.1 |
| Node.js | 22.22.0 | 22.22.0 |
@microsoft/spfx-web-build-rig@1.22.2 pins @rushstack/heft-sass-plugin@0.15.24; @1.23.0 pins @1.3.8 β so this is the version pair every SPFx project gets on each release. The reference dependency I imported in the repro is @n8d/htwoo-core@2.7.1.
Describe the bug / error
Between the @rushstack/heft-sass-plugin version SPFx 1.22 ships (0.15.24) and the one SPFx 1.23 ships (1.3.8), the plugin's Sass import-resolution model was rewritten β from Sass loadPaths + a tilde (~) importer to the pkg: scheme plus a tilde-to-pkg: text rewrite. pkg: is the modern Sass mechanism, so the direction is fine, but the change isn't documented anywhere I could find: not in the plugin CHANGELOG, not in the SPFx 1.23 release notes, not in Configure Sass processing during builds, and not in Migrate from the Gulp Toolchain to Heft Toolchain β even though that migration guide's whole job is to spell out what changes on upgrade.
Three things that worked in SPFx 1.22 fail in SPFx 1.23:
| Import form | SPFx 1.22 (0.15.24) | SPFx 1.23 (1.3.8) | |
|---|---|---|---|
| D | bare specifier β @use '@scope/pkg/...' |
works | Can't find stylesheet to import |
| E | ~ inside @include meta.load-css('~@scope/pkg/...') |
works | Unexpected tilde in URL |
| G | config/sass.json with importIncludePaths |
valid option | build fails config validation |
E is the one that really catches you out. ~ still works in @use, @import and @forward, so it's natural to assume ~ is just supported β until you use it in meta.load-css() and the build throws.
Why E happens
In 1.3.8, ~ is no longer a Sass importer. It's rewritten to pkg: by a regular expression that runs over the source before compilation (SassProcessor.js, line 56):
const importTildeRegex = /^(\s*@(?:import|use|forward)\s*)('~(?:[^']+)'|"~(?:[^"]+)")/gm;
That regex only matches @import, @use and @forward. @include meta.load-css('~β¦') doesn't start with any of those, so the ~ is never rewritten β and when it reaches the importer it is rejected outright (SassProcessor.js, line 356):
throw new Error(`Unexpected tilde in URL: ${url} in context: ${context.containingUrl?.href}`);
In 0.15.24, ~ was a genuine Sass importer, and Sass consults importers for meta.load-css() too β so it worked everywhere. Bare specifiers (D) worked in 0.15.24 because the plugin passed loadPaths: [<project>/node_modules, <project>/src]; 1.3.8 passes no loadPaths at all. importIncludePaths (G) was a documented config/sass.json option in 0.15.24's schema; 1.3.8 removed it, and the schema is additionalProperties: false, so setting it now fails validation.
Steps to reproduce
- Create (or upgrade to) an SPFx 1.23 project and install any package that ships SCSS partials β e.g.
npm install @n8d/htwoo-core. - Add a
.global.scssfile undersrc/webparts/<wp>/components/containing:@use 'sass:meta'; .x { @include meta.load-css('~@n8d/htwoo-core/lib/components/all'); } - Run
heft build. The build fails:[build:sass] Error: src/webparts/.../X.global.scss:2:11 - Error: Unexpected tilde in URL: ~@n8d/htwoo-core/lib/components/all in context: heft:/.../X.global.scss -------------------- Failed -------------------- - Add another file with a bare specifier β
@use '@n8d/htwoo-core/lib/components/all';β andheft buildfails withCan't find stylesheet to import. - Add
"importIncludePaths": ["node_modules", "src"]toconfig/sass.jsonandheft buildfails before compiling anything:[build:sass] Error: Resolved configuration object does not match schema: ... JSON validation failed [build:sass] must NOT have additional properties: importIncludePaths - Build the same files on an SPFx 1.22 project β all three succeed.
Full cross-version reproduction
I compiled six identical fixture files (Matrix{A..F}.global.scss) with each project's own heft build. Import target: @n8d/htwoo-core/lib/components/all.
| Fixture | Statement | SPFx 1.22 | SPFx 1.23 |
|---|---|---|---|
| MatrixA | @import '~β¦/all' |
PASS | PASS |
| MatrixB | @use '~β¦/all' |
PASS | PASS |
| MatrixC | @use 'pkg:β¦/all' |
FAIL | PASS (new in 1.23) |
| MatrixD | @use 'β¦/all' (bare specifier) |
PASS | FAIL |
| MatrixE | @include meta.load-css('~β¦/all') |
PASS | FAIL |
| MatrixF | @include meta.load-css('pkg:β¦/all') |
FAIL | PASS (new in 1.23) |
SPFx 1.23 β heft build (plugin 1.3.8):
[build:sass] Compiling 7 files...
[build:sass] Error: src/webparts/.../MatrixD.global.scss:1:0 - Can't find stylesheet to import.
[build:sass] @use '@n8d/htwoo-core/lib/components/all';
[build:sass] Error: src/webparts/.../MatrixE.global.scss:2:11 - Error: Unexpected tilde in URL:
~@n8d/htwoo-core/lib/components/all in context: heft:/.../MatrixE.global.scss
-------------------- Failed (4.352s) --------------------
Only MatrixD and MatrixE errored. A, B, C, F compiled fine.
SPFx 1.22 β heft build (plugin 0.15.24):
Error occurred parsing and generating typings for file ".../MatrixC.global.scss": ... Can't find stylesheet to import.
Error occurred parsing and generating typings for file ".../MatrixF.global.scss": ... Can't find stylesheet to import.
[build:sass] Generated sass typings
Only MatrixC and MatrixF errored (0.15.24 has no pkg: importer). MatrixA, B, D and E all compiled β confirming D and E are genuine regressions, not pre-existing failures.
Two more things the same builds surfaced
The rig still advertises the removed option. @microsoft/spfx-web-build-rig@1.23.0 ships this in node_modules/@microsoft/spfx-web-build-rig/profiles/default/config/sass.json (the file your project's config/sass.json extends β not your project file itself):
/**
* A list of paths used when resolving Sass imports. The paths should be relative to the project root.
*
* Default value: ["node_modules", "src"]
*/
// "importIncludePaths": ["node_modules", "src"],
Un-comment that and the build fails the schema validation above β the option it documents no longer exists.
A 1.23-scaffolded project will not build on 1.22. The webpart SCSS the 1.23 generator emits starts with @import 'pkg:@fluentui/react/dist/sass/References.scss'; (or pkg:@microsoft/sp-office-ui-fabric-core/... for the no-framework template). That pkg: line fails on SPFx 1.22, since 0.15.24 has no pkg: importer. (See also #10833 on the scaffold's deprecated @import.)
Expected behavior
The behavior change itself is reasonable β pkg: is the right modern mechanism. The problem is that it's undocumented, and ~ is left half-working (fine in @use/@import/@forward, broken in @include meta.load-css()), which is exactly the kind of thing that turns a 1.22β1.23 upgrade into mystery build failures.
I'd expect the docs to cover it:
- The SPFx 1.23 release notes and the Configure Sass processing during builds page should state that the resolution model changed β
loadPaths/importIncludePathsare gone,pkg:is the supported scheme, and~is only auto-rewritten in@use/@import/@forward. - The Migrate from the Gulp Toolchain to Heft Toolchain guide should include a Sass step: replace
@include meta.load-css('~β¦')and bare@use '@scope/pkg/β¦'with thepkg:form, and removeimportIncludePathsfromconfig/sass.json. - The stale
importIncludePathscomment should be removed fromspfx-web-build-rig'ssass.json.
Workaround for anyone hitting this today
Use pkg: for every npm-package import β it's the one form that works in @use, @import, @forward and meta.load-css():
@include meta.load-css('~@scope/pkg/...')β@include meta.load-css('pkg:@scope/pkg/...')- bare
@use '@scope/pkg/...'β@use 'pkg:@scope/pkg/...' - delete
importIncludePathsfromconfig/sass.json
References
@rushstack/heft-sass-plugin@0.15.24/@1.3.8SassProcessor.jsβimportTildeRegex(line 56),nonCanonicalScheme: 'pkg'(line 103),Unexpected tilde in URLthrow (line 356)@rushstack/heft-sass-plugin@1.3.8heft-sass-plugin.schema.jsonβadditionalProperties: false, noimportIncludePaths- Sass
pkg:importers β https://sass-lang.com/blog/announcing-pkg-importers/ - Sass
meta.load-css()β https://sass-lang.com/documentation/modules/meta/#load-css - Related: #10466, #10832, #10833, #10834
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up β it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.