Read-only variables for used modules
See original GitHub issueCurrently, built-in modules and userland modules have a big difference (which is not clearly explained in the doc IMO): in userland modules, any exported variable is writable by downstream modules, and this impacts other modules importing the same module later. This is even true for variables that are not configurable in @use
. On the other hand, variables exported by built-in modules (math.$pi
for instance) are immutable.
To me, this behavior of builtin modules makes it harder to reason about the behavior of modules, as I cannot look only at upstream modules to find out where a value comes from.
This behavior also makes variables unsuitable for cases where downstream modules are not meant to be allowed to change the values (for instance a color palette of a design system, where downstream modules should only be allowed to use colors).
Reproducing case proving this
// _a.scss
$v: "a";
@debug $v;
// _b.scss
@use "a";
@debug a.$v;
// _c.scss
@use "a" as c;
c.$v: "b";
@debug c.$v;
// b_first.scss
@use "b";
@use "c";
// c_first.scss
@use "c";
@use "b";
Output for sass b_first.scss
:
_a.scss:2 Debug: a
_b.scss:3 Debug: a
_c.scss:4 Debug: b
Output for sass c_first.scss
:
_a.scss:2 Debug: a
_c.scss:4 Debug: b
_b.scss:3 Debug: b
As you can see, the file in _c.scss
(that knows nothing about _b.scss
) will get a different in the value it receives from _a.scss
depending on the order in which modules gets executed for the first time, which can only be determined by looking at the whole dependency graph starting at the entrypoint (and things are even worse if meta.loadCss
adds some module execution in places that cannot be found statically).
Being able to expose values that can be read is nice API for anything needing to expose reusable values IMO (and math.$e
is a good proof of it). But most cases I can think about don’t actually expect those members to be writable in downstream modules. https://github.com/Awjin/guten-type/blob/master/src/_config.scss is another case that seems to prove it, using functions to expose members in a read-only way instead of exposing them directly.
Is it expected to make those members writable (the implementation seems to say yes, as I don’t see how that could have been implemented by accident) ? And do you think there should be a way for modules to forbid downstream assignments ?
Issue Analytics
- State:
- Created 2 years ago
- Reactions:2
- Comments:8 (6 by maintainers)
Top GitHub Comments
@Awjin the question is also whether authors (not belonging to the Sass core team) realize that exported variables are writable. Last time I checked, the documentation about Sass modules was not telling anything about that (and the emphasis about configuring modules might make them think that those variables are indeed writable only through the configuration, which is why I thought myself until I started reading the code of dart-sass to discover the opposite)
@AprilArcus styles are compiled on the module execution, the first time it is used. So any module variable re-assignment will not affect the module styles. But it will affect the module API used by other modules (the value of the exported variable, the output of the exported functions/mixins if they use that variable, etc…)