webpack-hot reload - CSS stylesheet doesnt update - css

This is my below express setup
if(process.env.NODE_ENV.trim()==='development'){
app.use(webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath,
stats: {colors: true}
}))
app.use(webpackHotMiddleware(compiler, {
log: console.log
}))
}
webpack.config
module.exports = {
entry:[
'webpack/hot/dev-server',
'webpack-hot-middleware/client?http://0.0.0.0:8080&reload=true',
'./client/index.js'
],
output:{
path:__dirname + '/public',
publicPath: '/',
filename: 'bundle.js'
},
module:{
rules:[
{
test:/(\.js|\.jsx)$/,
exclude: /(node_modules)/,
use: [
{
loader: 'react-hot-loader'
},
{
loader: 'babel-loader',
}
]
},
{ test: /\.json$/, loader: 'json-loader' },
{
test: /(\.css|\.scss)$/,
loader: ExtractTextPlugin.extract({fallback: 'style-loader',loader: extract_loaders})
},
{
test : /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/,
loader : 'file-loader'
}
]
},
resolve:{
extensions:['.js', '.jsx']
},
plugins:[
new ExtractTextPlugin({filename: 'style.css', allChunks: true}),
new CopyWebpackPlugin([
{from: 'client/images' ,to: 'public/images'}
]),
new webpack.HotModuleReplacementPlugin(),
new webpack.LoaderOptionsPlugin({ options: { postcss: [ autoprefixer ] } })
],
}
When i update my jsx files - the site seems to update. But the hot update doesnt happen when i change my css files
webpack seems to compile properly though when css is changed. but for some reasons , the new style.css file isnt seen in the browser.
if it'll be of any help .. i'm importing the style.css file from my HTML file
<link rel="stylesheet" type="text/css" href="/style.css">
update: when i change my css file , i get the below messages in my console
[HMR] Checking for updates on the server...
[HMR] Nothing hot updated
this doesnt appear when i change .jsx

Just don't use ExtractTextPlugin in development webpack configuration, because it extracts your styles to separate file, so HMR can't do nothing with it. Fast fix:
{
test: /\.scss$/,
loader: 'style-loader!css-loader!sass-loader'
// use: ExtractTextPlugin.extract({
// fallback: "style-loader",
// use: "css-loader!sass-loader",
// })
}

Since you have babel and webpack you can just import your css files in code files.
Example:
import 'styles.css';
It would be then bundled and loading should work.

Perhaps the issue is with the import line?
Have you tried it without the backslash? (assuming it's in the same directory)
<link rel="stylesheet" type="text/css" href="style.css">

Related

How to stop WebPack from including CSS file in the html even though it is already included in the produced js file

I am using WebPack to build a chrome extension. I import the css file in the popup.js file and it correctly styles my page but bundler also inserts the css file to the html which is unnecessary if I know correctly since it is injected to the output js file. Because the css file is included in the hmtl, I get a "Failed to load resource: net::ERR_FILE_NOT_FOUND". I want to know how to exclude the CSS file from the html and basically dont have the following line.
<link rel="stylesheet" href="popup-styles.css" />
This is my webpack.config.js file.
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
entry: {
popup: "./src/popup.js",
background: "./src/background.js",
content: "./src/content.js",
},
output: {
path: path.resolve(__dirname, "dist"),
filename: "[name].js",
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["#babel/preset-env", "#babel/preset-react"],
},
},
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/popup.html",
filename: "popup.html",
chunks: ["popup"],
}),
new CopyPlugin({
patterns: [{ from: "public" }],
}),
],
};

Compile CSS and JS in difference files / WEBPACK

For 2 days I have been trying to compile the js and css file to a separate file because now everything is together. Does anyone have any idea how this can be solved?
I would be very grateful for your help.
There is my code webpack.config.js
const path = require('path');
const webpack = require('webpack');
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'src/dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
{
test: /\.scss$/,
use: [
"style-loader", // creates style nodes from JS strings
{
loader: "css-loader",
options: {
url: false
}
},
"sass-loader" // compiles Sass to CSS, using Node Sass by default
]
},
]
},
plugins: [
new BrowserSyncPlugin({
// browse to http://localhost:3000/ during development,
// ./public directory is being served
host: 'localhost',
port: 3000,
files: ['./src/*.html'],
server: { baseDir: ['src'] }
}),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
]
};
I think MiniCssExtractPlugin is what you are looking for.
It takes the output of css-loader and create .css bundles. It takes care of downloading them in the browser (by pushing a section of code in webpack runtime code), and also yeah, it minifies the .css :).
Simple usage:
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
plugins: [new MiniCssExtractPlugin()],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
};
Yes you are right. Style-loader creates javascript snippets that later in runtime creates .css rules and push them to the browser global css scope.

Webpack 4 - Style-loader/url not working

I'm having my webpack set up and it's running all fine, but in development it is serving my compiled scss stylesheets inline instead of using an URL.
module: {
rules: [
{
test: /\.scss$/,
use: [
{ loader: "style-loader"},
{ loader: "css-loader" },
{ loader: 'postcss-loader',
options: {
plugins: () => [require('autoprefixer')]
}
},
{ loader: "sass-loader" }
]
}
]
}
So I grabbed the docs and read up on how to use a single CSS file instead. I updated my webpack config to the following and since all loaders are running in reverse order this should be working;
module: {
rules: [
{
test: /\.scss$/,
use: [
{ loader: "style-loader/url"},
{ loader: "file-loader" },
{ loader: "css-loader" },
{ loader: 'postcss-loader',
options: {
plugins: () => [require('autoprefixer')]
}
},
{ loader: "sass-loader" }
]
}
]
}
It results in no errors, and inserts the following stylesheet into my header;
<link rel="stylesheet" type="text/css" href="6bbafb3b6c677b38556511efc7391506.scss">
As you can see it's creating an scss file, whereas I was expecting a .css file. I tried moving the file-loader around but that didn't work either and resulted in several crashes. Any idea how to turn this into a working css file?
I can't use mini-css-extract in my dev env since I'm using HMR. I already got this working on my prod env.
Update: When removing css-loader it compiles and shows my css applied to the page. But when I inspect the elements everything is on line 1 and the file it refers to can not be found
I'm importing my css like this in index.js by the way;
import '../css/styles.scss';
You can install extract-text-webpack-plugin for webpack 4 using:
npm i -D extract-text-webpack-plugin#next
The you can define the following constants:
// Configuring PostCSS loader
const postcssLoader = {
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: [
// Write future-proof CSS and forget old preprocessor specific syntax.
// It transforms CSS specs into more compatible CSS so you don’t need to wait for browser support.
require('postcss-preset-env')()
]
}
};
// Configuring CSS loader
const cssloader = {
loader: 'css-loader',
options: {
importLoaders: 1
}
};
Then in your SASS loader section, you can use the following:
ExtractTextPlugin.extract({
use: [cssloader, postcssLoader, 'sass-loader']
})
Then in you plugins section, you need to use the following:
new ExtractTextPlugin({
filename: 'css/[name].css'
)
Now suppose that your entry section is like below:
entry: {
app: 'index.js'
}
The generated CSS will be named as app.css and placed inside the css folder.
Another useful plugins for handling these type of post creating operations are:
HtmlWebpackPlugin and HtmlWebpackIncludeAssetsPlugin
Working with these plugins along with extract-text-webpack-plugin gives you a lot of flexibility.
I had a similar issue with webpack, after searching for a long time i found the soluton of combining a few plugins:
This is my result config: (as a bonus it preserves your sass sourcemaps;))
watch: true,
mode: 'development',
devtool: 'source-map',
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css", //make sure you use this format to prevent .scss extention in the hot reload file
chunkFilename: "[id].css"
})
],
module: {
rules: [
{
test: /\.scss$/,
use: [
'css-hot-loader', //5. this will hot load all the extracted css.
MiniCssExtractPlugin.loader, //4 this will extract all css
{
loader: "css-loader", //3. this is where the fun starts
options: {
sourceMap: true
}
},
{
loader: "postcss-loader", //2. add post css
options: {
sourceMap: true
}
},
{
loader: "sass-loader", //1 . you can ingore the globImporter
options: {
importer: globImporter(),
includePaths: ["node_modules"],
sourceMap: true
}
}
]
},
]
}

How to configure global css and sass stylesheet with webpack, typescript, phaser and angular

The following configuration is made by hand to support all technologies given in the title (webpack, typescript, phaser and angular).
It works great for angular component stylesheet. But it looks like it's impossible to include a global style sheet. Here are related configuration files:
HTML file:
<!-- src/index.html -->
<!DOCTYPE html>
<html>
<head>
<base href="/">
<meta charset="UTF-8">
<!-- it's included here! -->
<link rel="stylesheet" href="styles/main.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<app-root></app-root>
</body>
</html>
CSS file:
/*
src/styles/main.css
This file is correctly loaded in dev environment. When I build the project it disapear. :(
*/
body {
background: #253050 url('../assets/design/main_background.jpg') no-repeat center;
}
And webpack configuration:
// config/webpack.common.js
'use strict';
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
const path = require('path');
var helpers = require('./helpers');
var distDir = path.resolve(__dirname, '../dist');
// Phaser webpack config
const phaserModule = path.join(__dirname, '/../node_modules/phaser-ce/');
const phaser = path.join(phaserModule, 'build/custom/phaser-split.js');
const pixi = path.join(phaserModule, 'build/custom/pixi.js');
const p2 = path.join(phaserModule, 'build/custom/p2.js');
module.exports = {
entry: {
'polyfills': './src/polyfills.ts',
"app": "./src/main.ts"
},
// What files webpack will manage
resolve: {
extensions: ['.js', '.ts', '.tsx'],
alias: {
'phaser': phaser,
'pixi': pixi,
'p2': p2
}
},
output: {
path: distDir,
filename: '[name]_bundle.js'
},
module: {
rules: [
{ test: /assets(\/|\\)/, use: [ 'file-loader' ] },
{
test: /\.tsx?$/,
// ts-loader loads typescript files
// angular2-template-loader is needed to load component templates
loaders: ['ts-loader', 'angular2-template-loader'],
exclude: [
/.+phaser-ce\/typescript\/.+\.ts$/,
/typescript\/.+\.d\.ts$/
]
},
{
test: /\.html$/,
loader: 'html-loader'
},
// to-string-loader is for css loaded by angular components
// .... and loading angular css work as expected.
{ test: /\.css$/, loaders: ['to-string-loader', 'css-loader'] },
{
test: /\.scss$/, // I'd like so much sass work but guess what... it doesn't!
use: ['to-string-loader', 'css-loader', 'sass-loader']
},
// Because phaser and its dependencies are not made for TypeScript and webpack
{ test: /pixi\.js/, use: [{loader: 'expose-loader', options: 'PIXI'}] },
{ test: /phaser-split\.js$/, use: [{loader: 'expose-loader', options: 'Phaser'}] },
{ test: /p2\.js/, use: [{loader: 'expose-loader', options: 'p2'}] }
]
},
plugins: [
new webpack.ContextReplacementPlugin(
// The (\\|\/) piece accounts for path separators in *nix and Windows
// For Angular 5, see also https://github.com/angular/angular/issues/20357#issuecomment-343683491
/\#angular(\\|\/)core(\\|\/)esm5/,
helpers.root('src'), // location of your src
{
// your Angular Async Route paths relative to this root directory
}
),
new CleanWebpackPlugin([distDir]),
new HtmlWebpackPlugin({
template: 'src/index.html',
chunksSortMode: function(a, b) {
// set the load order !
var order = ["polyfills", "app"];
return order.indexOf(a.names[0]) - order.indexOf(b.names[0]);
}
})
]
};
And here is webpack.prod.js configuration:
module.exports = merge(common, {
devtool: 'source-map',
plugins: [
// stops the build if there is an error
new webpack.NoEmitOnErrorsPlugin(),
new UglifyJSPlugin({sourceMap: true}),
// extracts embedded css as external files, adding cache-busting hash to the filename
new ExtractTextPlugin('[name].[hash].css'),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
]
});
When I run webpack --config config/webpack.prod.js the global CSS is not load, there is no error. Just no CSS.
Feel free to explain also how to load SCSS because it doesn't work even in development mode for me.
Thanks!
I finally make it work. So here is the changes I made:
1) The path to style.css is now ignored in css/scss clauses.
{
exclude: path.resolve(__dirname, '../src/styles'),
test: /\.css$/, loaders: ['to-string-loader', 'css-loader']
},
{
exclude: path.resolve(__dirname, '../src/styles'),
test: /\.scss$/,
use: ['to-string-loader', 'css-loader', 'sass-loader']
}
2) The I added a new entry file for the CSS
entry: {
'polyfills': './src/polyfills.ts',
'app': './src/main.ts',
'css': './src/styles/main.css'
}
3) It works because I also configured a new rule that uses the ExtractTextPlugin
{
test: /\.css$/,
exclude: path.resolve(__dirname, '../src/app'),
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader'
})
}
Notice that this works also because the prod configuration specify new ExtractTextPlugin('[name].[hash].css') as plugin. (it means you need to add it in the common configuration to avoid any error in dev environment)
I Think you need to use angular-cli where you can set the custom css url in angular-cli.JSON like as below :
"styles": [
"../node_modules/bootstrap/dist/css/bootstrap.min.css",
"../node_modules/font-awesome/css/font-awesome.min.css"
],
more global styles can be set in .angular-cli.json, it maybe looks like this:
...
"apps": [
{
...
"styles": [
"app/core/preloader/preloader.scss",
"styles.scss"
],
...
}
]
...
in app section, you should found that more global assets/scripts can be set here.
more about .angluar-cli.json is here

unable to load css in react js

my all css files placed under src/assets/css/* and i am trying to import or load css file inside my component, i have tried to load css with below webpack configuration
Webpack file
{ test: /\.css$/, loader: "style-loader!css-loader" }
Component
import './../../assets/css/bootstrap.min.css';
Also tried to load css in index.html file like <link rel="stylesheet" href="/src/assets/css/bootstrap.min.css">
Also, is there a way if i have 5-6 css files by which i dont need to load all files in every component like if we can add in <head> tag
Here is my webpack.config file. I have used foundation instead of bootstrap but the webpack configuration is similar.
var webpack = require('webpack');
var path = require('path');
module.exports = {
entry: [
'script!jquery/dist/jquery.min.js',
'script!foundation-sites/dist/js/foundation.min.js',
'./app/app.jsx'
],
externals: {
jquery: 'jQuery'
},
plugins:[
new webpack.ProvidePlugin({
'$': 'jquery',
'jQuery': 'jquery'
})
],
output: {
path: __dirname,
filename: './public/bundle.js'
},
resolve: {
root: __dirname,
modulesDirectories: [
'node_modules',
'./app/components',
'./app/api'
],
alias: {
applicationStyles: 'app/styles/app.scss',
actions: 'app/actions/actions.jsx',
reducers: 'app/reducers/reducers.jsx',
configureStore: 'app/store/configureStore.jsx'
},
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [
{
loader: 'babel-loader',
query: {
presets: ['react', 'es2015', 'stage-0']
},
test:/\.jsx?$/,
exclude: /(node_modules|bower_components)/
}
]
},
sassLoader:{
includePaths: [
path.resolve(__dirname, './node_modules/foundation-sites/scss')
]
},
devtool: 'cheap-module-eval-source-map'
};
And yes you can bundle the css in one file with webpack and import it in the root component.
Check my github repo for more details- https://github.com/hmachaharywork/ReactTodo
Use Extract text plugin. Only import this plugin in your webpack.conf.js
const ExtractTextPlugin = require("extract-text-webpack-plugin");
and refactor your rule like:
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
}
Finally, push new instance in plugin list:
plugins: [
new ExtractTextPlugin("styles.css"),
]

Resources