Using css-loader inline with Webpack + React - css

I'm building my React app with Webpack, and css-loader w/modules. I love it. Most of my stylesheets are very small, though, and I'd like to inline them within the same JSX file as my markup and JavaScript.
The CSS loader I'm using right now looks like this:
{ test: /\.(css)$/i,
loader: ExtractTextPlugin.extract("style-loader", "css-loader?modules") }
In my JSX, I import my separate CSS files like this:
import classNames from 'dashboard.css';
...
<div className={classNames.foo}></div>;
This is then compiled and translated into something like:
<div class="xs323dsw4sdsw_"></div>
But what I'd like to do is something more like below, while still preserving the localized modules that css-loader gives me:
var classNames = cssLoader`
.foo { color: blue; }
.bar { color: red; }
`;
...
<div className={classNames.foo}></div>;
Is this possible? How can I do this without having to actually require / import a separate file?

I believe your issue is that you your current webpack configuration uses CSS Modules. CSS Modules automatically rename your CSS Classes to avoid global class name collisions.
The fix:
// remove 'modules' from the end of your css-loader argument
{ test: /\.(css)$/i,
loader: ExtractTextPlugin.extract("style-loader", "css-loader?modules") }
// like so
{ test: /\.(css)$/i,
loader: ExtractTextPlugin.extract("style-loader", "css-loader") }
Now your class names will be preserved. Although, I'm not sure why you want to do this. Do you care to share why?

Related

Target a css class in 'a component generated by library' in react

I have used a chart library. I want to target and modify the properties of the CSS class generated by that library using external CSS. Let's assume the code in inspector is like this-
<div id="apexcharts9xagqubx" class="apexcharts-canvas apexcharts9xagqubx apexcharts-theme-light" style="width: 319.5px; height: 200px;">
<svg id="SvgjsSvg1001" width="319.5" height="200" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.dev/svgjs" class="apexcharts-svg apexcharts-zoomable hovering-zoom">
<div>
the apex chart documentation says I can target .apexcharts-canvas and change the background color. I have done this:
import React from "react";
import ReactApexChart from 'react-apexcharts'
import './apex.module.css'
return (
<div id="chart">
<ReactApexChart options={data.options} series={data.series} type="area" height={200}/>
</div>
);
inside apex.module.css I did this:
.apexcharts-canvas{
background-color: black;
}
now what?
looks like it doesn't work.
It looks like a CSS specifity thing.
You could try including the parent in the selector:
#chart .apexcharts-canvas {
background-color: black;
}
Hey friend when you import a css file with module prefix you shouldn't import that way, that kind of file will be imported giving it a name for example in this image:
This works equally with css extension files, since I am doing it with scss, this rule is for all css file types.
When you declare with module it's not a global style anymore but a style for a component because there is another way to import it but without the prefix module, in the image I already showed you the name of the declared name and then the name of the class.
Luckily my friend, it is not so complicated, I am also learning this little by little.
IF you are using CSS modules (else let me know):
TL;DR
You can either target the HTML element (instead of its class) where .apexcharts-canvas class is used (option 1), or you can make sure the global CSS imports are compatible with the CSS modules (option 2), checking webpack configuration.
I had same issue, I wanted to edit a CSS class in Apexcharts.
I am assumming you are using CSS modules (.module.css).
Option 1
Use this option if:
you used cra or you do not want to edit webpack configuration
it is enough to target the HTML element instead of the class directly
Steps:
The ID of the div where the chart is should be namespaced (CSS modules): id={styles.chart}, with CSS modules file imported as import styles from 'path-to-file'
In code inspector find div with chart id
Drill down until you find HTML element with your class .apexcharts-canvas
In your CSS modules file, target the HTML element with .apexcharts-canvas, using CSS selectors (example below)
.chart > div > div > :last-child {
background-color: black;
}
Option 2
Use this option if:
you can access the webpack config file (not using cra), AND
you want to target class directly
In the webpack configuration, you need to create a rule not only for CSS modules (import styles from 'path-to-file'), but also for global (normal) CSS (import 'path-to-other-file').
(credit: link)
rules: [
{
test: /\.(css|scss)$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: {
localIdentName: "[name]__[local]___[hash:base64:5]",
},
}
}
],
include: /\.module\.css$/
},
{
test: /\.(css|scss)$/,
use: [
'style-loader',
'css-loader'
],
exclude: /\.module\.css$/
},
]
After that you can import a global CSS file (import 'path-to-other-file') with a class .apexcharts-canvas on it.
Important: the webpack rules are mutually exclusive. Files ending with ".module.css" are considered CSS modules, other CSS files not ending like that are global CSS imports.

Is there a way to fetch colors stored from the Back End and place them in SCSS file

At the moment i'am currently re-factoring my code . So that means more clearness and higher maintance . I have an idea in my head , but unfortunately i don't know how this can be realeased.
In order to be more clean and effecient i want to create an isolated _colors.scss file that will contain all of my colors for the app . In other words i want it to look something like this
$colorPrimary: branding.colorPrimary,
$colorSecondary: branding.colorSecondary
...
At the moment is pretty messy because the color styling is maintened at the component level , but i want to do this seperately .
Ex:
<button style={
color: branding.colorPrimary,
background: branding.colorSecondary>
Hello
</button>
The colors are stored on the BE side so if i want to react them i have to do a call . I will be glad if someone can give me a hand with this mindf****. Thank you .
to acheive this behavior you have two main way to do it. the first one describe are not compatible with Internet Explorer.
On last CSS version describe on W3C we are able to have variable directly on CSS.
Like this backend can do something like this :
<head>
<style type="text/css">
:root {
--primary-color: #cecece;
--secondary-color: #fefefe;
}
</style>
</head>
then on your scss (or css) you can do something like :
.mySelector {
color: var(--primary-color, black);
}
which will be basically interpret as :
.mySelector {
color: #cecece;
}
Or fallback in color black if --primary-color is not defined.
As you can imagine, is very easy for backend to prepare the configuration for frontend. And from your side (as front end) you can simply use what is already available on CSS API tools.
But if you are looking for something which are compatible with IE. You probably need more complex infrastructure.
Goal is to spawn webpack sass compilation, on each User color change,
to build css output with relevant variable configuration.
for that you will need SaSS ressource loader which automatically inject sass file on all other file. Is like adding #import "_colors" automatically.
then backend server will have to :
Write _color.scss file somewhere (let say /user/123/_color.scss)
Ask for compilation like webpack client 123
read the output webpack folder for client 123 and detect if specific CSS exist
Inject on your head HTML.
For webpack configuration
on your webpack you will have something like :
const argv = require("yargs").argv;
entry: {
[...]
},
output: {
// Take the argument as clientId and craft dedicated output folder.
path: helpers.root(`public/themes/front/${argv.client}`),
filename: "[name].[contenthash].js",
chunkFilename: "[name].[contenthash].js"
}
Like this base on the client id you will store the outputed CSS on specific folder.
Finally the SaSS rules will looks like :
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'sass-loader',
{
loader: 'sass-resources-loader',
options: {
resources: (argv.client) ? `/user/${ argv.client }/_color.scss` : `/user/default/_color.scss`,
},
},
],
}

React/Webpack applying styles to tags but not classes/ids

I have setup my own react project from some tutorials including my own webpack configuration. When I try to style elements it is able to apply style to generic html tags such as <body> or <p> but it fails when I try to style classes/ids.
I know my css file is being imported because it styles the generic tags.
Webpack Config
{
test: /\.css$/,
use: [
"style-loader",
{
loader:"css-loader",
options:{
modules:true
}
}
]
}
CSS
.oakResults {
font-size:20px;
}
#yoyoyo {
color:red;
}
p {
color:orange;
}
React
<div className='oakResults'>
<p id='yoyoyo'>Results</p>
</div>
In my example, the <p> is colored red, but .oakResults font does not change and when I comment out the <p> style it doesn't turn red.
I want it to be able to style to both generic tags and classes/ids.
I think the reason of this issue is you have enable the css modules in webpack but not referring the css correctly.
So if you don't need the css module, try to remove options:{ modules:true} from your webpack config. Then the css could be applied to the class name you set in ReactJS.
Or if you do need the css module, keep the Webpack config. But modify your ReactJS to something like this:
import React, { Component } from 'react';
import styles from 'path\to\file.css';
class foo extend Component {
render() {
return (<div classname={styles.oakResults}> This is the test component</div>)
}
}
Hope it helps.
You should try this,
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
From the docs,
The modules option enables/disables the CSS Modules specification and setup basic behaviour.
Using false value increase performance because we avoid parsing CSS Modules features, it will be useful for developers who use vanilla css or use other technologies.
Refer more about CSS Modules.

Global variable in SCSS / SASS with angular components

We are developing a cloud application in angular 5 that will be deployed in a single instance but will be addressed to several customer.
The question concerns the management of themes, each customer wants to have his own theme (mainly colors).
The architecture (simplified) of the application looks like this:
--src
--app
app.component.html
app.component.scss
app.component.ts
-- component1
comp1.component.html
comp1.component.scss
comp1.component.ts
...
--scss
-- current
style.scss
_variables.scsc
-- customer1
style.scss
_variables.scss
-- customer2
style.scss
_variables.scss
...
Currently we are deploying by client, so there is no problem, we copy / paste the style in the current before the build.
Each component.scss imports _variables.scss to exploit the variables.
We would like that when a user logs on to the app, we detect the customer and choose the right style, but that the css is generated at compile time.
Is there a way to define global variables that can be modified in runtime and that impacts sub-components?
The solutions I tested:
Set in angular-cli a scss per customer, build and execute script js to modify the html link to css "href = 'assets / {customer} .bundle.css'". It works for global styles, but variables in subcomponents are not updated.
Use pure css to declare scope variables: root {--color-primary: gray; } and exploit them in the sub-components .test {color: var (- color-primary)}.
Make a JS script that will update all the global variables according to the client.
It works, but no equivalent in SCSS? strange
I do not know if I gave enough detail, thanks for the help.
As there is no proper way to do this; And solution used by Angular theming was not satisfactory to us; we've decided to use custom webpack builder that will compile our style based on the entries we provide. Please note, that we are not using SCSS in angular components explicitly.
"use strict";
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const AutoPrefixer = require("autoprefixer");
module.exports = {
entry: {
"modern_style.application": "./src/styles/modern_style.scss",
"default.application": "./src/styles/default.scss"
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].bundle.css"
})
],
module: {
rules: [
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
ident: "postcss",
plugins: [AutoPrefixer()],
sourceMap: true
}
},
{
loader: "resolve-url-loader"
},
{
loader: "sass-loader",
options: {
precision: 8,
includePaths: [],
sourceMap: true
}
}
]
}
]
}
};
These entry files will have their variables set & customizations applied in each respective entry file, which looks like this:
// Entry file: modern_style.scss
$someVariableToBeUsedOrOverwritten: red;
#import "common/allModulesAreImportedHere"
.customRule{
//...
}
This generated style, e.g default.bundle.css is then loaded via <link rel="stylesheet" type="text/css" [href]="linkToTheme">
There is no way to pass any variables from ts to scss.
All you need is theming.
So for each customer you need a global body class whith its own set of variables / classes.
Check out angular material theming docs for example https://material.angular.io/guide/theming#defining-a-custom-theme
Mixins will solve your issue.
In the specific customer scss files, you would be holding the specific definition.
In the component.scss, you would be using the mixin, which is specific to the customer and it will resolve your issue on both compile and run time.

Best way to have global css in Vuejs

What is the best way to have a global css file in Vuejs for all components? (Default css like bg color, button styling, etc)
import a css file in the index.html
do #import in main component
put all the css in the main component (but that would be a huge file)
Import css in your index.html, but if you're using webpack you can just import your stylesheets in your main js config and all your components will get the css.
As comments below suggested if using webpack adding this to main.js works:
import './assets/css/main.css';
I found the best way is to create a new file in the assets folder, I created as global.css but you can name anything of your choice. Then, import this file global.css file in the main.js.
Note: Using this approach you can also create multiple files if you think the global.css is getting really large then simply import all those files in the main.js.
#\assets\global.css
/* move the buttons to the right */
.buttons-align-right {
justify-content: flex-end;
}
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './routes'
Vue.config.productionTip = false
// Importing the global css file
import "#/assets/global.css"
new Vue({
router,
render: h => h(App)
}).$mount('#app')
In App.vue you can add a style property to declare you CSS file:
<style>
#import './assets/css/global.css';
</style>
You can also do something like this: https://css-tricks.com/how-to-import-a-sass-file-into-every-vue-component-in-an-app/
My folders are mostly structured like this:
- src
- assets
- _global.scss
- _colors.scss
- _fonts.scss
- _paragraphs
- index.scss // <-- import all other scss files.
This also works with normal css.
create a new css file in your assets folder for example : global.css
import "global.css" to main.js
import '#/assets/main.css';
There are to two ways, as I know, to achieve this.
Approach 1
Utilize vue.config.js configuration, less config can also be replaced with sass:
module.exports = {
css: {
loaderOptions: {
less: {
additionalData: `#import '#/style/common.less';`
}
}
}
}
Approach 2
In your .vue file, make your style looks like this:
<style lang="less">
#import (reference) "../../style/variables.less";
#app {
background: #bgColor;
}
</style>
Note: the (reference) flag is used to make variables defined in variables.less take effect. If you don't have variables, #import "../../style/variables.less"; is sufficient to do the trick.
For your reference, you can also take a look at this link:
https://github.com/tjcchen/vue-practice/tree/master/multipage-app
Sass announced their new module system. Why don't you use #use and #forward?
My approach is the best way to use scss with vite.
Use defineConfig to setup global scss (colors, mixin) and reuse in all component without import
css: {
preprocessorOptions: {
scss: {
additionalData: `#use "~/styles/main.scss" as *;`,
},
},
},
Here: code sandbox
create a vue.config.js file in your root directory
Create a styles folder inside your src folder and you can create your global style file here for example base.scss
to use scss install two dependencies
npm install node-loader sass-loader
Inside your vue.config.js paste code from below
module.exports = {
css: {
loaderOptions: {
sass: {
additionalData: `#import "#/styles/base.scss";`
}
}
}
};

Resources