Speeding Up Your Sass Compilation in Vite and Webpack
A quick guide to adopting the modern Sass API
Sass compilation can be a speed bottleneck in your build, but it doesn’t have to be anymore.
pkg:
URLs
A quick guide to using the new Node.js package importer
Enabling pkg:
URLs is quick and straightforward, and simplifies using packages from the node_modules
folder.
Over the years, there have been a variety of methods for resolving third party
libraries in Sass. I’ve used includePaths
or loadPaths
, a preceding ~
, or
even ../../../../node_modules/
(hoping I get the levels correct and the files
never move around).
Sass 1.71 introduces a new standard way, with pkg:
URLs. More can be found on
the official blog post,
and this article shows how quick it is to set it up.
pkg:
URLs in WebpackI am currently working on a project creating components in Storybook,
using Bootstrap as a base theme. Because of some project requirements,
we’re still using Webpack with Storybook, and not the latest versions with Vite.
Luckily, this setup makes it easy to use the new pkg:
URLs.
First, I needed to install the latest version of Sass, using npm install sass
.
In Storybook, Webpack is configured in .storybook/main.ts
. There, we need to
import the built-in Node.js package importer from sass
:
import { NodePackageImporter } from 'sass';
Then, I updated the rule for sass-loader
to use the new importer.
// File: .storybook/main.ts
{
loader: require.resolve('sass-loader'),
options: {
implementation: require.resolve('sass'),
sourceMap: true,
sassOptions: {
pkgImporter: new NodePackageImporter(),
},
},
},
By default, sass-loader
uses the Legacy Sass API, which only supports a single
importer. By adding api: 'modern'
, we can opt into the newer Sass API:
// File: .storybook/main.ts
{
loader: require.resolve('sass-loader'),
options: {
implementation: require.resolve('sass'),
sourceMap: true,
api: 'modern',
sassOptions: {
importers: [new NodePackageImporter()],
},
},
},
Then, all that is left is updating the imported URLs in your Sass files.
Before:
/* File: ./src/styles/index.scss */
@import '../../node_modules/bootstrap/scss/bootstrap';
After:
/* File: ./src/styles/index.scss */
@import 'pkg:bootstrap';
Wait – what happened to the file path? The pkg:
importer not only locates the
node_modules
folder, it also enables some smart path resolution. The key in
this case is in Bootstrap’s package.json
file:
// File: node_modules/bootstrap/package.json
...
"sass": "scss/bootstrap.scss",
...
The pkg:
importer also understands Node.js’s Conditional
Exports, which
provide library authors a lot of control over how internal files are exposed to
users.
pkg:
URLs in ViteVite-based projects can also easily use the Node.js package importer. Again, I
started by updating Sass using npm install sass
.
This was a fairly simple Vite project, so I hadn’t created a configuration file
at vite.config.ts
yet. Once I created that, I made my changes to the
css.preprocessorOptions.scss
object.
Changes in the scss
object only will affect .scss
files. If you’re using the
indent-based .sass
format instead, you’ll need to add the Node.js package
importer to css.preprocessorOptions.sass
.
Vite currently only supports the legacy API, so I needed to set the
pkgImporter
option.
// ./vite.config.ts
import { NodePackageImporter } from 'sass';
import { defineConfig } from 'vite';
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
pkgImporter: new NodePackageImporter(),
},
},
},
});
With that in place, I can now update my Sass import.
Before:
/* File: ./src/styles/main.scss */
@use 'vuetify' with (
…
After:
/* File: ./src/styles/main.scss */
@use 'pkg:vuetify' with (
…
But wait, that’s actually more characters – why would I make that change?
Before, the location of vuetify
was being determined by Vite. Adding pkg:
moves that logic into Sass. This doesn’t have an immediate impact in this case,
but it does make the code more portable. My styles could be shared with someone
building with Webpack or ported to a future build tool. When more Package
importers become available, this could even be used outside a Node.js module.
Updating your Sass to use pkg:
URLs is a fairly straightforward quality of
life improvement. I’m looking forward to seeing what can be achieved as more
tools take advantage of the standardized syntax.
A quick guide to adopting the modern Sass API
Sass compilation can be a speed bottleneck in your build, but it doesn’t have to be anymore.
CSS Working Group updates from July
Over the last month, the CSS Working Group has determined we can loosen containment restrictions for query containers, and agreed on a syntax for special-case support queries (like support for the gap property in a flex context, or support for align-content in a block flow context).
What I’ve been working on as an Invited Expert
The CSS Working Group has regular face-to-face meetings (hybrid online/in-person) throughout the year, and they always result in a flurry of activity! Here’s a rundown of some highlights from the last few months, with a focus on the features I maintain.