SCSS switching from #import to #use: undefined mixin - sass

For many years I've been completely happy with #import, but times, they are a-changing ...
So I try to shift my projects from #import to #use and #forward, and I found this posting quite useful. But when I try to implement #use into my partials, I keep getting an 'undefined mixin'. I think I may have misunderstood the way #use works, but I can't for the live of me figure out where i went wrong. I've reached the point where I just want to climb the next church tower and start shooting people ... which doesn't help me concentrating either ;)
So I stripped it all down to very basic chunks of code to examine the problem under 'lab conditions'. Here is what I came up whith:
Folders and files:
styles.scss
├── a_tools
│ └── _mixins.scss
├── b_settings
│ └── _global.scss
└── c-components
└── _test.scss
_mixins.scss:
#use '../b_settings/global' as *;
#function bp($bp) {
#return ($breakpoints, $bp);
}
#mixin vp-medium {
#media (min-width: #{breakpoints(small) + 1}) and (max-width: #{breakpoints(medium)}) {
#content;
}
}
_gobal.scss:
$breakpoints: (
'small': 767px,
'medium': 1024px,
'navigation': 840px,
);
:root {
--vp-name: small;
}
#include vp-medium {
:root {
--vp-name: medium;
}
}
_test.scss:
#use 'a_tools/mixins' as *;
#use 'b_settings/global' as *;
.test {
margin: 10px;
#include vp-medium {
margin: 20px;
}
}
styles.scss:
#use 'c_components/test';
Compiling keeps throwing 'undefined mixin on line 15, column 1 of _global.scss', which is the line '#include vp-medium {'. Compiled with Dart Sass 1.32.8.
Who can tell me where I got on the wrong path? Thanks in advance!

As I understand the new ruls #use the way, that you have to #usethe needed files with the needed mixin to EVERY file you want to use it.
If I did get it reight:
You #used the file mixins with mixin vp-medium in test.scss where it is used.
But you did not #use the same file in global where want to use the mixin as well. Just try to #use the file also to global.
ADDITIONAL:
We had similar discussion here: https://stackoverflow.com/a/66300336/9268485

Related

SASS using mixins (breakpoints) in different file

i am struggling with breaktpoints in SASS.
I have this file structure
style.scss
_layout.scss
_variables.scss
I wanna use code breakpotints from _variables.scss in _layout.scss
_variables.scss
$screen-xl-min: 1200px;
#mixin xl {
#media (min-width: #{$screen-xl-min}) {
#content;
}
}
_layout.scss
#use 'variables';
nav {
height: 80px;
#include xl {
background-color: red;
}
}
style.scss
#use 'variables';
#use 'layout';
And I have error
SassError: Undefined mixin.
Can someone tell me, what am I doing wrong? Thanks a lot for a help!
Try and change
#use 'variables'
for
#use 'variables' as *;
Check the documentation: https://sass-lang.com/documentation/at-rules/use
In your example correct way will be write #include variables.xl {}
Or modify #use rule like #Café wrote

How to migrate cases that make use of #content and #import with #content and #forward in SASS

I'm migrating a codebase from using #import to #use and #forward. Most of it is okay but I'm unsure what to do in a case where #import is used with #content.
Considering the following mixing that the only goal is to wrap styles in a class:
#mixin alternative-styles {
.parent-class {
#content;
}
}
The mixin is then used with #import to wrap all those styles in a .parent-class:
#include alternative-styles {
#import 'components';
}
I assumed replacing it with a #forward wouldn't work but have it a try anyway in this way:
#include alternative-styles {
#forward 'components';
}
This threw the following error:
Error: This at-rule is not allowed here.
╷
22 │ #forward 'components';
│ ^^^^^^^^^^^^^^^^^^^^^
╵
I have found that the sass-migration tool solves the issue this way:
#use 'sass:meta';
#use 'mixins';
#include mixins.alternative-styles {
#include meta.load-css('components');
}
The components.scss files has multiple #forward statements to keep all component references in one place like this:
// components.scss
#forward 'components/buttons';
#forward 'components/text';
After the sass compiler runs it results in an empty block:
.parent-class {
}
Is there any way to achieve wrapping a bunch of styles in a class that supports the #use and #forward rules?
I found that the meta.load-css mixin actually does work after creating a separate prototype with the same structure:
#use 'sass:meta';
#use 'mixins';
#include mixins.alternative-styles {
#include meta.load-css('components');
}
More details on using meta.load-css for this case can be found in this GitHub issue: https://github.com/sass/sass/issues/3095
The reason I got the empty .parent-class block was because I was making use of asynchronous compiling with the gulp-sass package. Replacing sass().on(...) with sass.sync().on(...) solved the issue.

Override variables in nested module

Tried many different ways but doesn't seem to work. Hoping someone can shed some light on this
This is what I'm trying to achieve and _variable.scss / _base.scss are coming from a library so I can't modify them
_variables.scss
$color: red !default;
_base.scss
#use 'variable' as base-variable;
.test {
color: base-variable.$color;
}
my-component.scss
#use '_base'; // I want to modify the color in this file, how should it be done?
**expected output
.test {
color: **another color**;
}
I finally figured it out, you can override the whole imported module.
my-component
#use 'variable' as base-variable with (
$color: 'another-color'
);
#use '_base'

How do i change material.io web component fill-color (mdc-top-app.bar)

I have been looking into google material design for web and am also totally new to SASS.
As it stands, i have been trying to change the background-color for the mdc-top-app-bar using the sass mixin fill-color($color) provided in the framework.
Having tried these few lines
#use '#material/button/mdc-button';
#use '#material/button';
#use "#material/top-app-bar/mdc-top-app-bar";
#use "#material/icon-button/mdc-icon-button";
.mdc-top-app-bar {
#include mdc-top-app-bar.fill-color(#8e44ad);
}
Am displayed with the follow error messages
ERROR in ./app.scss
Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: Undefined mixin.
╷
10 │ #include mdc-top-app-bar.fill-color(#8e44ad);
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I completely cooked the last answer but I have worked it out.
instead of:
#use "#material/top-app-bar/mdc-top-app-bar";
#use "#material/icon-button/mdc-icon-button";
use:
#import "#material/top-app-bar/mdc-top-app-bar";
#import "#material/icon-button/mdc-icon-button";
and then to use the mixin,
instead of:
.mdc-top-app-bar {
#include mdc-top-app-bar.fill-color(#8e44ad);
}
use:
.mdc-top-app-bar {
#include mdc-top-app-bar-fill-color(#8e44ad);
}
I hope this helps
--Nathaniel
To avoid import statement you should do:
#use "#material/top-app-bar";
and then
.mdc-top-app-bar {
#include top-app-bar.fill-color(#8e44ad);
}
Also you can create alias
#use "#material/top-app-bar" as topbar;
.mdc-top-app-bar {
#include topbar.fill-color(#8e44ad);
}

Why does my code duplicate the css of a file?

In Sass I have some components (navbar, footer) and some #mixins (fonts) and a function to control the fonts.
I #import the location of the fonts and do #include in the function of the fonts, in this function I just choose the font I want to use.
The problem is that as I separated as "partials" the components (navbar and footer) they have the same sources and I gave #import in those sources in each .scss.
And with that it generates duplicate code in my generated .scss file. I'd like to know what good practices are for this and if I'm doing it right and how do I avoid these duplicates in .scss?
Since I can't see your code, I am not sure how you imported your resources exactly. However, if you are only generating one .css file, a good practice is to import everything on the file that will be compiled and not on each partial.
Let's imagine you have the following structure :
styles
├─ components
│ ├─ _footer.scss
│ └─ _navbar.scss
├─ settings
│ ├─ _functions.scss
│ └─ _mixins.scss
└─ styles.scss
In this example, styles.sccs is the only one that will be compiled, it will be used only to import all partials (the order matters):
// Settings
#import './settings/mixins';
#import './settings/functions';
// Components
#import './components/footer';
#import './components/navbar';
You then can use any mixins or functions in your components and everything is only imported once.
I'm not sure this answers your question – but to prevent duplicates in Sass I would create a mixin to check if an #include has already been made
SCSS
// Global list to keep track of what mixins has been included
$include-once: ();
// Mixin helper to be used inside other mixins we would like
// not to produce duplicate content
#mixin once($mixin-name) {
// check if mixin name exists in our list
#if not index($include-once, $mixin-name) {
// add mixin name to list (using the global flag)
$include-once: append($include-once, $mixin-name) !global;
// print out the content of the mixin
#content;
}
}
// Use example
#mixin font {
// wrap content in the include once wrapper passing the name of the mixin
#include once(font){
// make sure font import is not nested
#at-root {
#import url("https://fonts.googleapis.com/css?family=Open+Sans");
}
}
}
// Test
.foo { #include font; color: red; }
.bar { #include font; color: green; }
.baz { #include font; color: blue; }
CSS Output
#import url("https://fonts.googleapis.com/css?family=Open+Sans")
.foo {
color: red;
}
.bar {
color: green;
}
.baz {
color: blue;
}
I'm sort of late to the game, but I experienced this issue and having partials or using #include did not work. What did it for me was using i.e. css-nano-webpack-plugin https://www.npmjs.com/package/cssnano-webpack-plugin. I'm using webpack v5, so could not get it to work using the webpack mini-css-extract-plugin https://www.npmjs.com/package/mini-css-extract-plugin.
Please bear in mind that the below snippet minimizes and minifies the css PER scss file. So, repetitions between files may still make it in the .css output file.
So, include it in your webpack config like so (source is the npmjs cssnano-webpack-plugin site)
const CssnanoPlugin = require('cssnano-webpack-plugin');
module.exports = {
module: {
loaders: [
{
test: /.s?css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader'
]
}
]
},
optimization: {
minimizer: [
new CssnanoPlugin()
]
}
};
´´´

Resources