SCSS file cannot import node_module - reactjs

Tried #import "~react-icons" in an SCSS file.
I get an error: Module build failed:
#import "~react-icons";
^
File to import not found or unreadable: ~react-icons.
This was an npm module that I installed and is on package-json.
My scss code looks like this, the error is at the first line:
#import "~react-icons";
input {
width: 100%;
box-sizing: border-box;
border: 2px solid #ccc;
border-radius: 4px;
font-size: 16px;
background-color: white;
padding: 12px 20px 12px 20px;
margin-bottom: 20px;
}
My webpack configuration looks like this:
const webpack = require('webpack');
const path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
let BUILD_DIR = path.resolve(__dirname, 'dist');
let APP_DIR = path.resolve(__dirname, 'src');
let config = {
entry: path.join(APP_DIR, '/index.js'),
output: {
path: BUILD_DIR,
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.jsx?/,
include: APP_DIR,
loaders: ['babel-loader']
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: ['css-loader', 'sass-loader'],
publicPath: "/dist"
})
},
{
test: /\.(ttf|eot|svg|gif|woff(2)?)(\?[a-z0-9]+)?(\?v=
[0-9]\.[0-9]\.[0-9])?$/,
loader: 'file-loader',
}
]
},
resolve: {
extensions: ['.js', '.jsx']
},
devServer: {
contentBase: path.join(__dirname),
// serve index.html in place of 404 responses to allow HTML5
// history
historyApiFallback: true
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
title: 'Project',
minify: {
collapseWhitespace: true
},
hash: true,
template: './index.html'
}),
new ExtractTextPlugin({
filename: 'style.css',
disable: false,
allChunks: true
})
]
};
module.exports = config;

There is not an scss file to import for react-icons. You have to import the icons in the file you want to use:
import FaSearch from 'react-icons/lib/fa/search';
class Search extends React.Component {
render() {
return <FaSearch />
}
}

Related

LESS style not applied to react component in react+webpack application

In a react + web pack application, I'm trying to style my react component using LESS, but the style does not get applied, although I get no errors, so I wouldn't know where to look. Of course, my devDependencies includes less, less-loader, CSS-loader and style-loader.
webpack.config.js
const path = require("path");
const webpack = require("webpack");
module.exports = {
entry: './src/index.js',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
"babel-loader",
"eslint-loader"
]
},
{
test: /\.(c|le)ss$/,
use: [
"style-loader",
"css-loader",
"less-loader",
]
}
]
},
resolve: {
extensions: [".js", ".jsx"],
alias: {
"#components": path.resolve(__dirname, "src/components"),
"#containers": path.resolve(__dirname, "src/containers")
}
},
output: {
path: __dirname + '/dist',
filename: 'bundle.js'
},
plugins: [
new webpack.HotModuleReplacementPlugin()
],
devServer: {
contentBase: './dist',
hot: true
}
};
components/App/App.jsx
import React from "react";
import Body from "#components/Body/Body.jsx";
import Footer from "#components/Footer/Footer.jsx";
import styles from "./App.less";
class App extends React.Component {
render() {
return <div className={styles.root}>
<h1> test </h1>
<Body />
<Footer />
</div>;
}
}
export default App;
components/App/App.less
.root {
width: 100%;
height: 100%;
background-color: coral;
h1 {
margin-top: 200px;
color: red;
}
}
I expected to see the style applied, but it's not.
Try setting "root" as string-value to className.
The way your webpack has been configured, the content of the LESS-files will not be exported as css-rules but only collected to be rendered into a style-tag.
You need to import the less-file, so webpack knows which files to consider, but you neither can access its rules, or its styles. So to make it work, you simply set the CSS-class names so that the compiled CSS-rules match.
I had to enable CSS Modules in the Webpack config:
{
test: /\.(c|le)ss$/,
use: [
"style-loader",
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: "[path][name]__[local]--[hash:base64:5]",
},
},
"less-loader"
]
},

How do you remove unused classes with Webpack 4 tree shaking with CSS modules?

Someone made a great example to remove unused CSS based on whether or not the JS Module is used, but I am trying to figure out how to remove the unused CSS classes from the bundle that are not actually used by components.
Example
// Sub.scss
.sub-container {
background-color: green;
}
.unused-junk {
color: blue;
}
// Sub.js
import React from "react";
import styles from "./Sub.scss";
export default function Sub() {
return <div className={styles.subContainer}>Hi from sub.</div>;
}
// App.scss
.app-container {
background-color: red;
}
// App.js
import React from "react";
import ReactDOM from "react-dom";
import Sub from "./Sub";
import styles from "./App.scss";
function App() {
return (
<div className={styles.appContainer}>
Hi from app.
<Sub />
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
// webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
module.exports = {
entry: "./src/App.js",
output: {
path: __dirname + "/build",
filename: "bundle.js"
},
module: {
rules: [
{
test: /\.js/,
loader: "babel-loader",
include: __dirname + "/src",
query: {
presets: ["react"]
}
},
{
test: /\.scss/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
modules: true,
camelCase: true,
importLoaders: 1,
localIdentName: "[name]--[local]--[hash:base64:5]"
}
},
"sass-loader"
],
include: __dirname + "/src"
}
]
},
plugins: [
new CopyWebpackPlugin([{ from: `src/index.html`, to: "index.html" }]),
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
]
};
// CSS bundle
.App--app-container--3wd6W {
background-color: red; }
.Sub--sub-container--38uqh {
background-color: green; }
.Sub--unused-junk--2-h5r {
color: blue; }
Is there a way to tree shake the .unused-junk class from the bundle?

unable to load background image on body using webpack 4 in reactjs

in my react js app I want to add the background image on the body.it is working fine when I'm doing in development mode but when comes to production it is not working.
for production, I'm using dist separate folder may it is creating some path issue.
here my scss
body {
font-family: Helvetica,Arial,sans-serif;
font-size: $m-size;
height: 100%;
width: 100%;
margin: 0px;
padding: 0px;
background-image: url(/images/bg4.png);
background-attachment: fixed;
background-repeat: no-repeat;
background-position: top;
background-size:cover;
}
my webpack.config
module.exports = {
entry:{
vendor: VENDOR_LIBS,
main: './src/app.js',
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].bundle.js',
chunkFilename: '[name].bundle.js',
publicPath: '/',
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{ test: /\.bundle\.js$/, use: { loader: 'bundle-loader', options: {lazy: true} } },
{
test: /\.s?css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader?url=false',
options: {
sourceMap: true,
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
},{
test: /\.(gif|svg|jpg|png|ttf|eot|woff(2)?)(\?[a-z0-9=&.]+)?$/,
loader: "file-loader?name=[name].[ext]",
}
]
},
plugins: [
new CleanWebpackPlugin('dist', {} ),
new MiniCssExtractPlugin({
filename: 'style.[contenthash].css',
}),
new HtmlWebpackPlugin({
inject: true,
hash: true,
template: './src/index.html',
filename: 'index.html',
favicon: './public/images/fav.ico'
}),
new WebpackMd5Hash(),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
}),
],
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor',
chunks: 'all',
minChunks: 2
},
}
},
runtimeChunk: true,
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true,
uglifyOptions: {
compress: {
inline: false
}
}
}),
new OptimizeCSSAssetsPlugin({})
],
},
};
webpack generating other images into base64 but not for this image.and it is not available in dist folder.
can any one help me out, i searched lot of questions but couldn't solve.
i don't want any external link to load image.
In production your current directory will change to /dist/index.html so thats why the path you used for development /images/bg4.png can't find the file.
The solution is to copy your static image files, like your background, into the /dist folder in the build process.
Assuming your project directory is similar to the following:
...
/images/bg4.png
package.json
Then add these commands to your webpack build script to copy the images into your production directory /dist.
// in package.json
"scripts": {
...
"build": "...your webpack build commands... && cp -a images\\. dist\\images",
...
},
Your new file directories will look like
/dist/...your index.html, bundles, etc...
/images/bg4.png
/images/bg4.png
package.json
and your image path should find the image file now.

Webpack not picking up changess to scss

Here are my files... webpack compiles fine but not picking up style changes. I have followed 2 tutorials and just want to get styling working with webpack under a basic development built process.
webpack.config.js:
var webpack = require('webpack')
var path = require('path')
var BUILD_DIR = path.resolve(__dirname + '/build')
var APP_DIR = path.resolve(__dirname + '/app')
var config = {
entry: APP_DIR + '/index.jsx'
, output: {
path: BUILD_DIR
, filename: 'bundle.js'
, publicPath: '/'
}
, resolve: {
extensions: ['.js', '.jsx']
}
, devtool: 'source-map'
, devServer: {
inline: true
, contentBase: BUILD_DIR
, port: 3333
}
, module: {
rules: [
{
test: /\.jsx?/
, include: APP_DIR
, loader: 'babel-loader'
, query: {
presets: ['es2015', 'stage-0', 'react']
}
},
{
test: /\.scss$/,
use: [//{
// loader: "style-loader" // creates style nodes from JS strings
//}, {
{ loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "sass-loader" // compiles Sass to CSS
}]
}
]
}
}
module.exports = config
index.jsx
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import reducer from './reducers/index.js'
require('./stylesheets/main.scss');
// Create a store
let store = createStore(reducer);
import App from './components/App.jsx'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider> , document.getElementById('app'));
main.scss:
.app {
#import 'components/all';
}
components/all:
#import 'product';
_product.scss
.pr-product {
width: percentage(1/7);
float: left;
text-align: center;
padding: 0.5rem;
font-size:2rem;
font-weight: 400;
border-radius: 0.25rem;
transition: background-color 0.25s ease-in-out;
color: pink;
background-color: orange;
// Variants
&.past, &.future {
opacity: 0.5;
}
// States
&:hover {
cursor: pointer;
background-color: rgba(orange, 0.3);
}
}
product.jsx:
import React from 'react'
let Product = ({id, name, cost, handleClick}) => (
<div className='pr-product'>
{name} ${cost} <button onClick={() => handleClick(id)}>Add to cart</button>
</div>
)
export default Product
index.html:
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<!-- Made no difference: <link rel="stylesheet" href='../app/stylesheets/main.scss'> -->
</head>
<body>
<div id='app' class='app'></div>
<script src='bundle.js'></script>
</body>
</html>
Thank you if you can help. . .
EDIT:
I've incorporated all of the below recommendations and still no luck getting webpack to pick up css. Here is my modified webpack config:
var webpack = require('webpack')
var path = require('path')
var BUILD_DIR = path.resolve(__dirname + '/build')
var APP_DIR = path.resolve(__dirname + '/app')
var CSS_DIR = path.resolve(__dirname + '/app/stylesheets')
var config = {
entry: APP_DIR + '/index.jsx'
, output: {
path: BUILD_DIR
, filename: 'bundle.js'
, publicPath: '/'
}
, resolve: {
extensions: ['.js', '.jsx', '.scss']
}
, devtool: 'source-map'
, devServer: {
inline: true
, contentBase: BUILD_DIR
, port: 3333
}
, module: {
rules: [
{
test: /\.jsx?/
, include: APP_DIR
, loader: 'babel-loader'
, query: {
presets: ['es2015', 'stage-0', 'react']
}
},
{
test: /(\.scss)$/,
include: CSS_DIR,
use: [{loader: 'css-hot-loader'},
{loader: "style-loader" }, // creates style nodes from JS strings
{loader: "css-loader"}, // translates CSS into CommonJS
{loader: "sass-loader?" + JSON.stringify({ includePaths: [ CSS_DIR ], sourceMap : true })} // compiles Sass to CSS
]
}
]
}
}
module.exports = config
Try to make use of css-hot-loader
{
test: /(\.scss)$/,
use: [{loader: 'css-hot-loader'},
{loader: "style-loader"}, // creates style nodes from JS strings
{loader: "css-loader"}, // translates CSS into CommonJS
{loader: "sass-loader"} // compiles Sass to CSS
]
},

fixing relative paths with css-loader and react-router

I can't figure out how to configure webpack to produce css with valid urls no matter the current application url. Here's my project structure:
/theme
/assets
/css
/fonts
/images
/js
/dist
bundle.js
index.html
/node_modules
/src
/test
package.json
webpack.config.js
The /theme directory is a bootstrap theme. The urls in the css are relative. For example:
/* /theme/assets/css/ace-fonts.css */
#font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 300;
src: local('Open Sans Light'), local('OpenSans-Light'), url(../fonts/OpenSans-300.woff) format('woff');
}
#font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: local('Open Sans'), local('OpenSans'), url(../fonts/OpenSans-400.woff) format('woff');
}
When I visit my application at it's root url(http://localhost:8080/) or a url with a single segment(http://localhost:8080/about) everything works. Those relative urls get resolved to the base url. However, if i refresh the browser while on a 2+ segment url(http://localhost:8080/some/thing) the browser ends up requesting the following url:
http://localhost:8080/some/db812d8a70a4e88e888744c1c9a27e89.woff
React router ends up architecting the right markup for the url, yet the urls in the stylesheets are relative, thus breaking. I'm new to webpack and have no idea how to go about fixing this.
Here's my webpack config:
var path = require('path');
var webpack = require('webpack');
var prodPlugins = [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin()
];
var defaultPlugins = [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.$": "jquery",
"window.jQuery": "jquery"
}),
new webpack.HotModuleReplacementPlugin()
];
module.exports = {
  entry: [
'webpack-dev-server/client?http://localhost:8080',
'webpack/hot/only-dev-server',
'./src/index.js'
],
  output: {
path: 'dist',
filename: 'bundle.js'
},
devServer: {
contentBase: './dist',
hot: true
},
resolve: {
root: path.resolve('./')
},
  module: {
    loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'react-hot!babel'
},
{
test: /\.css$/,
loader: 'style!css!resolve-url'
},
{ test: /\.less$/, loader: "style!css!less"},
{ test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file" },
{ test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "url-loader?limit=10000&mimetype=application/font-woff" },
{ test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/octet-stream" },
{ test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=image/svg+xml" },
{ test: /\.(png|jpg)$/, loader: 'url?limit=8192' }
]
  },
resolveUrlLoader: {
absolute: true
},
plugins: process.env.NODE_ENV === 'production' ? prodPlugins.concat(defaultPlugins) : defaultPlugins,
};
Any help would be much appreciated.
I ended up using the extract-text-webpack-plugin to put my css file at the root path. That fixed my relative paths in my css files problem but then I noticed the paths of images referenced in my components weren't correct so per #lux's suggestion i set my publicPath to /. Here is my updated webpack.config.js
var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var prodPlugins = [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin()
];
var defaultPlugins = [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.$": "jquery",
"window.jQuery": "jquery"
}),
new webpack.HotModuleReplacementPlugin(),
new ExtractTextPlugin('styles.css')
];
module.exports = {
  entry: [
'webpack-dev-server/client?http://localhost:8080',
'webpack/hot/only-dev-server',
'./src/index.js'
],
  output: {
path: 'dist',
publicPath: '/',
filename: 'bundle.js'
},
devServer: {
contentBase: './dist',
hot: true
},
resolve: {
root: path.resolve('./')
},
  module: {
    loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'react-hot!babel'
},
{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
},
{ test: /\.less$/, loader: "style!css!less"},
{ test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file" },
{ test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "url?limit=10000&mimetype=application/font-woff" },
{ test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/octet-stream" },
{ test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=image/svg+xml" },
{ test: /\.(png|jpg)$/, loader: 'url?limit=8192' }
]
  },
resolveUrlLoader: {
absolute: true
},
plugins: process.env.NODE_ENV === 'production' ? prodPlugins.concat(defaultPlugins) : defaultPlugins,
};
Because i'm extracting the css to a styles.css file, I had to update my dist/index.html file.
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>My App</title>
<link rel="stylesheet" type="text/css" href="/styles.css">
</head>
<body class="no-skin">
<div id="app"></div>
<script src="/bundle.js"></script>
</body>
</html>

Resources