Include sass in gatsby globally - sass

I have the following project structure:
gatsby-config.js
/src
/components
layout.jsx
/button
button.jsx
button.scss
/pages
/styles
styles.scss
_mixins.scss
_variables.scss
and gatsby-config.js and styles.scss are configured respectively in the following way:
...
plugins: [
...,
`gatsby-plugin-sass`
]
...
#import 'variables',
'mixins';
in order to access the mixins and variables, the styles.scss is being currently imported in all the components' scss files, e.g.:
//button.scss
#import './../styles/styles.scss'
This approach is working, but the problem is, as the project grows, the styles.scss is being imported multiple times and seems to be something wrong with this approach.
Is it possible to import styles.scss only once, and make all mixins and variables available across all the components?

You are able to pass options to Sass via gatsby-plugin-sass.
The following options would globally expose the contents of ./src/styles/_styles.scss to each Sass file in the project, without the need to explicitly import it.
module.exports = {
plugins: [
{
resolve: 'gatsby-plugin-sass',
options: {
data: `#import "${__dirname}/src/styles/styles";`,
}
},
],
}
Note: The below might be obvious to some but it's worth mentioning for future readers.
Only do this with Sass files that contain just variables, mixins, functions, etc (Sass features that do not output any actual CSS until they are consumed). Otherwise you will end up with CSS that is repeated multiple times across your project.
Example repo

Providing SCSS variables globally to your components
With #use
SCSS syntax
gatsby-plugin-sass
Component-Scoped Styles with CSS Modules
gatsby-plugin-sass config
gatsby-config.js file:
{
resolve: `gatsby-plugin-sass`,
options: {
implementation: require("sass"),
data: `#use "${__dirname}/src/global-styles/variables" as var;`
}
},
var will be used as namespace.
Providing variables to your scss files
./src/global-styles/_variables.scss
./src/components/main.jsx
./src/components/main.module.scss
Info about the underscore in _variables.scss, partials.
_variables.scss file:
$color-1: red;
$color-2: blue;
main.jsx file:
import React from 'react'
import style from './main.module.scss'
const Main = () => (
<div className={style.main}>Content</div>
)
export default Main
main.module.scss file:
.main {
color: var.$color-1;
}
But I need expose some global styles in gatsby-browser.js
Well, your are going to need #use, or follow other answers that use #import in gatsby-config.js. Mixing #import and #use may not work because of:
Heads up!
A stylesheet’s #use rules must come before any rules other than #forward, including style rules. However, you can declare variables before #use rules to use when configuring modules.
https://sass-lang.com/documentation/at-rules/use
I stopped using #import, only using #use.
global-styles.scss file:
#use "./variables" as var;
body {
color: var.$color-2;
}
gatsby-browser.js file:
import './src/global-styles/global-styles.scss'

Create a file named gatsby-browser.js in the root of your directory. Import the .scss file once and it will work perfectly .
In your gatsby-browser.js
import "./src/styles/styles.scss"

As Ankit Sinha mentioned, you can import your styles in gatsby-browser.js:
import './src/styles/styles.scss';
This method is mentioned in the Gatsby tutorial.
According to the docs (see Standard Styling with Global CSS Files):
The best way to add global styles is with a shared layout component.
Your project structure suggests that you are using one (layout.jsx). If that's the case, you can also import your styles in layout.jsx:
import './../styles/styles.scss';

I cant write comments yet. I dont have the reputation. But what a complete answer from Undefined Behavior.
Just to order a little bit:
Import your global-styles.scss in gatsby-browser.js
Configure something that's going to be exposed to all scss files, in your gatsby-config.js.
It can be an #import or an #use. With #import you access directly to your variables and mixins and with #use you reference it. I don't really know what are the benfits of both, but you could use any.

Related

In a partial SASS file, how can I use a variable defined in the parent?

In my main.scss file, I use the following two partials with #use:
#use 'variables' as v;
// #forward 'variables'; // doesn't work
#use 'layout';
In _layout.scss, I try to use this variable:
h1 {
color: v.$mainHeaderColor;
}
But it gives me the error:
There is no module with the namespace "v".
color: v.$mainHeaderColor;
How can I load all my partials in my main.scss so that every partial can use every other partial, which was possible with #import i.e. before #use namespaces.
There is no module with the namespace "v". - color: v.$mainHeaderColor;
Your receiving the error when compiling main.scss because the _layout.scss partial file doesn't know about the namespace "v" and wasn't able to load the members like $mainHeaderColor from the _variables.scss module. This happens because _layout.scss doesn't have a #use rule loading the members from "variables", therefore it can't access variables defined in that module.
A "quick" fix would be to introduce a #use rule in your _layout.scss file to load the variables from _variables.scss like this:
#use "./variables" as v;
/* _layout.scss */
h1 {
color: v.$mainHeaderColor;
}
Now there really isn't a need to use #forward with your current structure as its only two partial files being loaded into main.scss. If you want to use #forward I'd recommend reading further and setting up directories with index files.
To update your main file, this is how loading the files with #use at-rules into main.scss would look:
#use 'variables' as v;
#use 'layout';
/* main.scss */
/* Use the loaded members from '_variables.scss' inside the main file */
.demo {
color: v.$mainHeadColor;
}
Using #use rules along with #forward and index files
With the #import at-rule slowly being phased out of the main implementation of Sass, (dart-sass). It's time for us to adopt #use rules and learn how to utilize the cool features like index files with #forward and setting custom namespaces for loaded modules.
Since #import at-rules made everything globally accessible, this is where I've seen most of the confusion around usage of #use come into play. We have to make sure all files have appropriate knowledge of variables, mixins, functions etc if they aren't defined in the same partial or file.
If you have a main.scss Sass file that is going to be compiled with two (or more) imported partial files. The best way to utilize #use and #forward rules is by creating a directory at the same level as your main.scss file (or elsewhere just use the correct path) and create an index file, _index.scss to load the entire directory of partials with a single #use rule.
Note: All #use at-rules must be placed at the top of the file.
This index file will be where you place your #forward rules, using #forward "<url>"; for each partial you want to load into the index file. Think of it as one big module that you can load elsewhere with a single #use rule in your main.scss file, thus giving you access to all of the partial files loaded into that index file within the /partials directory.
- main.scss
- partials/
- _index.scss
- _variables.scss
- _layout.scss
...
Going along with the example, lets say your _variables.scss partial file looked like this and wasn't relying on any other files:
$mainHeaderColor: #222;
$someOtherVar: #f06;
and if the _layout.scss partial wanted to use variables defined in _variables.scss, we would have to include a #use rule to let _layout.scss "know" about the loaded members.
#use "./variables" as v;
/* _layout.scss */
h1 {
/* now this works as expected */
color: v.$mainHeaderColor;
}
If you didn't want to define a namespace when loading with #use, simply write #use "<url>" as <namespace>; where the namespace being an asterisk * signals that a namespace won't be defined so you can use it like color: $mainHeaderColor instead of v.$mainHeaderColor. Note, this can leading to naming conflicts if your not careful.
Now to load these partials into the main.scss file which will be compiled, you could either use two separate #use rules for the _layout.scss and _variables.scss partials or create an index file (_index.scss) and load the /partials directory with a single #use at-rule giving you access to all the partials in the directory.
#forward "./variables";
#forward "./layout";
/* partials/_index.scss */
Voila! Now all that is left is to load the /partials directory into the main.scss file to be compiled and maybe used later on. The _layout.scss partial is loaded into main.scss through our single #use rule and we also have access to _variables.scss variables or any other partial file that was forwarded in the index file.
#use "./partials" as *;
/* main.scss */
h2 {
color: $mainHeaderColor;
background: $someOtherVar;
}
If you had a directory of mixins like ./mixins, then you would follow the same workflow of placing all partial files inside the /mixins directory and then create an _index.scss file to load the partials with #forward rules. To finally load the directory with a single #use rule giving you access to all of the partials loaded in a specific directory through an index file. I used the /partials directory as a "starting" point but it would make more sense to create a directory /vars, /mixins etc and place files in their respective directories for better structure/organization.

Angular 6 style.scss not globally applied into the components

I created a new cli project with --style=sass and then defined some variables in the src/sass/styles.scss (no partials created) so they should be globally defined right? , so when i tried to use them in home.component.scss i got this error https://imgur.com/a/IckJL14
i then added a black border just to make sure normal css works and it did work , the problem is with sass ,
here's the angular.json
"styles": [
"src/sass/styles.scss",
"./node_modules/bootstrap/dist/css/bootstrap.min.css",
"./node_modules/malihu-custom-scrollbar-
plugin/jquery.mCustomScrollbar.css",
"./node_modules/animate.css/animate.min.css",
edit: i then created a partial _variables.scss and in the component.scss i wrote #import '~sass/variables'; after importing them in the styles.scss like so #import './variables'; according to the guide from this link : https://scotch.io/tutorials/using-sass-with-the-angular-cli
still not working.
The best approach to achieve this, is creating a variable file and import this file in your scss files.
Like so:
#import "../../variables.scss";
or
#import "~variables.scss";
And in your styles.scss you just put a reference of your variable file!
If it's correct that you used the --style=sass option on project init, then that might be the problem. If you intend to use .scss files (which I would recommend), then you should have used --style=scss.
To fix this now, you can run the command ng set defaults.styleExt scss.
the answer was to simply add the full path to the component.scss like so,
#import "src/sass/~variables.scss"; instead of just #import "~variables.scss";

How to import global SCSS file in a React/Redux project?

I'm using react-redux-starter-kit for my project. I want to know how it is possible to create a global SCSS file that when imported in _base.scss, it will affect the whole project. I've tried to #import like in the examples within the file, but nothing works. Strangely, it seems to have worked with #import './fonts/*';
I have the following structure:
styles/
----/components/
--------/Dashboard
--------/Home
--------_default.scss
----/fonts/
----_base.scss
----core.scss
And therefore, the _base.scss is like this:
#import './components/_default'
But it doesn't work. No errors are shown. I've tried also to create a theme/default.scss, just like the example in the commentary within the file, but also no effect.
In your root component just import your main scss file like you would import a module:
require('path/to/styles/_base.scss')
or:
import 'path/to/styles/_base.scss'
Just make sure that in your webpack config there is:
{
test: /\.scss$/,
loader: 'style!css!sass',
}

How to pre-load SASS custom utilities (variables and mixins) with webpack

I am loading my utilities and assets in base.scss like so
#import "_variables";
#import "_mixins";
...
I have tons of modules in my application and we are doing so many changes in these modules.
so importing the base.scss in the header of each of the scss files is causing so much trouble and seems very redundant.
I tried using sass's includePaths but it didn't help as it only resolves the #import declarations.
Is there any way that I can auto import my utilities without having to #import it manually in each file?
This loader will do the job
https://github.com/shakacode/sass-resources-loader
by adding this to your webpack config
sassResources: [ './path/to/vars.scss', './path/to/mixins.scss' ]
Update
check the implementation out in action in this boilerplate
In Webpack 5, this is how I did it:
{
loader: 'sass-loader',
options: {
sourceMap: true,
additionalData: `#import "${__dirname}/src/int/css/_mixins.scss";`
},
Simply add the path to your e.g. SCSS Mixin or variable file to "additionalData".

webpack to allow import of all sass files? i.e #import 'components/**/*'

I'm currently using css-loader, node-sass, sass-loader and style-loader packages within webpack to compile my sass files, here is how my loader looks at the moment:
{
test: /\.scss$/,
loader: 'style!css!sass'
}
I want to use folder structure like this for my styles
styles
components/
main.sass
and somehow within main.sass I want to import everything from components folder so something like #import './components/**/*' is this possible via webpack?
You can prefix a Sass import with '~' to tell the Sass loader to use webpack's require() resolution on the import. Once webpack is in charge of the import you have some flexibility.
If you do a dynamic require, e.g. require('~./components/' + someVar + '.scss'), webpack can't evaluate the variable at build time and it bundles all the possible files in that directory, and the actual resolution of the require() happens at runtime (which can lead to errors at runtime if you've asked for something that doesn't exist). Not sure off the top of my head if that would give you what you need (all the files bundled) or if you would still need to explicitly require() each partial -- but if that's the case you could easily loop through all the files in the directory and require each one.
More on how you can leverage webpack's dynamic requires and loading context.

Resources