Using webpack to prepend variables for SCSS - reactjs

Webpack amateur here... I'm trying to incorporate a theme.scss file to customize the theme used by React Toolbox by following the directions specified here, namely:
If you are using Webpack as module bundler, you are probably using sass-loader as well. What we want to do is to prepend to each SASS file compilation a bunch of variables to override and this can be done with the data option. For example:
sassLoader: { data: '#import "' + path.resolve(__dirname, 'theme/_theme.scss') + '";' }
In this case we have are prepending the theme import to each SASS compilation so the primary color will be changed in every single stylesheet.
I'm having trouble implementing this instruction with my current webpack configuration, which looks like this:
const webpack = require('webpack');
const path = require('path');
let ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
context: path.join(__dirname, 'client'),
entry: [
'./main.js',
],
output: {
path: path.join(__dirname, 'www'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
'babel-loader',
],
},
{
test: /\.css$/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
modules: true,
sourceMap: true,
importLoaders: 1,
localIdentName: "[name]--[local]--[hash:base64:8]"
}
},
"postcss-loader" // has separate config, see postcss.config.js nearby
]
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader', options: {
sourceMap: true,
data: '#import "' + path.resolve(__dirname, 'theme.scss') + '";'
}
},
'postcss-loader',
{
loader: 'sass-loader', options: {
sourceMap: true,
data: '#import "' + path.resolve(__dirname, 'theme.scss') + '";'
}
},
],
})
}
]
},
plugins: [
new ExtractTextPlugin({
filename: 'style.css',
allChunks: true
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
}),
],
resolve: {
modules: [
path.join(__dirname, 'node_modules'),
],
},
};
I don't get an error, but it seems like the data option is being entirely ignored because my file does not get imported.
Here is my theme.scss file (located in client/theme.scss):
#import "~react-toolbox/lib/colors";
$color-primary: $palette-red-500;
$color-primary-dark: $palette-red-700;
body {
background-color: black; //testing
}
I feel like I must be doing something stupid here, but I'm driving myself crazy. I have tried messing with the path of the theme.scss file (changing the data attribute to data: '#import "' + path.resolve(__dirname, 'client/theme.scss') + '";') but that doesn't make a difference. I'm surprised I'm not getting an error of some kind.
Any suggestions?

The below configuration worked for me
{
test: /\.scss$/,
include: /client/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
loader: [
{
loader: 'css-loader',
query: {
modules: true,
sourceMap: false,
localIdentName: '[name]_[local]_[hash:base64:5]',
},
},
'postcss-loader',
{
loader: 'sass-loader',
query: {
sourceMap: false,
data: `#import "${path.resolve(__dirname, 'client/_theme.scss')}";`
}
}
],
}),
},
and client/_theme.scss file
#import "react-toolbox/lib/colors.css";
$color-primary: var(--palette-blue-500);
$color-primary-dark: var(--palette-blue-700);
I checked the colors.css file in the react-toolbox library and used the same variable names. i.e --palette-blue-500, not $palette-blue-500.

Related

webpack Can't resolve '../../assets/icon-font/icomoon.eot?e3uwku' in 'D:\sudi\aa-Server-side-render\MAPS101_Fresh_ssr\src\scss'

I want to implement SSR in an already build react application.
I am trying to include icon-fonts and ignore CSS files from node_modules of a particular library
Please help me, I am stuck here!!
I'm trying to load a font in my SCSS file but giving the below error.
my folder structure is :
my webpack.config.js is:
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
// webpack optimization mode
mode: ('development' === process.env.NODE_ENV ? 'development' : 'production'),
// entry files
entry: 'development' === process.env.NODE_ENV ? [
'./src/index.js', // in development
] : [
'./src/index.js', // in production
],
// output files and chunks
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'build/[name].js',
},
// module/loaders configuration
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env', '#babel/preset-react']
}
},
exclude: [/node_modules/, /static/]
},
{
test: /\.(sa|sc|c)ss$/,
use: [
true ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader',
],
exclude: [/node_modules/, /static/]
},
{
test: /\.(css)$/,
use: [{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '/public/css'
}
}, 'css-loader'],
exclude: [/node_modules/, /static/]
},
{
test: /\.(jpg|jpeg|png|svg|gif)$/,
use: [{
loader: 'file-loader',
options: {
name: '[md5:hash:hex].[ext]',
publicPath: '/public/img',
outputPath: 'img'
}
}]
},
{
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=10000&mimetype=application/font-woff',
},
{
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=10000&mimetype=application/font-woff',
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=10000&mimetype=application/octet-stream',
},
{
test: /\.otf(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=10000&mimetype=application/octet-stream',
},
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=10000&mimetype=application/vnd.ms-fontobject',
},
]
},
// webpack plugins
plugins: [
// extract css to external stylesheet file
new MiniCssExtractPlugin({
filename: 'build/styles.css'
}),
// prepare HTML file with assets
new HTMLWebpackPlugin({
filename: 'index.html',
template: path.resolve(__dirname, 'src/index.html'),
minify: false,
}),
// copy static files from `src` to `dist`
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(__dirname, 'src/assets'),
to: path.resolve(__dirname, 'dist/assets')
}
]
}),
],
// resolve files configuration
resolve: {
// file extensions
extensions: ['.js', '.jsx', '.css', '.scss'],
},
// webpack optimizations
optimization: {
splitChunks: {
cacheGroups: {
default: false,
vendors: false,
vendor: {
chunks: 'all', // both : consider sync + async chunks for evaluation
name: 'vendor', // name of chunk file
test: /node_modules/, // test regular expression
}
}
}
},
// development server configuration
devServer: {
port: 8088,
historyApiFallback: true,
}, // generate source map
devtool: 'source-map' };
For me, I had the icomoon font in fonts directory. Did some investigation and found that the .scss file was trying to link it like this
url("./assets/styles/fonts/icomoon.svg?y2smka#icomoon"). The problem with that is icomoon.svg?y2smka#icomoon does not exist. So I looked in the fonts directory and found that it's called icomoon.eot
Solution:
In your _fonts.scss file, change all url("./assets/styles/fonts/icomoon.svg?y2smka#icomoon"). to url("./icomoon.eot")

CSS Loader in Webpack config is not working

I am trying to integrate https://www.npmjs.com/package/react-date-range
When I import css files, it gives loader issue.
My webpack file and error message is shown below. Any help regarding this problem is appreciated
Webpack config File
var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var CircularDependencyPlugin = require('circular-dependency-plugin');
var ExtractCssChunks = require("extract-css-chunks-webpack-plugin");
var config = require('./../config');
var BASE_PATH = process.env.BASE_PATH || '/';
module.exports = {
name: 'client',
devtool: 'cheap-eval-source-map',
target: 'web',
mode: 'development',
node: { fs: 'empty' },
externals: [
{ './cptable': 'var cptable' },
{ './jszip': 'jszip' }
],
entry: {
app: [path.join(config.srcDir, 'index.js')]
},
output: {
filename: '[name].bundle.js',
chunkFilename: '[name].chunk.js',
path: config.distDir,
publicPath: BASE_PATH
},
resolve: {
modules: [
'node_modules',
config.srcDir
]
},
plugins: [
new CircularDependencyPlugin({
exclude: /a\.js|node_modules/,
failOnError: true,
allowAsyncCycles: false,
cwd: process.cwd(),
}),
new HtmlWebpackPlugin({
template: config.srcHtmlLayout,
inject: false,
chunksSortMode: 'none'
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development'),
'process.env.BASE_PATH': JSON.stringify(BASE_PATH),
}),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
new ExtractCssChunks(),
],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader'
},
// Modular Styles
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true,
importLoaders: 1,
}
},
{ loader: 'postcss-loader' }
],
exclude: [path.resolve(config.srcDir, 'styles')],
include: [config.srcDir]
},
{
test: /\.scss$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true,
importLoaders: 1,
}
},
{ loader: 'postcss-loader' },
{
loader: 'sass-loader',
options: {
includePaths: config.scssIncludes
}
}
],
exclude: [path.resolve(config.srcDir, 'styles')],
include: [config.srcDir]
},
// Global Styles
{
test: /\.css$/,
use: [
ExtractCssChunks.loader,
'css-loader',
'postcss-loader'
],
include: [path.resolve(config.srcDir, 'styles')]
},
{
test: /\.scss$/,
use: [
ExtractCssChunks.loader,
'css-loader',
'postcss-loader',
{
loader: 'sass-loader',
options: {
includePaths: config.scssIncludes
}
}
],
include: [path.resolve(config.srcDir, 'styles')]
},
// Fonts
{
test: /\.(ttf|eot|woff|woff2)$/,
loader: "file-loader",
options: {
name: "fonts/[name].[ext]",
}
},
// Files
{
test: /\.(jpg|jpeg|png|gif|svg|ico)$/,
loader: "file-loader",
options: {
name: "static/[name].[ext]",
}
}
]
},
devServer: {
hot: true,
contentBase: config.serveDir,
compress: true,
historyApiFallback: {
index: BASE_PATH
},
host: '0.0.0.0',
port: 3000
}
}
Following are the error messages, Seems like it can find the css files but cannot parse it, Let me know if anybody can help.
Error Message :
ERROR in ./node_modules/react-date-range/dist/styles.css 1:0
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> .rdrCalendarWrapper {
| box-sizing: border-box;
| background: #ffffff;
# ./app/index.js 8:0-42
# multi ./app/index.js
ERROR in ./node_modules/react-date-range/dist/theme/default.css 1:0
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> .rdrCalendarWrapper{
| color: #000000;
| font-size: 12px;
# ./app/index.js 10:0-49
# multi ./app/index.js
Since you are loading the css file from node_modules package but you set css loader with include only your source path. I suggest to either remove that:
{
test: /\.css$/,
use: [
ExtractCssChunks.loader,
'css-loader',
'postcss-loader'
],
},
Or put more package into your list, it's up to you:
{
test: /\.css$/,
use: [
ExtractCssChunks.loader,
'css-loader',
'postcss-loader'
],
include: [path.resolve(config.srcDir, 'styles'), /node_modules/\react-date-range /]
},

Resolve Relative Path from node_modules to Dist folder with Webpack

I'm using React component as an NPM Package. in the component, I have SCSS file
with url(../iamges/img..) path, but actually, the images folder located in the Dist folder, how can I point Webpack to take the relative path from node_modules and serve it from images folder located in the Dist?
located in node_modules =>
background: url('../images/some-icon.svg') no-repeat center center;
Webpack config:
const webpack = require('webpack');
const path = require('path');
module.exports = {
entry: './src/index.js',
devtool: 'inline-module-source-map',
output: {
path: path.resolve(__dirname, '/dist'),
filename: 'bundle.js',
publicPath: '/',
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.scss$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
{
loader: 'resolve-url-loader',
// options: {
// debug: true,
// root: path.join(__dirname, './dist/images'),
// includeRoot: true,
// absolute: true,
// },
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
sourceMapContents: false,
},
},
],
},
{
test: /\.css$/,
loaders: ['style-loader', 'css-loader'],
},
{
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
use: {
loader: 'url-loader?name=/images/[name].[ext]',
options: {
limit: 10000,
},
},
},
],
},
resolve: {
extensions: ['.js', '.jsx'],
// modules: [path.resolve(__dirname, '/images'), 'node_modules'],
alias: {
'react-redux': path.resolve('./node_modules/react-redux'),
},
},
plugins: [new webpack.HotModuleReplacementPlugin()],
devServer: {
hot: true,
publicPath: '/dist/',
},
};
babel.config.js
module.exports = {
// presets: ['#babel/preset-env', '#babel/preset-react'],
plugins: [
'#babel/plugin-proposal-class-properties',
'#babel/plugin-proposal-export-default-from',
'#babel/transform-runtime',
],
sourceType: 'unambiguous',
presets: [
[
'#babel/preset-env',
{
targets: {
node: 'current',
},
},
],
'#babel/preset-react',
],
};
dist
-- images
-- index.html
ERROR:
ERROR in ./node_modules/comp/src/styles/details.scss (./node_modules/css-loader!./node_modules/resolve-url-loader!./node_modules/sass-loader/lib/loader.js??ref--5-3!./node_modules/compdetails/src/styles/details.scss)
Module not found: Error: Can't resolve '../images/icon.svg'
Anything referred through url('...') in css will be computed with reference to the path of deployed application (scss will not compute the path unless variable or function is not being used):
For example:
If your referred component SCSS module is having background: url('../images/some-icon.svg') no-repeat center center;
The final CSS compilation will be same (it is also because the component is not using any SCSS variables or functions to compute the final path).
So your application will always try to find that image as:
Example: http://localhost:3000/../images/some-icon.svg which is a problem.
(.. is referred as parent directory)
If you try to run your app with some sub-url (also known as sub context) as http://localhost:3000/sub-url/ and you keep your images parallel to sub-url folder it will automatically work.
-- /
|
|-- sub-url
|
|-- index.html
|-- images
|
|-- some-icon.svg
Another option can be override the component SCSS with yours.
You already found the solution to use resolve-url-loader, but in this case you need to import the component's scss file into you scss.
so your webpack config should look like:
const webpack = require('webpack');
const path = require('path');
module.exports = {
entry: './src/index.js',
devtool: 'inline-module-source-map',
output: {
path: path.resolve(__dirname, '/dist'),
filename: 'bundle.js',
publicPath: '/',
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.scss$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
// CHANGE HERE
{
loader: 'resolve-url-loader',
options: {
root: '/images', // considering all your images are placed in specified folder. Note: this is just a string that will get as prefix to image path
includeRoot: true,
absolute: true,
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
sourceMapContents: false,
},
},
],
},
{
test: /\.css$/,
loaders: ['style-loader', 'css-loader'],
},
{
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
use: {
loader: 'url-loader?name=/images/[name].[ext]',
options: {
limit: 10000,
},
},
},
],
},
resolve: {
extensions: ['.js', '.jsx'],
// modules: [path.resolve(__dirname, '/images'), 'node_modules'],
alias: {
'react-redux': path.resolve('./node_modules/react-redux'),
},
},
plugins: [new webpack.HotModuleReplacementPlugin()],
devServer: {
hot: true,
publicPath: '/dist/',
},
};
I hope it helps.

Webpack return ValidationError: CSS Loader Invalid Options

I'm getting an error for css loader invalid option and my webpack.conifg.js code is as follows :
const path = require('path');
const HtmlWebPackPlugin = require("html-webpack-plugin");
const htmlWebpackPlugin = new HtmlWebPackPlugin({
template: "./public/index.html"
});
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve('dist'),
filename: 'bundled.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.css$/,
use: [
{
loader: "style-loader"
},
{
loader: "css-loader",
options: {
modules: true,
importLoaders: 1,
localIdentName:"[name]_[local]_[hash:base64]",
sourceMap: true,
minimize: true
}
}
]
},
{
test: /\.(png|jpg|woff|woff2|eot|ttf|svg)$/,
loader: 'url-loader?limit=100000'
}
]
},
plugins: [htmlWebpackPlugin]
};
I don't know where I'm doing wrong.Please help me to solve this issue. I'm using webpack for reactjs 4 and webpack version is 4. Thanks
This is what resolved my case:
css-loader 2.1.1
{ loader: 'style-loader'},
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[local]',
import: true,
importLoaders: true,
}
},
{ loader: 'sass-loader'}
css-loader 3.0.0
{ loader: 'style-loader'},
{
loader: 'css-loader',
options: {
modules: {
mode: 'local',
localIdentName: '[local]',
},
import: true,
importLoaders: true,
}
},
{ loader: 'sass-loader'}
Try commenting out:
// minimize: true
Commenting out minimize worked previously, though I began a new project with a fresh install of css-loader, and the culprit this time around is importLoader: 1. Just remove importLoader and it should work.
I'm using css modules with React, and everything is running properly.
This worked for my VUE Js project:
Browse to the /build/utils.js file and in the object of thecss-loader comment on the option that is marking you in the error. In my case I had to comment:
minimize: process.env.NODE_ENV === 'production',

Webpack 4 configuration for react-toolbox

I try to upgrade my app from webpack 2 to webpack 4.16.5.
Because I want not again end up in a hard to understand some hundreds line config, I start with a minimal config. This is my current:
const path = require("path");
const HtmlWebPackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const context = path.resolve(__dirname, "app");
module.exports = {
entry: {
home: "./index.js"
},
context,
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: { minimize: true }
}
]
},
{
test: /\.(css|sass|scss)$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader"
},
{
loader: "postcss-loader"
},
{
loader: "sass-loader"
}
]
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: "./index.html",
filename: "./index.html"
}),
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
],
resolve: {
extensions: [".js", ".jsx", ".css", "json"],
modules: [path.resolve(__dirname, "node_modules"), context]
}
};
But I run in problems importing the CSS files from react-toolbox i.e.:
import Dialog from 'react-toolbox/lib/dialog';
in a js file and also
#import "react-toolbox/lib/button/theme.css";
causes errors like this:
ERROR in ../node_modules/react-toolbox/lib/switch/theme.css (../node_modules/css-loader!../node_modules/postcss-loader/src!../node_modules/sass-loader/lib/loader.js!../node_modules/react-toolbox/lib/switch/theme.css)
Module build failed (from ../node_modules/css-loader/index.js):
Error: composition is only allowed when the selector is single: local class name not in ".disabled", ".disabled" is weird
Does anyone have a working application with wbpack4 and react-toolbox? Also, any hints on what may cause these errors are welcome!
I'm learning react.js with the js stack from scratch tutorial and try to using react-toolbox components.
Finnaly, i have a working demo with webpack 4 and the react-toolbox, it's based on the react-toolbox-example.
This is my settings:
add css-modules related packages
$ npm install postcss postcss-cssnext postcss-import postcss-loader css-loader style-loader
add a postcss.config.js
module.exports = {
plugins: {
'postcss-import': {
root: __dirname,
},
'postcss-cssnext': {}
},
};
add a webpack rule
...
{ test: /\.css$/, use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
sourceMap: true,
importLoaders: 1,
localIdentName: '[name]--[local]--[hash:base64:8]'
}
},
'postcss-loader'
]},
...
add cmrh.conf.js - Using the css-modules-require-hook for SSR(Optional)
module.exports = {
generateScopedName: '[name]--[local]--[hash:base64:8]'
}
You can see all the settings in here, hope it will work for you.

Resources