Why are my global style modules being imported multiple times? - css

I have tried to set up some global Scss in my Gatsby application, but it looks like after doing this i am seeing some odd behaviour in dev tools:
You can see that my global styles are appearing and being overwritten multiple times.
It is a Gatsby app so i am using sass-loader and the default dart-sass.
Here is how i have configure my gatsby-config.js file to allow me to use these global styles based on this stackoverflow post: https://stackoverflow.com/a/65904094/12119984
module.exports = {
plugins: [
...
{
resolve: `gatsby-plugin-sass`,
options: {
additionalData: `#use 'main' as *;`,
//allow mixins, variables etc to be accessible globally
sassOptions: {
includePaths: [`${__dirname}/src/styles/sass`],
// data: `#import "main.scss";`,
},
},
}...
I the use #forward along with #extend to get it all working in my module.scss files. My folder structure looks like this:
My global styles are in base.scss and I import them into main.scss using #forward:
#forward "base";
#forward "layout";
#forward "components";
As an exmaple, here is my index.module.scss file where i then use these global styles:
.sectionHome {
...
h1 {
background-color: $color-secondary;
#extend .uMarginBottomLarge;
#extend .headingPrimary;
}
}
It seems like a reasonable approach to me to use some global styles but to extend them into local sccs module classes, so can anyone explain to why these global styles are being applied several times?

The #forward rule, according to the docs:
The #forward rule loads a Sass stylesheet and makes its mixins,
functions, and variables available when your stylesheet is loaded with
the #use rule. It makes it possible to organize Sass libraries across
many files, while allowing their users to load a single entrypoint
file.
So basically, each time you are requesting a CSS module in some component, you are importing all the nested extensions (#extend and #use). Moreover, because of React's component extensions, you may also nest styles when importing nested components (Button in Layout, Layout in a index.js, etc)
Global styles in CSS apply exactly in the same way as CSS "standard" files, as you can see in Gatsby's docs, extending its documentation, you will need to add the following in your gatsby-browser.js:
import "./src/styles/sass/main.scss"

Related

Webpack css-loader: how to import file to a specific place in the code?

In order to use Angular style encapsulation for specific parts of the app I want to load with css-loader the styles from another file to another place with preserving the structure of the top-level file. In my .less file I have a code like this:
:host ::ng-deep {
#import '~ag-grid-community/dist/styles/ag-grid.css';
#import '~ag-grid-community/dist/styles/ag-theme-balham.css';
}
The point here is to use less syntax to add :host ::ng-deep prefix to every rule in the imported files. However the structure is not preserved, so it works as if the files were imported outside of the outer selector. eventually, after using require(css-loader!./myfile.less).toString() it works like this:
#import '~ag-grid-community/dist/styles/ag-grid.css';
#import '~ag-grid-community/dist/styles/ag-theme-balham.css';
:host ::ng-deep {
}
With imports replaced by their contents.
The current stack of loaders are css-loader, postcss-loader and less-loader.
Is there a way to keep the structure with the current loaders? If not, in your opinion, what is the best way of solving this problem?

Angular External Style in Angular.json or Styles.scss

I want to include an external style from a module in node_modules. Which is considered better practice?
Add the stylesheet to Angular.json in the application's build: styles: [], e.g.
"build": {
"styles": [
...,
"node_modules/leaflet/dist/leaflet.css"
}
}
Import the stylesheet into the application's styles.scss file, e.g.
#import "~leaflet/dist/leaflet.css";
If I were using styles.css instead of styles.scss, the second wouldn't work. However, given that I'm using SASS, I'm wondering if the second is preferred because it keeps Angular.json cleaner.
Are the two functionally equivalent or is there an important distinction that makes one better than the other?

Gulp sass not defining variables & mixins across all imports?

I'm compiling my SCSS with gulp-scss. My styles.scss file looks like this:
#import "node_modules/bulma/sass/utilities/initial-variables";
#import "node_modules/bulma/bulma";
#import 'src/styles/navigation';
The second line of this code imports Bulma, the source code for which can be found here. This file imports some utilities, including some mixins I need.
Unfortunately when I try to use those mixins in my navigation.scss file:
#include desktop {
.navbar {
min-height: 135px;
}
}
I get the following error:
Worth noting that if I #import the mixins and variables file in navigation.scss directly, it works fine. What's going on here?
The problem was with my file names. They were not preceeded by an underscore, which appears to be the convention for the compiler to work properly. So src/styles/navigation.scss became src/styles/_navigation.scss. The import remained the same:
#import 'src/styles/navigation';
I will assume you use gulp-sass.
What I usually do is creating a path in the gulp file for better reference and also for letting know gulp I will be using these node resources in .scss files.
In this case I'm calling foundation and compass mixins modules in the include paths.
This is a task in the Gulfile.js
gulp.task('styles', function () {
gulp.src('src/scss/application.scss')
.pipe(sass({
includePaths: [
'node_modules/foundation-sites/scss',
'node_modules/compass-mixins/lib'
],
outputStyle: 'compressed'
}).on('error', sass.logError))
.pipe(gulp.dest('./public/css/'))
});
Then in your main .scss or where you want to place the import for those files you can just simply add:
#import 'compass';
#import 'foundation';
#include foundation-everything;
Here I call the compass file inside this node module path I specified in the gulp file, and also the foundation.scss (which imports a lot of other scss files).
Then once foundation is availabe I initialize all the mixins.
So summing up:
Possible solutons:
1: Check if this gulpfile definition with include path solves you routes errors.
2: check if the modules you are importing don't have a trigger mixin to enable them, such as foundation has his "foundation-everything"
Hope this helps.

Accessing global sass variables and bootstrap in .vue files

I need my Vue components to inherit styling and variables from other "global" imports.
I do not want to import variables and bootstrap in every single component, this seems very redundant and not best practice.
It is basic usage so Vue must have made the functionality. I have already attempted to create a base component, an "app.vue" component if you will, that has its own styling that includes the variables and bootstrap, but my components can still not access it.
Any idea?
You can do this with webpack's sass loader options that name is 'prependData'. This code will be added top of every .vue file that consist of scss style. I know this is ugly but It works. As bootstrap documentation said. You have two choices about this. One of these is adding whole bootstrap files another one is this technique.
You can check here bootstrap documentation.
// webpack.config.js
loader: 'sass-loader',
options: {
prependData: "#import '~/node_modules/bootstrap/scss/_functions.scss'; #import '~/node_modules/bootstrap/scss/_variables.scss'; #import '~/node_modules/bootstrap/scss/_mixins.scss';"
}
I know of no other way than #import the variables file in each component. Much like we have to import/require the npm libs we use in each component.

Sass with CSS Modules & Webpack

I've been building a project for a while using Webpack, Sass, and CSS modules. Normally in my .scss files, I define a class like:
:local(.button) {
color: white;
}
and in my React components, in the render method, I require the styles:
render = () => {
const styles = require('./MyStyles.scss');
<div className={ styles.button } />
}
and all is good with the world. Everything works as expected.
Now today I was reading through the CSS Modules page and noticed that none of the selectors were encompassed by :local() like mine and furthermore that they were importing the styles like:
import styles from './MyStyles.scss';
And I thought "Wow that looks much nicer, it's easier to see where it's imported, ect. And I'd love not to use :local() and just have things local by default." So I tried that and immediately ran into several problems.
1) `import styles from './MyStyles.scss';
Because I'm using ESLint on my React files, I immediately get an error thrown that MyStyles.scss doesn't have a default export which would normally make sense but the CSS Modules page stated:
When importing the CSS Module from a JS Module, it exports an object with all mappings from local names to global names.
so I naturally expected the default export of the stylesheet to be the object they're referring too.
2) I tried import { button } from './MyStyles.scss';
This passes linting but button logs as undefined.
3) If I revert to the require method of importing my styles, anything not specified with :local is undefined.
For reference, my webpack loader (I'm also including Node-Neat and Node-Bourbon, two awesome libraries):
{ test: /.(scss|css)$/, loader: 'style!css?sourceMap&localIdentName=[local]___[hash:base64:5]!resolve-url!sass?outputStyle=expanded&sourceMap&includePaths[]=' + encodeURIComponent(require('node-bourbon').includePaths) +
'&includePaths[]=' + encodeURIComponent(require('node-neat').includePaths[1]) + '&includePaths[]=' + path.resolve(__dirname, '..', 'src/client/') }
My questions, following all of this, are:
1) When using CSS Modules with Sass, am I confined to using either :local or :global?
2) Since I'm using webpack, does that also mean I can only require my styles?
Soon after posting, I figured out the solution. The problem, which I thought was quite confusing, was in my Webpack config. Originally my loader looked like:
loader: 'style!css?sourceMap&localIdentName=[local]___[hash:base64:5]!resolve-url!sass?outputStyle=expanded&sourceMap
which enabled to me to 1) require my Sass and 2) wrap my styles in :local.
However, the css loader was missing the modules option so that it looked like:
loader: 'style!css?modules&sourceMap&localIdentName=[local]___[hash:base64:5]!resolve-url!sass?outputStyle=expanded&sourceMap
Now I can import my styles and I don't have to wrap them in :local (although I presume I still can if I want to).
What I found most interesting about all this is that without the modules option, one can still use CSS Modules-esque features, although somewhat limiting.
EDIT:
Something I noticed, a future warning to whomever looks at this answer, is if you're using the eslint-plugin-import to lint the imports in your javascript code, it will throw an error upon importing styles like:
import styles from './MyStyles.scss';
because of the way CSS Modules exports the resulting styles object. That does mean you'll be required to do require('./MyStyles.scss') to bypass any warnings or errors.

Resources