GitHub: https://github.com/Chirag161198/react-boilerplate 1
Here is the react boilerplate I’m trying to make from scratch.
I have bundled html with the react code but I’m not able to add styles (CSS).
I have heard about ExtractTextPlugin but not able to configure it.
Please suggest some way to add styles to it.
Thank you in advance.
You need to use style-loader and css-loader in your webpack.config.js
First, install these two packages via npm:
npm install style-loader, css-loader --dev
Then, create a styles.css in your src folder and append the following styles into the file (just for demo purpose, so you know it's working correctly):
body {
background-color: #ff4444;
}
Don't forget to import the css file in your src/index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App.js';
import './styles.css'; // <- import the css file here, so webpack will handle it when bundling
ReactDOM.render(<App />, document.getElementById('app'));
And use style-loader and css-loader in your webpack.config.js:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: { loader: 'babel-loader' },
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
}),
],
};
If you don't see the correct output, you might need to restart the webpack dev server again. I have cloned your repo and made the changes like I mentioned above, it works.
As for ExtractTextPlugin, you will need this when bundling for a production build, you can learn more from their Repo
Hope it helps!
Hi Chirag ExtractTextPlugin works great but when it comes to caching and bundle hashing. Css bundle becomes 0 bytes. So they introduced MiniCssExtractPlugin which has tackled this issue. It is really important to cache static files as your app size increase by time.
import plugin first:
var MiniCssExtractPlugin = require("mini-css-extract-plugin");
add these in your webpack config:
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.scss$/,
use: [ 'style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
}
]
}
plugins: [
new MiniCssExtractPlugin({
filename: 'style.css',
}),
new HtmlWebpackPlugin({
template: './src/index.html',
}),
Let me know you the issue still persists.
first you need to load style-loader and css-loader.Then you will add the following code in "rules" in webpack.config.js file.
{ test: /\.css$/,use: ['style-loader', 'css-loader']}
then import the "style.css" file location into the "index.js" file and for example:
import "./style.css";
When you package, "css" codes will be added in "bundle.js".
Related
I am building a workflow for a react starter and would like to have my browser auto reload when I make a change to my scss files.
Currently, webpack will hot reload when I make a change in my index.js file (set as my entry point). However when I change/add scss code in my scss file, it gets compiled, but the css doesn't get output anywhere and does not trigger a browser reload.
I am new to webpack would really appreciate some insight here.
Here is my webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: ['./src/js/index.js', './src/scss/style.scss'],
output: {
path: path.join(__dirname, 'dist'),
filename: 'js/index_bundle.js',
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.scss$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].css',
outputPath: 'css/'
}
},
{
loader: 'extract-loader'
},
{
loader: 'css-loader'
},
{
loader: 'postcss-loader'
},
{
loader: 'sass-loader'
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
}
My index.js entry point file
import React from 'react';
import ReactDOM from 'react-dom';
import App from '../components/App';
ReactDOM.render(
<App/>,
document.getElementById('App')
);
And my App component
import React, {Component} from 'react';
import '../../dist/css/style.css';
class App extends Component {
render() {
return (
<div>
<p>Test</p>
</div>
)
}
}
export default App;
Actually, style-loader is the one that is responsible for CSS HMR.
You should add it at the end of the style pipeline, only for dev.
For production, you can remain your config.
It should look something like that:
const devMode = process.env.NODE_ENV !== 'production'
{
test: /\.scss$/,
use: [
devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
{
loader: 'css-loader'
},
{
loader: 'postcss-loader'
},
{
loader: 'sass-loader'
}
]
}
Pay attention, the best practice of extracting css into a separate file is to use MiniCssExtractPlugin if you are using webpack 4, or ExtractTextWebpackPlugin, if you are using webpack < 4.
Try using Parcel instead of Webpack. I used to spend hours configuring Webpack to get things like hot reload working. With Parcel, most things just "work" without a configuration file. For example, I wanted to start using Pug templates. Parcel recognized the .pug extension and automatically downloaded the required NPM dependencies!
In your case, just include the SCSS file in your app like this: import '../scss/style.scss' (notice the path is to the .scss source file relative to index.js). Parcel will automatically do the "sensible" thing.
Here are some references to get started with Parcel + React + SASS:
Build a React web app with Parcel.js lightning fast
Parcel SCSS documentation
Notable advantages and disadvantages of Parcel vs WebPack:
Parcel requires minimal configuration; often no configuration.
Parcel usually builds much faster than WebPack.
The WebPack dev server seems more stable. (The Parcel dev server needs to restarted once in a while and doesn't play nice with Dropbox. Apparently this should be fixed in version 2.0.)
When (an uncommon) configuration is required, it might not be obvious how to do that in Parcel; at least in WebPack, all the configuration is in one place.
Sometimes Parcel's automatic configuration does thing people don't expect, confusing them.
I am using Webpack to bundle a number of js/css files in a site. I am bundling bootstrap.css and chosen.css as part of my bundles. In order to create the bundles, I have a main.js that I am using as an entry point to import all the other files that I will need. I am using file-loader to process font and image files and move them to the appropriate directories. I am using the ExtractTextPlugin with the css-loader and resolve-url-loader to create a separate css bundle from my js bundle.
My main.js is:
import 'bootstrap/dist/css/bootstrap.css';
import 'chosen-js/chosen.css';
import './datetimehelper.js';
import './deletelink.js';
import './dropdown.js';
My webpack.config.js is:
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: './src/js/main.js',
output: {
filename: 'wwwroot/js/bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
name: 'images/[name].[ext]',
outputPath: 'wwwroot/'
}
}
]
},
{
test: /\.(eot|svg|ttf|woff|woff2)$/,
use: [
{
loader: 'file-loader',
options: {
name: 'fonts/[name].[ext]',
outputPath: 'wwwroot/'
}
}
]
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: ['css-loader?url=false', 'resolve-url-loader'],
publicPath: '../'
})
}
]
},
plugins: [
new ExtractTextPlugin({
filename: 'wwwroot/css/bundle.css'
})
]
};
With the above configuration, the font references in bootstrap.css are picked up, moved to the appropriate directory and the urls are fixed in the css bundle that is emitted. However, the images that are referenced in chosen.css are not being picked up. Can anyone tell me what I need to do to make the images work correctly? I've tried replacing file-loader with url-loader and no change. I've also tried importing the images in my main.js and they were moved, but the urls in the css bundle were not rewritten correctly.
Having path configured in output makes life a lot easier. That would serve as the base output folder and all other loaders/plugins can work relative to that. May be the files were copied but not to your intended directory. Please do take a look at WebpackBootstrap repo. The config copies as well as converts image paths properly.
I finally figured it out. In the rules, I had:
{
test: /\.css$/,
use: ExtractTextPlugin.extract('css-loader', 'resolve-url-loader')
}
Instead, it should be:
{
test: /\.css$/,
loader: ExtratTextPlugin.extract('css-loader', 'resolve-url-loader')
}
Not sure what the difference is between use and loader because I'm fairly new to Webpack, but in this case it makes all the difference.
This has got to be one of the strangest issues with webpack i have ever come across...
Check out this bundle breakdown:
react 116.01KB - fair enough
react-dom 533.24KB - seriously WTF
I thought it may be a corruption in my dependencies but nuking node_modules and reinstalling doesn't have any effect. I guess it's something to do with the way webpack is bundling it but i'm lost for ideas. The way i'm handing .js imports is pretty stock standard.
// webpack.config.js
const path = require('path');
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const Dashboard = require('webpack-dashboard');
const DashboardPlugin = require('webpack-dashboard/plugin');
const dashboard = new Dashboard();
module.exports = {
context: path.join(__dirname, 'src'),
entry: {
bundle: './index.js',
},
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'build'),
},
module: {
rules: [
{
test: /\.html$/,
use: 'file-loader?name=[name].[ext]',
},
{
test: /.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
'css-loader',
'postcss-loader',
],
}),
},
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader',
},
],
},
plugins: [
// new BundleAnalyzerPlugin(),
new ExtractTextPlugin('styles.css'),
new DashboardPlugin(dashboard.setData),
],
devServer: {
quiet: true,
},
};
// .babelrc
{
"presets": [
"react",
"es2015"
],
"plugins": ["transform-object-rest-spread"]
}
http://elijahmanor.com/react-file-size/
In v15.4.0 the file size of react-dom grew from 1.17kB to 619.05kB. Which means my webpack setup isn't doing anything wrong bundling files. The reason why this module grew so large is because code was transferred from the react module.
I had to change my webpack.config.js, from
devtool: 'inline-source-map'
to
devtool: 'source-map'
Now it generates a much smaller .js + a separate .js.map file, for each of the chunks.
Notice the JS size is even less than react-dom.production.min.js in node_modules:
If you look into the corresponding folders under the node_modules folder, and note the file sizes, you'll see that there's nothing to be surprised about:
That is, the size of the bundle grows noticeably because the size of react-dom.js is large.
Add this following commands at plugins to minify your imports:
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.DefinePlugin(GLOBALS),
new webpack.optimize.UglifyJsPlugin(),
You should create a file or option to production bundle to use this plugins
I've spent hours attempting to get my Webpack config to compile Sass; it's kinda ridiculous. During my research I found dozens of Github issues, Stackoverflow posts, and blogs talking about how to use Sass with Webpack, and they all do it differently. Also, there are so many people with problems. I just think Webpack needs to be better documented. Ugh.
I figured out how to compile Sass and have Webpack serve it in memory from /static, but I want the class names to be locally scoped. Isn't that one of the benefits of modular CSS with React components?
Example of locally scoped: .foo__container___uZbLx {...}
So, this is my Webpack config file:
const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
devtool: 'source-map',
entry: {
bundle: './src/js/app'
},
output: {
path: __dirname,
filename: '[name].js',
publicPath: '/static'
},
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new ExtractTextPlugin('[name].css', {allChunks: true})
],
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
include: path.join(__dirname, 'src'),
loader: 'babel'
},
{
test: /\.scss$/,
exclude: /node_modules/,
include: path.join(__dirname, 'src'),
loader: ExtractTextPlugin.extract('style', 'css?sourceMap!sass')
}
]
}
};
I managed to get it to work for vanilla CSS:
{
test: /\.css$/,
exclude: /node_modules/,
include: path.join(__dirname, 'src'),
loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]')
}
I don't really understand the parameter-like syntax with all the ? marks, and I don't know what to search for to find documentation pertaining to that.
This is what my React component looks like; just incase you want to see how I am importing the style:
import React, { Component } from 'react';
import s from './foo.css';
class Foo extends Component {
render() {
return (
<div className={s.container}>
<h1 className="title">Welcome!</h1>
<p className="body">This is a dummy component for demonstration purposes.</p>
</div>
);
}
}
export default Foo;
Also, I have three unrelated questions:
What's the point of output.path property if Webpack merely serves the file from memory by means of /static?
What's the point of webpack-dev-server if what I am doing here is adequate? From my understanding, webpack-dev-server is just for hot module replacement stuff, right? Just automatic refreshing?
Are my exclude and include properties redundant? From my understanding, excluding node_modules decreases the compilation time making it work quicker; less files to process.
I got it to work with this:
loader: ExtractTextPlugin.extract('style', 'css?modules&localIdentName=[name]__[local]___[hash:base64:5]!sass')
All I had to do was put !sass at the end of the query. I wish this stuff was better documented; can't find adequate docs anywhere...
I'm trying to create a React application with multiple entries using webpack and extract-text-webpack-plugin.
My config file looks like this,
const commonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
const extractTextPlugin = require('extract-text-webpack-plugin');
let config = {
entry: {
app: './client/app.entry.js',
signIn: './client/sign-in.entry.js',
},
output: {
path: './server/public',
filename: '[name].js'
},
module: {
loaders: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015']
}
},
{
test: /\.css$/,
loader: extractTextPlugin.extract('style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]')
}
]
},
resolve: {
modulesDirectories: ['node_modules', 'client'],
extensions: ['', '.js']
},
plugins: [
new commonsChunkPlugin('common', 'common.js'),
new extractTextPlugin('styles.css', { allChunks: true })
]
};
module.exports = config;
My problem is that extract-text-webpack-plugin only includes imported css files from the entry chunks, and not from submodules of the entry chunks.
So if app.entry.js has
import "./app-style.css";
import "./sub-module"; // This module has import "./sub-style.css";
then the styles from app-style.css gets bundled but not the styles from sub-style.css.
I haven't had this issue before when there's only been one entry file, so I'm wondering if having multiple entries requires another setup?
Something to also take into consideration is the use of CSSModules by the way the css-loader is used, which also could be a factor.
Any ideas?
I'm trying to solve similar problem, and i think it will be nice idea to document the solution and thoughts for those who has the same questions.
TextExtract plugin can work with chunks that have to be configured with commonchunks plugin, enable chunks support:
// Configuration of the extract plugin with chunks and naming
new ExtractTextPlugin("[name].css", { allChunks: true })
It's all ) Next thing is just configuration of the chunks (webpack is very flexible tool, everyone configure it for own needs. For an instance i'll show how i configure "vendour.css" and "application.css" build configuration based on "imports")
// Vendour chunks definition for vendor css
entry: {
vendor : ['./css/vendour.sass']
Example of entrypoint file.js
import "./css/vendor.sass"
import "./css/application.sass"
After build, webpack will create vendor.css (where you export vendour things with #import "~vendormodules/sass/alla") and application.css files.
Thanks,