how to make auto reload work when HMR enabled - html

I've been trying multiple times to configure webpack. Everytime I start the process, auto reload works fine all the way, until I enable --hot for web-dev-server, then any change to the html has no impact, no errors, nothing, just a log in terminal that there's been a change, and a log on browser console that there's nothing to update. Hot reload works fine for CSS and JS, and I understand HTML doesn't support HMR but at least expected auto refresh to keep working ...
My configuration below:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin');
const webpack = require('webpack');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'app.js',
path: path.resolve(__dirname, 'dist'),
},
plugins: [
new HtmlWebpackPlugin({
title: 'Hello world',
template: 'src/views/index.html',
alwaysWriteToDisk: true
}),
new HtmlWebpackHarddiskPlugin(),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin()
],
devtool: 'inline-source-map',
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
hot: true,
inline: true,
open: true,
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader',
]
}
]
}
};
My scripts in package.json
"scripts": {
"dev": "webpack-dev-server --config webpack.config.js",
"prod": "cross-env NODE_ENV=production webpack -p --config webpack.config.js"
},

I am not sure if this is the "right" way to achieve it. But this is working for me with the following amends.
devServer: {
**contentBase: resolve('src/views'),**
open: true,
hot: true,
stats: "errors-only",
overlay: true,
**watchContentBase: true**
},
This does not seem to make sense to me but, if you set watchContentBase to true and point the contentBase to "dist", you lose HMR and any changes (event to css/js files) will cause a full reload which is not what I was aiming for.
my src structure below:
/ src
- images
- js
- sass
- views
I had also a look at vue-cli which seems to suffer from the same issue. Any changes to the index.html are not reflected (does not trigger a full page reload).

Related

Webpack 5, How to make live reload when I update html file after the service run

I want the server reload the page automatic when I update the html file but I keep getting error.
[webpack-dev-middleware] HookWebpackError: Path variable [id] not implemented in this context: [id].[fullhash].hot-update.js
I am not sure if I set the dev-server correctly or the plugin I use make this error.
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "main.js",
},
mode: "development",
devtool: "source-map",
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.html$/,
use: ["html-loader"],
},
],
},
plugins: [
new MiniCssExtractPlugin(),
new HtmlWebpackPlugin({
title: "Bootstrap 2",
template: "src/index.html",
filename: "index.html",
}),
],
optimization: {
chunkIds: false,
},
devServer: {
port: 9000,
historyApiFallback: true,
hot: true,
static: path.resolve(__dirname,"dist")
},
};

Webpack 4 not loading images from HTML files

For some reason my webpack configuration is loading the images that comes from my SCSS files but not the ones that come from the HTML files. Also when I run the BUILD command in order to deliver my prod archives it does not create the "img" folder. To be honest I'm pretty new with webpack 4 and I guess there's a couple of steps that I'm not including on the WP config file.
This is my webpack.dev.js
This is the prod folder structure that I would want to create:
dist
|----img
|----css
|----js
a.html
b.html
c.html
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
module.exports = {
entry: {
main: "./src/js/scripts.js"
},
output: {
path: path.resolve(__dirname, "dist"),
filename: "js/[name].[hash].js"
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.scss$/,
use: [
"style-loader",
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"sass-loader"
]
},
{
test: /\.(png|jpg|gif)$/,
use: ["url-loader"]
}
]
},
devServer: {
port: 8080
},
plugins: [
new CleanWebpackPlugin("dist", {}),
new MiniCssExtractPlugin({
filename: "css/style.[contenthash].css"
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
inject: false,
hash: true,
filename: "index.html"
}),
new HtmlWebpackPlugin({
template: "./src/actualitat.html",
inject: false,
hash: true,
filename: "actualitat.html"
}),
new HtmlWebpackPlugin({
template: "./src/projectes.html",
inject: false,
hash: true,
filename: "projectes.html"
})
]
};
This is the way im loading both css and js on my html files:
<link
rel="stylesheet"
href="<%=htmlWebpackPlugin.files.chunks.main.css %>"
/>
<script src="<%= htmlWebpackPlugin.files.chunks.main.entry %>"></script>
I have a "scripts.js" js file where I import the files like this:
import "../scss/style.scss";
import "../img/searchBar-icon.png";
import "../img/townHall.png";
import "../img/icon-title.png";
UPDATE:
I have change the way im loading images using the "file-loader" loader:
{
test: /\.(png|jpg|gif)$/,
use: {
loader: "file-loader",
options: {
outputPath: "img/",
name: "[name][hash].[ext]"
}
}
}
Now all of my images are being copied to the "img" folder which is good, problem is that all the names of the files have hashes now (which make sense since I'm telling the loader to add them) and they're not loading on my html files.
Can you try the following for loading the images?
{
test: /\.(jpe?g|png|gif|ico)$/i,
use: ["file-loader?name=[name].[hash].[ext]"]
}

Minify JSON and copy the result to file using Webpack?

I have a couple of language files that I just copy to a location on disk, and I need to continue to do so for now.
The problem is that they're not minified and I would like to do so using WebPack 3.X as this is what we use... :)
Something like https://www.npmjs.com/package/grunt-jsonmin but without the grunt part.
What I have:
Uncompressed JSON in src/lang/*.json
What I want:
Compressed JSON in dist/lang/*.json
/J
This is kind of old, but if anyone is still pondering, here's how I did it:
// npm i -D node-json-minify copy-webpack-plugin
//webpack.config.js
const JSONMinifyPlugin = require('node-json-minify'),
CopyWebpackPlugin = require('copy-webpack-plugin');
options.plugins = [
new CopyWebpackPlugin([
{
/* i18n */
from: path.join(__dirname, 'src', '_locales'),
transform: function(content) {
// minify json
return JSONMinifyPlugin(content.toString());
},
to: path.join(__dirname, 'build', '_locales')
}
])
]
In webpack 5 you can use JsonMinimizerWebpackPlugin.
It works for both rules and CopyPlugin.
const JsonMinimizerPlugin = require("json-minimizer-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
module: {
rules: [
{
test: /\.json$/i,
type: "asset/resource",
},
],
},
plugins: [
new CopyPlugin({
patterns: [
{
context: path.resolve(__dirname, "dist"),
from: "./src/*.json",
},
],
}),
],
optimization: {
minimize: true,
minimizer: [
// For webpack#5 you can use the `...` syntax to extend existing minimizers (i.e. `terser-webpack-plugin`), uncomment the next line
// `...`
new JsonMinimizerPlugin(),
],
},
};

Webpack 3.9.1 - How do I combine LESS files into one CSS file?

I'm very new to Webpack and I'm not certain how to handle LESS. I want to have many LESS files and I want them to compile into one CSS file after I run npm run build. This would result in a style.css file which includes everything.
My webpack.config.js looks like this:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules:
[
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.less$/,
use: [{
loader: "style-loader", // creates style nodes from JS strings
path: path.resolve(__dirname, 'src')
}, {
loader: "css-loader", // translates CSS into CommonJS
path: path.resolve(__dirname, 'src')
}]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
{
test: /\.json$/,
loader: 'json-loader'
}
]
},
plugins: [new HtmlWebpackPlugin()]
};
How exactly do I configure webpack to make it combine all LESS files into one CSS file?
You can use a plugin called extract-text-webpack-plugin to achieve this. According to their documentation, this plugin moves all the required *.css modules in entry chunks into a separate CSS file. So your styles are no longer inlined into the JS bundle, but in a separate CSS file (styles.css). Now of course, in your case, you will first have to parse your .less files to .css and then bundle them up into a single file.
You can modify your webpack config like so:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
},
{
test: /\.less$/,
use: ExtractTextPlugin.extract({ <---- Use the plugin here to extract the styles
fallback: "style-loader",
use: "css-loader"
})
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader']
},
{
test: /\.json$/,
loader: 'json-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin(),
new ExtractTextPlugin("styles.css"),
]};
You can use extract-text-webpack-plugin to make one css file. But only do this for a production build not while you are developing.
I would look at using the Webpack less-loader. It covers a production build here

How can I configure the webpack or typescript that changes are made immediately?

I've implemented webpack so that it generates one file from my angular application. webpack.js
Now the problem is whenever I change the TypeScript file, I'd have to re-run the webpack to see the effect.
That's slowed the development dramatically.
How can I configure the webpack or typescript that changes are made immediately?
webpack.config.js:
const webpack = require('webpack');
module.exports = {
entry: {
app: './app/main.js',
vendor: './app/vendor.js'
},
output: {
//path: './bin',
filename: 'webpack/webpack-[name].js'
},
resolve: {
extensions: ['', '.js', '.ts']
},
devtool: 'source-map',
module: {
loaders: [
{ test: /\.ts$/, loader: 'ts-loader' },
{ test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ },
{ test: /\.css$/, loaders: ['style', 'css'] },
{ test: /\.json/, loaders: ['json-loader'] },
{ test: /\.html/, loaders: ['raw-loader'] },
{ test: /\.(jpg|png|gif)$/, loaders: ['file-loader'] }
]}
// Add minification
, plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
output: {
comments: false
}
})
]
};
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true
}
}
How can I configure the webpack or typescript that changes are made immediately
Actually configure how you run webpack. If you use webpack --watch it automatically updates the bundle as soon as you make a change, but then you still need to refresh the browser page. Even better if you use webpack-dev-server as webpack-dev-server --hot --inline will even reload your browser page immediately.