How to import SCSS on Component Level with Next.js - reactjs

I am coming from a CRA background and working my way through Next.js version 9.4.2
My project tree looks something like this :-
pages/
_app.tsx
index.tsx
components/
Navbar/
index.ts
Navbar.tsx
Navbar.scss
Inside my Navbar.tsx I have a statement import './Navbar.scss';
This gives me the following error :-
./src/components/Navbar/Navbar.scss
Global CSS cannot be imported from files other than your Custom <App>. Please move all global CSS imports to src/pages/_app.tsx.
Read more: https://err.sh/next.js/css-global
Location: src/components/Navbar/Navbar.tsx
The error, as mentioned, goes away if I move the import Navbar.scss statement to pages/_app.tsx
I know I can switch to Navbar.module.scss, but I don't want to go down the route of modular scss as I expect my scss to get complex I would like to stick to the manner in which I write my scss and not keep finding work arounds to issues that might arise later. I am open to being convinced here but I have not found good read ups on this to choose it as my path.
So by the looks if it, I am stuck with importing all <component>.scss files in _app.tsx. This will leave me with a long list of <component>.scss imports in my _app.tsx and I will also be left with a lot of <component>.scss files for Components that might conditionally not render.
What are my options here ?

Your Navbar.scss file is not named properly.
Let's say your stylesheet contains something like...
$color: red;
.someclassselector {
color: $color;
}
Component stylesheet files have to be named in the following convention for next.js to compile them as addressed in next's css getting started guide
<TheComponent>.module.scss
be imported like this:
import styles from './<MyComponent>.module.scss>';
and be applied to the component like this:
<TheComponent className={styles.someclassselector} />
Not really an expert but it seems that you should stick to class selectors as global selectors can only be declared if you import them in pages/_app.js. You may name a main.scss file to use Global or Tag Element selectors like h1 {},h2{}, * {}, etc.

Related

Import a file as a string (or source asset) in Gatsby / React

I want to import .ts, .tsx, .js, and .jsx files into a react component and render them within a PrismJS highlighting block. For example, let's say I have a TypeScript file with functionA in it that I want to highlight in my actual website:
functionA.ts:
export function functionA() {
console.log("I am function A!");
}
I want to include this in a different component. The problem is, when I import it, I am obviously importing the webpack module version of it. My weak attempt at trying to get my function render in a react component looks like this:
MyComponent.tsx:
import * as React from "react"
import { functionA } from "./functionA"
export function MyComponent() {
return (
<>
<h1>Here is your code block:</h1>
<pre>
<code>
{functionA.toString()}
</code>
</pre>
</>
)
}
and what will actually render on the page where the code block is will look something like this:
Here is your code block:
WEBPACK__IMPORT.functionA() {
console.log("I am function A!")
}
I can't exactly remember what the .toString() function output looked like, but the point is it is NOT just the contents of the file how it appears in a code edit for example - it has been modulized by WebPack.
So, in a Gatsby project, how can i get these various code snippets to be imported directly as a string, purely as they are written, without WebPack enacting its import stuff on it? Is there a plugin or some way to tell Webpack to use the imported file as its asset/source module type? I know for MD or MDX files there is the gatsby-remark-embed-snippet, but I am building a component based HTML page and can't use MD or MDX files!
It's very late, and perhaps I just can't see the forest from the trees, I know there must be a way to do this...
You need to require the file using webpack's raw-loader, i.e:
const functionA = require("!!raw-loader!./functionA");
This works for create-react-app, as in the solution discussed here, and this works for Gatsby as well!
After using require on such a file, the file contents can be rendered in the component as:
<pre>{functionA.default.toString()}</pre>
It's then up to you to add syntax highlighting using a tool like prism or similar.
Note this solution will only work as long as Gatsby V3 continues to use WebPack v4, as raw-loader is deprecated in WebPack v5 and will be phased out for asset/source type modules.

ReactJS mixed all css

First page is Index.js and contains Index.css
Path-> /src/action/Index.js
- src
|
-- action
|
--- Index.js
import '../css/Index.css';
Second page is Customer.js contains Auth.css
Path-> /src/action/User/Customer.js
- src
|
-- action
|
--- User
|
---- Customer.js
import '../../css/Auth.css';
The problem is that both pages are using both CSS files. How can I avoid this?
Those CSS files become global when imported like that. The easiest way is to add classNames to your component like this:
<ComponentA className="a">
Then in corresponding CSS file target the class:
.a {
color: red;
}
In reality you might want to get to know CSS-in-JS solutions like styled-components or learn automatic hashing for CSS with webpack. Check this tutorial for example: https://blog.bitsrc.io/5-ways-to-style-react-components-in-2019-30f1ccc2b5b
Your index.css module should import a "tree" of relevant css modules, using #import "example.css".
I'd recomment to nest it more, to different css modules that import other css themselves, creating a logical tree of css imports.
Using that, the only import you'll need to do is to the root index css.

React How to generate a separate stylesheet for a specific component?

Here I want to generate a separate stylesheet for Landing component and hopefully for other. Other components will have Hero component too. Can anyone tell me how can I do that?. Is it a good idea?.
Anything with an underscore _name.scss, tells your sass compiler that it's a partial scss file. Simply don't use an underscore for single component scss files, for example: Hero.scss. Then in your Hero.js, you can import the style like so:
import './Hero.scss';
<div className="heroContainer">...</div>
or, if your webpack has been configured to allow scss module imports, then you could do:
import { heroContainer } from './Hero.scss';
<div className={heroContainer}>...</div>
If you want to share heroContainer's styles with other stylesheets, simply use the #extend in your scss file.
clientsContainer {
#extend .heroContainer;
}
The downside to this approach is that you'll have to manually import any partials, like _vars.scss, _mixins.scss...etc, and any other dependent stylesheets into each new Example.scss file.
Ideally, if you're working in a large team, it's better to individualize your scss stylesheets, so that everything is modular (components and their styles can be passed off to someone else, instead of having to send ALL of your stylesheets for ONE component).

How to use SCSS variables into my React components

I am working on a React project that follows this structure
src |
components |
Footer |
index.jsx
styles.scss
Header |
index.jsx
styles.scss
scss |
helpers.scss
variables.scss
...
main.scss
Into my variables file I was using the css custom variables so, all them where on :root and I can access them in my components styles.
When I wanted to create the dark colours I wanted to use the SCSS function darken, but it does not evaluate them and throws an error saying that var(--blue) is not a valid colour.
As a solution I decided to move all the variables into a SCSS variables but when project is building it throws another error that says that a $blue is not defined.
The unique solution possible I can use, it is to include the variables file in all the styles files but, I do not know if there are a better solution for the structure that I am using.
From React 17
To access your scss variables into the react component, you need to do something like that
Install node-sass as a dependency or dev dependency
No need to do any config change in webpack
import as a module <-- main point
variables.module.scss
$color: skyblue;
$primaryColor: red;
:export {
color: $color;
primary-color: $primaryColor;
}
App.js
import variables from '<YOUR_PATH>/variables.module.scss';
const App = () => {
console.log(variables);
}
If you don't want to use styled-component
then you can follow this link.
https://til.hashrocket.com/posts/sxbrscjuqu-share-scss-variables-with-javascript
I use a similar structure to organize my .scss files. I like having the styles in the same folder as the component. However, I import all scss files to my main.scss file. This helps avoid style conflicts in the DOM.
main.scss
import "./scss/helpers.scss"
import "./variables.scss"
import "./Footer/style.scss"
import "./Header/styles.scss"
Make sure to name your files with an underscore so that all the files get merged on compilation. Note you don't need to name the underscore in the import.
_helpers.scss
_variable.scss
_style.scss
Using this method you only need to import styles once into your app. index.jsx
There are different ways I can recomend you to tackle this.
1- Duplicate the values of those variables. Add them both on your variables.scss and as constants in some other file, maybe config.js or constants.js that way you'll be able to reference these values from your react components, the downside to this, is you'll have to remember to change them in two places if you have to modify the value.
2- Consider using styled-components. With styled components you can define your styles within your components, using variables or props within the styles.
3- Use some mechanism to define these variables in a single file or as environment variables, and setup your build process to be able to import these values into js and scss files.
It is possible to use custom variables with that project structure using css-vars mixin.
After proposing the option to evaluate custom variables before executing the SCSS function, a guy suggested me this mixin. I have just tested and works pretty nice.

React Component Names Like BEM

I got some great react best practices are here. Grateful to AirBnB https://github.com/airbnb/javascript/tree/master/react
So... Got this idea like BEM for classes, but use for component names and children. A bit tired of happening to search around components.
Like so.. Component__childName__childName__childName.jsx
I have this idea however and would like to know:
Is this a bad practice?
Are component names going to be come unwieldy?
Sort of links the file names all together when its box in a box in a box in a box.
Could get as short as say:
Component__List.jsx
Component__List__Item,jsx
UpdAte question:
Could a separate directory for each component be useful? I am seeing that as well indifferent projects.
For example:
|-Components
|--ExampleComponent
|---Component.jsx
|---ComponentList.jsx
|---ComponentItem.jsx
|---ComponentItemDetail.jsx
|---Component.scss
|--AnotherOne
|---AnotherOne.jsx
And so on...
I guess you are asking for a good naming practice and is it ok to name your components like Component_User.jsx, then if it has a header, Component_User_Header.jsx, then if the header has a label Component_User_Header_Label.jsx. If you are asking smtg else you can just ignore the rest :)
I guess a better approach would be to put related components into a domain folder: such as under user directory index.jsx would be your main component and index.css would be your main css for that component. Then for each subcomponent you can create a similar named files as a sub-directory.
user // main directory
image //sub directory
index.jsx //component file import index.css
index.css //css for this component
header
index.jsx //component file import index.css
index.css
index.jsx //main component file import sub-directories index files to use those components
index.css

Resources