How to setup react app with SCSS? (Errors) - reactjs

I am trying to setup my react project so I can use SASS in the SCSS format.
This is in my webpack.config.dev.js:
{
test: /\.scss$/,
exclude: /node_modules/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
},
},
{
loader: require.resolve('sass-loader'),
}
]
}
I import the scss files into my jsx in two different ways:
import './index.scss';
import css from './ModalWrapper.scss';
When I run the app I am currently getting the error:
./src/index.scss
Module build failed:
body {
^
Invalid CSS after "m": expected 1 selector or at-rule, was "module.exports = __"
in /pathtoapp/web/src/index.scss (line 1, column 1)
It appears me, that one, react is trying to interpret the SCSS as CSS which should work. In addition, react believes that body is not valid CSS. There, I would believe that neither CSS or SCSS are being loaded correctly.
Any help would be appreciated. There are quite a few unanswered questions to this problem.

If you are on Webpack 3, add this to module.rules
{
test: /\.scss$/,
loader: [
require.resolve('style-loader'),
require.resolve('css-loader'),
require.resolve('sass-loader'),
]
},
And then add the file loader and make sure to add .scss to the array of the key exclude like this
{
loader: require.resolve('file-loader'),
// Exclude `js` files to keep "css" loader working as it injects
// it's runtime that would otherwise processed through "file" loader.
// Also exclude `html` and `json` extensions so they get processed
// by webpacks internal loaders.
exclude: [/\.js$/, /\.html$/, /\.json$/, /\.scss$/,],
options: {
name: 'static/media/[name].[hash:8].[ext]',
},
}
And of course, make sure you have style-loader, sass-loader, css-loader and file-loader in you package.json. This code snippet worked for me when using the latest version of create-react-app.

This is what ended up working for me:
{
test: /\.scss$/,
use: [{
loader: 'style-loader'
}, {
loader: 'css-loader',
options: {
modules: true,
sourceMap: true,
localIdentName: "[local]___[hash:base64:5]",
},
}, {
loader: 'sass-loader',
options: {
outputStyle: "expanded",
sourceMap: true,
},
}]
},

I'm sure the other answers are just as good, but for maximum brevity, this works for me (I erased some of the internal webpack.config.dev.js comments presumably made by the create react folks):
module: {
strictExportPresence: true,
rules: [
{
test: /\.scss/,
use: ['style-loader','css-loader', 'sass-loader']
},...
I don't know if it matters, but I put this on the top. Also, yes, make sure to add the scss file to the excluded array as mentioned above.

Related

ReactJS custom webpack config, trying to hash css class names while using both css-loader and sass-loader

My .css or .scss files won't load at all.
What I'm trying to achieve is to hash my class names using css-loader option localIdentName.
I'm working on ReactJS with custom webpack config. This is one of my rules inside webpack.config.js:
{
test: /(\.css|\.scss|\.sass)$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
options: {
modules: {
localIdentName: "[path][name]__[local]--[hash:base64:5]",
}
},
},
{
loader: 'sass-loader',
options: {
},
},
],
},

How to setup babel-plugin-react-css-modules in create-react-app?

I really like the separation of className and styleName that babel-plugin-react-css-modules offers for global and local styles respectively, but have had some trouble getting the plugin to work with create-react-app.
I've tried installing the plugin by running
npm install babel-plugin-react-css-modules --save
... as it says to do in the project (github https://github.com/gajus/babel-plugin-react-css-modules#css-modules) ...
... and have also used craco as suggested in a similar thread (#5113) to help overcome the limitations of create-react-app without the need to eject, but am still unable to import a scss file and reference to it using styleName.
Does anyone know if I'm missing something else here? Sorry if it's a noob question, I'm new to React and have been looking for a solution to this for a while now.
1. add the plugin to .babelrc first.
"plugins": [
["babel-plugin-react-css-modules",
{
"webpackHotModuleReloading": true,
"autoResolveMultipleImports": true
}],....
]
2. add css rule in webpack.config.js.
below is my configuration that you can reference from.
make sure that
2.1 option modules set to true.
2.2 localIdentName follow this format. localIdentName: "[path]___[name]__[local]___[hash:base64:5]"
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
use: [
{
loader: "babel-loader",
options: { cacheDirectory: true }
}
]
},
{
test: /\.css$/i,
use: [
{
loader: ExtractCssChunks.loader,
options: { hot: true }
},
{
loader: "css-loader", //generating unique classname
options: {
importLoaders: 1, // if specifying more loaders
modules: true,
sourceMap: false,
localIdentName: "[path]___[name]__[local]___[hash:base64:5]" //babel-plugin-css-module format
//localIdentName: "[path][name]__[local]" //recommended settings by cssloader#local-scope , this option generate unique classname for compiled css
}
}
]
},

Unable to skip 3rd party library CSS from CSS-Module transformation

I am trying CSS Modules for the first time with React and Webpack and I came across at least three ways to achieve it:
css-loader
react-css-modules
babel-plugin-react-css-modules
I went with babel-plugin-react-css-modules in order to balance code simplicity and performance and everything seems to be working fine except for one thing: my 3rd party libraries (Bootstrap and Font Awesome) are also included in CSS Modules transformation.
<NavLink to="/about" styleName="navigation-button"></NavLink>
The above assigns a properly transformed className to the NavLink. However, a span inside needs to refer to global styles in order to render an icon.
<span className="fa fa-info" />
The above span is not assigned a transformed className which is expected, but my bundled stylesheet does not have these CSS classes as they are being transformed into something else, to simulate local scope.
Below is the content in my .babelrc file to activate babel-plugin-react-css-modules:
{
"presets": ["env", "react"],
"plugins": [
["react-css-modules", {
"generateScopedName": "[name]__[local]___[hash:base64:5]",
"filetypes": {
".less": {
"syntax": "postcss-less"
}
}
}]
]
}
In my Webpack configuration, below is the section to configure css-loader for transforms:
{
test: /\.(less|css)$/,
exclude: /node_modules/,
use: extractCSS.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
minimize: true,
modules: true,
sourceMap: true,
localIdentName: '[name]__[local]___[hash:base64:5]'
}
},
{
loader: 'less-loader'
}
]
})
}
As far as I have read, the above rule should exclude the library stylesheets and I also tried adding another rule specifically for the excluded stylesheets, however that did not seem to work, as I guess as those stylesheets were still transformed with the original rule.
In order to import CSS from the two libraries, I have the below two lines in my parent stylesheet that declares some global styles:
#import '../../../node_modules/bootstrap/dist/css/bootstrap.min.css';
#import '../../../node_modules/font-awesome/css/font-awesome.min.css';
I find these two approaches below might be helpful:
https://stackoverflow.com/a/52294675
https://github.com/css-modules/css-modules/pull/65#issuecomment-412050034
In short, there seems to be no options to ignore/exclude certain paths from being modularized by the css-modules webpack plugin so far. Ideally it should be supported by the plugin, but here're some approaches you can try out:
use two webpack rules to utilise the webpack rule exclusion/inclusion:
module.exports = {
rules: [
{
test: /\.css$/,
exclude: /node_modules/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[path]__[local]___[hash:base64:5]',
},
},
],
},
{
test: /\.css$/,
include: /node_modules/,
use: ['style-loader', 'css-loader']
}
]
}
...or, inject into webpack's getLocalIdent from the second answer above to manually exclude certain paths.
const getLocalIdent = require('css-loader/lib/getLocalIdent');
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]',
getLocalIdent: (loaderContext, localIdentName, localName, options) => {
return loaderContext.resourcePath.includes('semantic-ui-css') ?
localName :
getLocalIdent(loaderContext, localIdentName, localName, options);
}
}
}
For me using :global worked :
.my-component {
:global {
.external-ui-component {
padding: 16px;
// Some other styling adjustments here
}
...
}
}
Ps: for doing it with webpack config, please see another answer.
source
Updated solution from playing771
{
loader: 'css-loader',
options: {
modules: {
auto: (resourcePath) => !resourcePath.includes('node_modules'),
localIdentName: '[name]__[local]__[hash:base64:5]',
},
},
},

Using Webpack with SASS and PostCSS in Angular2

Init
Im trying to use webpack with the sass-loader and the postcss-loader. I already tried different solutions but nothing worked like I want it to.
I tried the solution from Angular 2 Starter Pack with the raw-loader and the sass-loader, but than the postcss-loader didnt work.
Code
Angular 2 Component
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
// styles: [
// require('./app.component.scss')
// ]
})
Webpack module loader
{
test: /\.scss$/,
loaders: ['to-string-loader', 'css-loader', 'postcss-loader', 'resolve-url-loader', 'sass-loader']
}
Problem
With these code lines everything works but the styles are added in the <head> tag within the <style> tag. At some point I would have hundreds of style lines which I want to avoid.
If I change my loader code to this:
loader: ExtractTextPlugin.extract('to-string-loader', 'css-loader', 'postcss-loader', 'resolve-url-loader', 'sass-loader?sourceMap')
and add this to the webpack config
plugins: [
new ExtractTextPlugin('style.css')
]
it results in an error
Uncaught Error: Expected 'styles' to be an array of strings.
The style.css is actually linked in the html code.
Im searching for a solution which allows me to use sass, postcss and a single .css file.
I just ran into this issue and figured out a solution. I'm pretty sure its the "to-string-loader". The dev config below is working for me using Webpack 4 and Angular 7. It allows a global stylesheet (Tailwind CSS in my case) alongside component styles. Hot module replacement is also working for editing both entries.
entry: {
app: './src/main',
styles: './src/assets/styles/styles'
},
resolve: {
extensions: ['.ts', '.tsx', '.mjs', '.js', '.scss'],
},
module: {
rules: [
{
// Process the component styles
exclude: path.resolve(__dirname, 'src/assets/styles/styles'),
test: /\.(scss)$/,
use: [
{ loader: 'raw-loader' }, // Load component css as raw strings
{
loader: 'postcss-loader', // Process Tailwind CSS
options: {
sourceMap: 'inline',
}
},
{
loader: 'sass-loader', // Compiles Sass to CSS
},
]
},
{
// Process the global tailwind styles
include: path.resolve(__dirname, 'src/assets/styles/styles'),
test: /\.(scss)$/,
use: [
{
loader: 'style-loader', // Allow for HMR
},
{
loader: 'postcss-loader', // Process Tailwind CSS
options: {
sourceMap: 'inline',
}
},
{
loader: 'sass-loader', // Compiles Sass to CSS
},
]
},
]
},
The style-loader will extract the styles into the head at runtime, and allow for HMR. In your prod config, you can use css-loader alongside MiniCssExtractPlugin to extract and inject the global styles as a .css file into the head:
{
// Process the global tailwind styles
include: path.resolve(__dirname, 'src/assets/styles/styles'),
test: /\.(scss)$/,
use: [
{ loader: MiniCssExtractPlugin.loader },
{ loader: 'css-loader' },
{
loader: 'postcss-loader', // Process Tailwind CSS
options: {
sourceMap: false,
}
},
{
loader: 'sass-loader', // Compiles Sass to CSS
},
]
},

Add Sass (.scss) to ejected create-react-app config

I want to add .scss support in my app, which was created using create-react-app.
I did eject npm run eject and installed necessary dependencies: npm install sass-loader node-sass --save-dev
Inside config/webpack.config.dev.js I added to the loaders this snippet:
{
test: /\.scss$/,
include: paths.appSrc,
loaders: ["style", "css", "scss"]
},
So the beginning of the loaders array now look like so:
loaders: [
// Process JS with Babel.
{
test: /\.(js|jsx)$/,
include: paths.appSrc,
loader: 'babel',
query: require('./babel.dev')
},
// "postcss" loader applies autoprefixer to our CSS.
// "css" loader resolves paths in CSS and adds assets as dependencies.
// "style" loader turns CSS into JS modules that inject <style> tags.
// In production, we use a plugin to extract that CSS to a file, but
// in development "style" loader enables hot editing of CSS.
{
test: /\.css$/,
loader: 'style!css!postcss'
},
// LOAD & COMPILE SCSS
{
test: /\.scss$/,
include: paths.appSrc,
loaders: ["style", "css", "scss"]
},
Now in my jsx when I try to import scss file:
import './assets/app.scss';
I get an error:
Uncaught Error: Cannot find module "./assets/app.scss"
So my config must be wrong as I'm not able to load .scss files. How to adjust config to load .scss files in ejected create-react-app?
Check the first loader, first it get all the files and it excludes the other loaders files
loaders: [
{
exclude: [
/\.html$/,
/\.(js|jsx)$/,
/\.css$/,
/\.json$/,
/\.svg$/
],
loader: 'url',
query: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]'
}
},
so adding
/\.sass$/,
/\.scss$/,
to exclude, seems that fixed the same problem I had :D
When trying to integrate sass into empty react project I used this article. The solution presented there did not work and received the similar error as in the subject.
In my case replacing style-loader with require.resolve('style-loader') helped:
{
test: /\.scss$/,
include: paths.appSrc,
loaders: [require.resolve('style-loader'), require.resolve('css-loader'), require.resolve('sass-loader')]
},
OK, I found the solution - changed from this:
{
test: /\.scss$/,
include: paths.appSrc,
loaders: ["style", "css", "scss"]
},
to this:
{
test: /\.scss$/,
loaders: ['style', 'css', 'sass']
},
And now my .scss files are loading!!
You probably have to use
include: paths.appSrc,
option to enable webpack hot-reload. So you config snippet could looks like
{
test: /\.scss$/,
include: paths.appSrc,
loaders: ['style', 'css', 'sass']
},
as per Latest Configuration [CRA]
::webpack.config.dev.js::
{
test: /\.css$/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
},
},
{
loader: require.resolve('postcss-loader'),
options: {
// Necessary for external CSS imports to work
// https://github.com/facebookincubator/create-react-app/issues/2677
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
flexbox: 'no-2009',
}),
],
},
},
],
},
{
test: /\.scss$/,
loaders: [
require.resolve("style-loader"), // creates style nodes from JS strings
require.resolve("css-loader"), // transl ates CSS into CommonJS
require.resolve("sass-loader") // compiles Sass to CSS
]
},
Check this loader settings for the latest versions.
{
test: /\.scss$/,
use: [
"style-loader", // creates style nodes from JS strings
"css-loader", // translates CSS into CommonJS
"sass-loader" // compiles Sass to CSS
]
}

Resources