Today we are going to talk about a feature of Sass that no one else seems to be talking about. The deprecation of the @import
rule and implementation of the new Module System including the new @use
rule.
I recently came across this in the Sass documentation:
If you are interested in more content like this, feel free to subscribe to my YouTube channel.
What is the Module System and @use
?
In October of 2019, the Module System became available. The heart of the Module System is the @use
rule. This rule makes CSS, variables, mixins, and functions from another stylesheet accessible in the current stylesheet. By default, variables, mixins, and functions are available in a namespace based on the basename of the URL.
@use "colors";
.element {
background-color: colors.$body-bg;
}
In addition to namespacing, there are a few important differences between @use
and @import
:
-
@use
only executes a stylesheet and includes its CSS once, no matter how many times that stylesheet is used. -
@use
only makes names available in the current stylesheet, as opposed to globally. - Members whose names begin with
-
or_
are private to the current stylesheet with@use
.
Namespaces
Let's take a closer look at namespaces and why this is a really awesome feature.
So, here we have two component files. One for our hero component and one for our card component. Generally we would have to uniquely name our variables to avoid any conflicts. But let's just say we "accidentally" named two variables the same.
// _hero-component.scss
$width: 100vw;
// _card-component.scss
$width: 80%;
If we used @import
to bring these in, we'll run into some issues. @import
will always evaluate the member that has been imported last. So this will always evaluate to the card width since it was the last to load.
@import 'hero-component';
@import 'card-component';
.hero {
width: $width; // 80%
}
.card {
width: $width; // 80%
}
This is where the @use
rule comes in.
@use 'hero-component';
@use 'card-component';
.hero {
width: hero-component.$width; // 100vw
}
.card {
width: card-component.$width; // 80%
}
So now we no longer have to get creative with our variable names.
Controlling Namespaces
Now, you might think that's more work having to type the namespaces. Well, we can actually control the namespace of a module. It can be set explicitly using as
.
@use 'hero-component' as hero;
@use 'card-component' as card;
.hero {
width: hero.$width;
}
.card {
width: card.$width;
}
We can even promote modules to the top-level namespace using as *
.
@use 'colors' as *;
.element {
background-color: $bgColor;
}
But we have to be careful with this and ensure that we do not introduce any conflicts. If conflicts are found, the compiler with throw an error.
Configuring Modules
Another great feature of the Module System is the ability to configure the default values of a module. A stylesheet can define variables with the !default
flag to make them configurable. Here we have a library that defines a default $border-radius
:
// _library.scss
$border-radius: 0.25rem !default;
.card {
border-radius: $border-radius;
}
We can modify the default value like this:
// style.scss
@use 'library' with (
$border-radius: 0.1rem
);
And here is the resulting CSS:
.card {
border-radius: 0.1rem;
}
Private Members
There's never been a way to have private members in a Sass stylesheet before the Module System. Now we can define private members by starting its name with either - or _. These members will work just like normal within the stylesheet that defines them, but they won't be part of a module's public API. That means stylesheets that load your module can't see them!
In this example we define a private variable, $-radius
. We can @include
the mixin but we cannot use the variable. That will result in an error during compilation.
// _corners.scss
$-radius: 3px;
@mixin rounded {
border-radius: $-radius;
}
// style.scss
@use "corners";
.button {
@include corners.rounded;
// This is an error! $-radius isn't visible outside of `_corners.scss`.
padding: 5px + corners.$-radius;
}
What Now??
So what do these changes mean for developers? As mentioned before, Sass has provided a migration tool that will aid in converting your existing @import
based code to @use
based.
Fortunately we have some time before @import gets removed from Sass. The deprecation is set for October 2021 and support will end October 2022.
But I would recommend that you start using @use
and try to forget about @import
One downside is the current compiler support for the Module System. Currently only Dart Sass supports the compilation of the @use
rule. Support within LibSass is not available yet. The worst part about this is that the VS Code extension "Live Sass Compiler" uses LibSass. So if you want to use these new features you will have to ditch that extension and start using the CLI Sass compiler. This is very easy to use but it's just annoying that we cannot use a tool that a lot of us are used to. Hopefully LibSass will be updated with the new features soon, but there is no current ETA that I could find.
Follow and support me:
Special thanks if you subscribe to my YouTube channel :)
Top comments (3)
Do you foresee any risks (beyond @import deprecation) to adding a namespacing system and private members to CSS compilation like this?
Also, when I read the title of this post, I thought of "Sass" in a different way, because only the first letter was capitalized. If anybody want Sass in a more literal (as in "Sassy") form, as a service, and will excuse a terrible pun, there's always FOaaS: github.com/tomdionysus/foaas
I think these are great changes that enable greater control over our libraries and modules. I don't see any risks. I just hope that developers will be on-board since these changes are very different from what we are used to with @import.
Thanks for the update.