A custom FileImporter for Dart Sass that adds include path resolution, similar to the deprecated includePaths option.
Dart Sass removed the includePaths option. This package provides a FileImporter that restores that behavior, allowing you to resolve @use and @import from directories like node_modules.
I needed this for my own bundler and static site generator Poops in 2023. Since legacy API support includePaths didn't work for me at all and I wanted it to work like I was remembering it, I went ahead and wrote it. Might be completely useless by now...
Now that it's complete and supports paths like in good old days, because:
It's dangerous to go alone! Take this.
P.S. I see now pkg: prefixed node imports exist since exactly a year ago... well, whatever... 🤣
npm install sass-path-resolverimport { compile } from "sass";
import { sassPathResolver } from "sass-path-resolver";
const result = compile("src/styles/main.scss", {
importers: [sassPathResolver("node_modules")],
});Multiple include paths:
const result = compile("src/styles/main.scss", {
importers: [sassPathResolver(["node_modules", "vendor/styles"])],
});Works with compileString too:
import { compileString } from "sass";
import { sassPathResolver } from "sass-path-resolver";
const result = compileString('@use "my-package";', {
importers: [sassPathResolver("node_modules")],
});Given @use "my-pkg/core/config" and an include path of node_modules, the resolver tries the following in order:
- Directory with index file -
node_modules/my-pkg/core/config/index.{sass,scss,css} - Directory with
package.json- readssass,scss,style,css, ormainfields - Exact file -
node_modules/my-pkg/core/config - File with extension -
node_modules/my-pkg/core/config.{sass,scss,css} - Underscore partial -
node_modules/my-pkg/core/_config.{sass,scss,css} - Package-relative path - resolves the path relative to the package entry point defined in
package.json
The first match is returned as a file: URL. If nothing matches across all include paths, null is returned and Sass falls through to its default resolution.
Say you have a package my-design-system published to npm:
node_modules/
└── my-design-system/
├── package.json { "sass": "src/index.scss" }
└── src/
├── index.scss
└── core/
├── _config.scss
├── index.scss
└── utils/
├── _helpers.scss
└── index.scss
With sassPathResolver('node_modules'), these all resolve:
// Package entry point (via sass field in package.json)
@use "my-design-system"; // → src/index.scss
// Directory with index file
@use "my-design-system/src/core"; // → src/core/index.scss
@use "my-design-system/src/core/utils"; // → src/core/utils/index.scss
// Direct file (with or without extension)
@use "my-design-system/src/index"; // → src/index.scss
@use "my-design-system/src/index.scss"; // → src/index.scss
// Underscore partials
@use "my-design-system/src/core/config"; // → src/core/_config.scss
@use "my-design-system/src/core/utils/helpers"; // → src/core/utils/_helpers.scss
// Package-relative paths (resolved relative to package.json entry)
@use "my-design-system/core/config"; // → src/core/_config.scss
@use "my-design-system/core/utils/helpers"; // → src/core/utils/_helpers.scss
// If your package is scoped, for instance, same rules apply
@use "@scope/my-design-system"; // → entry from package.json
@use "@scope/my-design-system/core/config"; // → resolved via package.json entryThe last two are the key feature — core/config doesn't exist at node_modules/my-design-system/core/config, but the resolver reads package.json, finds the entry point is in src/, and resolves relative to that.
When resolving a package root (e.g. @use "my-pkg"), the resolver reads package.json and checks the following fields in order:
sassscssstylecssmain
Returns a Dart Sass FileImporter object.
includePathsstring | string[]- One or more directories to search for imports. Throws if not provided or not a string/array.
Lower-level function that resolves a single URL against a single include path. Returns a URL object or null.
MIT