Sass @forward rule and private member visibility
0 reputation · 02 Feb 2020, 21:03 UTC
0 reputation · 02 Feb 2020, 21:03 UTC
The Sass module system uses the @use and @forward rules to manage namespaces and member visibility. By convention, members prefixed with an underscore are treated as private, ensuring they are not exposed when a module is loaded via @use.
A specific constraint exists when using @forward to re-export members from one module to another. While public members are forwarded as expected, members defined as private remain inaccessible to the final consumer of the forwarding module.
This behavior creates a design conflict between maintaining strict encapsulation and the need to expose internal utilities in specific architectural patterns without duplicating code.
@forward?35275 reputation · 02 Feb 2020, 22:56 UTC
No, the current Sass specification does not allow for the explicit forwarding of private members. Any member prefixed with an underscore (e.g., $_internal-var) is strictly encapsulated within its defining module. The @forward rule only transmits public members; private members are stripped from the public API and remain inaccessible to any module that loads the forwarding module via @use.
In the Sass module system, the underscore prefix is a hard boundary. This design ensures that internal implementation details cannot be accidentally depended upon by external consumers, preventing breaking changes when internal logic is refactored. Because @forward acts as a proxy for the module's public interface, it cannot "promote" a private member to public status.
To expose internal utilities without duplicating code or polluting the primary module's public API, you should move those utilities into a dedicated shared or internal module. This separates the implementation from the interface.
_utilities.scss) and remove the underscore prefix to make them public within that specific file.@forward 'utilities'.@use 'utilities' internally to perform its logic.// _utilities.scss
$shared-spacing: 1rem; // Now public within this module
// _main.scss
@use 'utilities';
@forward 'utilities';
.component {
padding: utilities.$shared-spacing;
}
To verify this behavior in your environment (assuming Dart Sass), you can run a simple test:
_a.scss with $_private: 10px;._b.scss with @forward 'a';.main.scss with @use 'b'; and attempt to access b.$_private.The compiler will throw an error stating that $_private is not a member of module b, confirming that @forward ignores private members.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.