Request for Comments: Package Importer
Posted 26 September 2023 by James Stuckey Weber
Sass users often need to use styles from a dependency to customize an existing
theme or access styling utilities. Historically, Sass has not specified a
standard method for using packages from dependencies. This has led to a variety
of domain-specific solutions, including the ~
prefix in Webpack, and adding
node_modules
to loadPaths
.
This has been a common pain point, and can make it difficult to rely on dependencies. It can also make it more difficult to move your project to a new build process.
Package ImportersPackage Importers permalink
We are proposing a new type of importer that allows users to use the pkg:
URL
scheme to direct Sass to resolve the dependency URL using the resolution
standards and conventions for a specific environment.
To address the largest use case, we are proposing a built-in Package Importer
for the Node ecosystem. Our recommendation is for package authors to define a
sass
conditional export for entry points to their package in their
distributed package.json
. For example, a package.json
containing:
{
"exports": {
".": {
"sass": "./src/scss/index.scss",
"import": "./dist/js/index.mjs",
"default": "./dist/js/index.js"
},
"./utils": {
"sass": "./src/scss/_utils.scss",
"default": "./dist/js/utils.js"
}
}
}
would allow a package consumer to write:
@use "pkg:library";
@use "pkg:library/utils";
We wanted to allow Sass package consumers to start using pkg:
URLs without
requiring changes from the package authors. Because many Sass packages already
define their entrypoints in a variety of ways, the Node Package Importer also
supports several other ways of defining entrypoints, which cover the majority of
implementations we observed. These resolve in the following order:
-
sass
,style
, ordefault
condition in package.jsonexports
that resolves to a Sass or CSS file. -
If there is not a subpath, then find the root export:
-
sass
key at package.json root. -
style
key at package.json root. -
index
file at package root, resolved for file extensions and partials.
-
-
If there is a subpath, resolve that path relative to the package root, and resolve for file extensions and partials.
To better understand and allow for testing against the recommended algorithm, a Sass pkg: test repository has been made with a rudimentary implementation of the algorithm.
DetailsDetails permalink
Because the Node ecosystem is primarily concerned with distributing JavaScript, we needed to find a way to allow package authors to distribute Sass. In many ways, the closest analog is to TypeScript types, as type definition files are distributed alongside compiled code, and are often not the primary export in a package.
Based on our analysis of over 400 packages for design libraries and
frameworks, we anticipate package consumers will be able to use pkg:
URLs for
many packages without package authors needing to make changes. Package authors
will be able to better specify and document how to consume the packages.
Our analysis also showed that packages distributing Sass almost always did so
alongside JavaScript code. Some packages do specify a Sass file as a sass
key
or a CSS file as a style
key at the package.json
root, both of which will be
supported by the Node Package Importer. We observed little usage of main
or
module
keys for CSS or Sass, which will not be supported.
While we observed low usage currently of conditional exports fields for
specifying Sass and CSS files, we expect this to grow as package authors adopt
conditional exports. In addition, build tools like Vite, Parcel and Sass
Loader for Webpack all currently resolve Sass paths using the sass
and
style
custom conditions.
Users will need to opt-in to the new Package Importer by importing the
nodePackageImporter
from sass
and including it in the list of importers
.
This won’t be available for Sass in the browser.
const sass = require('sass');
sass.compile('style.scss', {
importers: [sass.nodePackageImporter]
})
Next stepsNext steps permalink
This is still in the proposal phase, so we are open to feedback. Review the proposal on Github, and open an issue with any thoughts or concerns you may have.