Webpack recompiles CSS but does not update - javascript

Using webpack 4.1.1 and webpack-dev-server I have the following webpack.dev.js file
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin')
const src = path.resolve(__dirname, "../");
const build = path.resolve(__dirname, "../../build");
const components = path.resolve(__dirname, "../components");
const icons = path.resolve(__dirname, "../static/icons");
const images = path.resolve(__dirname, "../static/images");
const context = path.resolve(__dirname, 'src');
module.exports = {
mode: 'development',
entry: `${src}/index.js`,
output: {
filename: "bundle.js",
path: build
},
resolve: {
alias: {
components: components,
icons: icons,
images: images
}
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
path: build
}),
new HtmlWebpackPlugin({
template: './src/index.html'
}),
],
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/,
query: {
plugins: [
"transform-react-jsx",
[
"react-css-modules",
{
context
}
]
]
}
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader:'css-loader',
options:{
modules: true
}
}
]},
{
test: /\.(gif|png|jpe?g|svg)$/i,
use: [
'file-loader',
{
loader: 'image-webpack-loader',
options: {
bypassOnDebug: true,
},
},
],
},
{
test: /\.svg/,
use: {
loader: 'svg-url-loader',
options: {}
}
}
]
},
};
My issue is that when I update a CSS file, i watch the terminal, it says it compiles successfully, however I don't see the changes in the browser. Even when I navigate directly do localhost:8080/main.css, the old CSS file is still shown. The only way I can get the CSS to successfully recompile is to stop the dev server and start it all over again.
FWIW, here is my startup script:
$ ./node_modules/.bin/webpack-dev-server --config ./src/config/webpack.dev.js --content-base build/ --content-base src/static
Can someone tell me what I'm missing here?

Related

Webpack multiple entries under certain urls

Hey I have this project which has this structure:
bundler -> webpack.common.js
src -> main.js, index.html, styles.css
package.json
node_modules... the rest doesnt matter really
It is set up like when I do: npm run dev webpack creates a live server using my current main.js for my index.html
The webpack.common.js looks like this:
const CopyWebpackPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const path = require("path");
module.exports = {
entry: path.resolve(__dirname, "../src/current_script.js"),
output: {
hashFunction: "xxhash64",
filename: "bundle.[contenthash].js",
path: path.resolve(__dirname, "../dist"),
},
devtool: "source-map",
plugins: [
new CopyWebpackPlugin({
patterns: [{ from: path.resolve(__dirname, "../static") }],
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../src/index.html"),
minify: true,
}),
new MiniCSSExtractPlugin(),
],
module: {
rules: [
// HTML
{
test: /\.(html)$/,
use: ["html-loader"],
},
// JS
{
test: /\.js$/,
exclude: /node_modules/,
use: ["babel-loader"],
},
// CSS
{
test: /\.css$/,
use: [MiniCSSExtractPlugin.loader, "css-loader"],
},
// Images
{
test: /\.(jpg|png|gif|svg)$/,
type: "asset/resource",
generator: {
filename: "assets/images/[hash][ext]",
},
},
// Fonts
{
test: /\.(ttf|eot|woff|woff2)$/,
type: "asset/resource",
generator: {
filename: "assets/fonts/[hash][ext]",
},
},
],
},
};
```
Now my question is how can I define multiple entries under certain URLs.
So for example now under localhost/ it will redirect me to index.html using my main.js
Is there a way of having localhost/2 use my index.html with another js file like main2.js

How to ignore error js script tag from html on running webpack with HtmlWebpackPlugin?

How can i ignore the script tag in Html webpack plugin?
Because I have added this
<script src="cordova.js"/>
tag into my index.html template anonymously for my app development.
See my configuration in Webpack.config.js:
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "www"),
filename: "./js/build/[name].build.js",
chunkFilename: "./js/build/[name].build.js",
// publicPath: "./js/build/",
},
module: {
rules: [
{
test: /\.m?js$/,
use: {
loader: "babel-loader",
options: {
presets: ["#babel/preset-env"],
},
},
},
{
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: "./",
},
},
"css-loader?url=false",
"sass-loader",
],
},
{
test: /\.html$/,
use: ["html-loader"],
},
{
test: /\.(svg|png|jpeg|jpg|gif)$/,
use: {
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "res",
},
},
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "./css/build/[name].css",
// chunkFilename: "../css/[id].css"
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
// new BundleAnalyzerPlugin()
],
// devtool: "inline-source-map",
};
I just wanted to ignore the script on production and I have researched this many times but unfortunately I don't see any solution
So, if I got the problem right, you want to ignore a certain resource when bundling for production.
The html-loader has an option to filter sources based on attribute, attribute value, context file and anything you have available in you webpack.config.js.
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// Assuming you are passing arguments to your webpack config like argv.mode
const PRODUCTION = true;
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "www"),
filename: "./js/build/[name].build.js",
chunkFilename: "./js/build/[name].build.js",
// publicPath: "./js/build/",
},
module: {
rules: [
{
test: /\.m?js$/,
use: {
loader: "babel-loader",
options: {
presets: ["#babel/preset-env"],
},
},
},
{
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: "./",
},
},
"css-loader?url=false",
"sass-loader",
],
},
{
test: /\.html$/,
use: {
loader: "html-loader",
options: {
sources: {
urlFilter: (attribute, value, resourcePath) => {
if (PRODUCTION && /cordova.js$/.test(value)) {
return false;
}
return true;
},
}
},
},
},
{
test: /\.(svg|png|jpeg|jpg|gif)$/,
use: {
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "res",
},
},
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "./css/build/[name].css",
// chunkFilename: "../css/[id].css"
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
// new BundleAnalyzerPlugin()
],
// devtool: "inline-source-map",
};
In the html module rule, I added an options property to html-loader with an example how you could ignore a certain resource with urlFilter. Check the html-loader docs on filtering resources
You will need to get a reference to the variables you passed to your cli like --mode eg. line 5-6. (Not in the current example) See webpack docs on env vars.

webpack 4 gives background: url([object Module]) as bg image

I'm having issues with setting up web-pack 4 and svg-sprite-loader to render svg icons as background images. I was following these instructions from official docs for svg-sprite-loader (https://github.com/kisenka/svg-sprite-loader/tree/master/examples/extract-mode).
I have successfully managed to create sprite.svg file in my dist folder and use it as reference for my use tags inside of html. However, i was also trying to use svg icons from my src/images/icons folder for a background image like this:
background: url('../images/icons/upload_icon.svg') 10% 50% no-repeat;
when doing this, webpack compiles correctly, but creates this in dist css file:
background: url([object Module]) 10% 50% no-repeat;
Any help would be great.
here is my webpack config file:
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const SpriteLoaderPlugin = require("svg-sprite-loader/plugin");
module.exports = {
mode: "development",
devtool: "source-map",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist")
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
sourceMap: true
}
}
},
{
// scss configuration
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader"
},
{
loader: "postcss-loader"
},
{
loader: "sass-loader",
options: {
sourceMap: true
}
}
]
},
{
// html configuration
test: /\.html$/,
use: {
loader: "html-loader"
}
},
{
// images configuration
test: /\.(jpg|jpeg|gif|png|woff|woff2)$/,
use: [
{
loader: "file-loader",
options: {
name: "[path][name].[ext]"
}
}
]
},
{
test: /\.svg$/,
use: [
{
loader: "svg-sprite-loader",
options: {
extract: true,
spriteFilename: "sprite.svg"
}
}
]
}
]
},
plugins: [
// all plugins used for compiling by webpack
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: "Style Guide",
template: path.resolve(__dirname, "src", "index.html")
}),
new MiniCssExtractPlugin({
filename: "app.css"
}),
new SpriteLoaderPlugin()
]
};
Adding esModule: false to the file-loader options did the trick for me.
{
test: /\.(jpg|png|gif|svg)$/,
use: {
loader: 'file-loader',
options: {
name: "[name].[ext]",
outputPath: "img",
esModule: false
}
},
You have to pass esModule: false for svg-sprite-loader options.
By the way (it is not related to esModule): With MiniCssExtractPlugin you can not to extract svg sprite. I've faced this problem one hour ago..
After a few hours, I have managed to make this thing to work, thanks to #WimmDeveloper for pointing me in right direction. Main change from prior webpack config file is that I have added esModule: false in svg-sprite-loader options and replaced MiniCssExtractPlugin with extract-text-webpack-plugin. Mind you that this solution is not ideal since this webpack plugin is deprecated.
here is my full webpack config file:
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const SpriteLoaderPlugin = require("svg-sprite-loader/plugin");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
mode: "development",
devtool: "source-map",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist")
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
sourceMap: true
}
}
},
{
test: /\.(s*)css$/,
use: ExtractTextPlugin.extract({
use: ["css-loader", "postcss-loader", "sass-loader"]
})
},
{
// html configuration
test: /\.html$/,
use: {
loader: "html-loader"
}
},
{
test: /\.svg$/,
use: [
{
loader: "svg-sprite-loader",
options: {
esModule: false,
extract: true,
spriteFilename: "sprite.svg"
}
}
]
},
{
// files configuration
test: /\.(jpg|jpeg|gif|png|woff|woff2)$/,
use: [
{
loader: "file-loader",
options: {
name: "[path][name].[ext]"
}
}
]
}
]
},
plugins: [
// all plugins used for compiling by webpack
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: "Style Guide",
template: path.resolve(__dirname, "src", "index.html")
}),
new ExtractTextPlugin({ filename: "app.css" }),
new SpriteLoaderPlugin()
]
};

Adding a csv file to a webpack build

I have placed a csv file in my assets folder for my react app, however, that file is not getting picked up and added to my dist build via webpack (the images are still added as assets to the build but the csv file is not). You can see my webpack build below. So how do I add a csv file to my dist build via webpack (the goal is for users of my app to be able to download this file)? Thanks!
webpack.dev.js
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const config = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
devServer: {
contentBase: './dist',
historyApiFallback: true,
hot: true,
proxy: {
'/api': {
target: 'http://localhost:5001',
secure: false,
},
},
allowedHosts: [
'localhost',
'fatpandadev'
],
public: 'fatpandadev:8080'
},
});
module.exports = config;
webpack.common.js
const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const DIST_DIR = path.resolve(__dirname, "dist");
const SRC_DIR = path.resolve(__dirname, "src");
const config = {
entry: [
"babel-polyfill",
`${SRC_DIR}/app/index.js`,
`${SRC_DIR}/app/assets/stylesheets/application.scss`,
`${SRC_DIR}/app/components/index.scss`,
"font-awesome/scss/font-awesome.scss",
"react-datepicker/dist/react-datepicker.css",
"rc-time-picker/assets/index.css",
"react-circular-progressbar/dist/styles.css",
"#trendmicro/react-toggle-switch/dist/react-toggle-switch.css",
],
output: {
path: `${DIST_DIR}/app/`,
filename: "bundle.js",
publicPath: "/app/"
},
module: {
rules: [
{
enforce: "pre",
test: /\.js$/,
exclude: /node_modules/,
loader: "eslint-loader",
options: {
failOnWarning: false,
failOnError: true
}
},
{
test: /\.js$/,
include: SRC_DIR,
loader: 'babel-loader',
query: {
presets: ['react', 'stage-2']
}
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader'
]
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
loaders: ['file-loader?context=src/images&name=images/[path][name].[ext]', {
loader: 'image-webpack-loader',
query: {
mozjpeg: {
progressive: true,
},
gifsicle: {
interlaced: false,
},
optipng: {
optimizationLevel: 7,
},
pngquant: {
quality: '75-90',
speed: 3,
},
},
}],
exclude: path.resolve(__dirname, "node_modules"),
include: __dirname,
},
{
test: /\.woff2?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
// loader: "url?limit=10000"
use: "url-loader"
},
{
test: /\.(ttf|eot|svg)(\?[\s\S]+)?$/,
use: 'file-loader'
},
{
test: /\.(txt|csv)$/,
use: [
{
loader: 'file-loader',
options: {}
}
]
},
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "application.css"
})
]
};
module.exports = config;
(this answer is only referenced on the server side)
In addition to #PlayMa256,
On Server side(Nodejs runtime), you may need emitFile: true
{
test: /\.(txt|csv|mmdb)$/,
use: [
{
loader: 'file-loader',
options: {
name: "[path][name].[ext]",
emitFile: true,
},
},
],
},
Refer to this PR: https://github.com/webpack-contrib/file-loader/pull/135
In my opinion, file-loader way seem to better than copy-webpack-plugin way.
You can test like below:
import csvPath from './assets/data.csv'
console.log(csvPath) // assets/data.csv
Tested version:
$ cat node_modules/webpack/package.json | jq .version
"4.29.5"
$ cat node_modules/file-loader/package.json | jq .version
"3.0.1"
You might want to check the CopyWebpackPlugin if you have no need to process/parse the files, but only to copy them to your dist folder.
Copy Webpack Plugin
Copies individual files or entire directories to the build directory
Install
npm i -D copy-webpack-plugin
Usage
webpack.config.js
const CopyWebpackPlugin = require('copy-webpack-plugin')
const config = {
plugins: [
new CopyWebpackPlugin([ ...patterns ], options)
]
}
Patterns
A simple pattern looks like this
{ from: 'source', to: 'dest' }
{
test: /\.(txt|csv)$/,
use: [
{
loader: 'file-loader',
options: {}
}
]
}
You should import you csv file as you import your images too.
import your csv files using raw-loader,
{
test: /\.csv$/i,
use: 'raw-loader',
}

Can the PurifyCss plugin be forced to wait until the bundle is ready?

My first "Hello Webpack" project was going great until I started integrating purifycss-webpack. If I delete my /dist folder manually and then build, this config works. But if the /dist folder exists and CleanWebpackPlugin deletes it as its designed to do, then PurifyCSS throws this error:
clean-webpack-plugin: \dist has been removed.
purifycss-webpack\dist\index.js:52 \ if (!_fs2.default.existsSync(p))
throw new Error('Path ' + p + ' does not exist.');
Is there another way to have Webpack run PurifyCSS only AFTER all the other plugins have executed? I thought I was doing that by placing it last in the plugins array, but this feels like execution order issues to me. Here's my config:
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const globAll = require('glob-all');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
const PurifyCSSPlugin = require('purifycss-webpack');
const webpack = require("webpack");
var extractPluginCSS = new ExtractTextPlugin({
filename: "app.css"
});
module.exports = {
entry: "./src/js/app.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "app.js"
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: "babel-loader",
options: {
presets: ["env"]
}
}
]
},
{
test: /app\.scss$/,
use: extractPluginCSS.extract({
use: [
{
loader: "css-loader",
options: {}
},
{
loader: "sass-loader",
options: {}
}
]
})
},
{
test: /\.html$/,
use: ["html-loader"]
},
{
test: /\.(jpg|png)$/,
use: [
{
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "img/"
}
}
]
}
]
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
template: "./src/html/index.html"
}),
new webpack.optimize.UglifyJsPlugin(),
extractPluginCSS,
new PurifyCSSPlugin({
// Give paths to parse for rules. These should be absolute!
paths: globAll.sync([
path.join(__dirname, '/dist/*.html')
]),
// minimize: true,
verbose: true
})
]
};

Categories

Resources