How to get browser reload when editing html/jade files in webpack - javascript

This is part of the code I have in my webpack.config.js
const common = {
entry: {
style: PATHS.style,
app: PATHS.jsComp
},
output: {
path: PATHS.build,
filename: '[name].js'
},
module: {
loaders: [
{ test: /\.jade$/, loader: "jade" }
]
},
plugins: [
new HtmlWebpackPlugin({
title: 'Webpack demo',
template: PATHS.template, // Load a custom template (ejs by default but can be changed)
inject: 'body' // Inject all scripts into the body (this is the default so you can skip it)
})
]
};
I'm showing you the section where I think the problem is, I don't think you needed the entire code, but it's basically a slightly modified version of this git file
When I run webpack-dev-server everything works. JavaScript and SASS changes do reload the browser but when I change by jade file, the browser doesn't reload. In the terminal I have tried running these variations of webpack-dev-server
webpack-dev-server
webpack-dev-server --inline --hot
webpack-dev-server --inline --hot --colors
webpack-dev-server --inline --hot --colors --content-base app
webpack-dev-server --inline --hot --colors --content-base app --host 0.0.0.0
webpack-dev-server --inline --hot --colors --host 0.0.0.0
None of the above 6 variations get the browser reloading when I made changes to the jade file.
Also, if I remember correctly, after every tutorial I have went through (before finding this setup), the browser never reloaded on html changes.
Is there anything else that I need to install (globaly or otherwise)

According to the documentation, you should do 3 things:
add an entry point to the webpack configuration: webpack/hot/dev-server.
add the new webpack.HotModuleReplacementPlugin() to the webpack configuration.
add hot: true to the webpack-dev-server configuration to enable HMR on the server.
As far as I see, I think the only thing of those 3 that you already did is using the hot: true. I use to run the webpack-dev-server via Gulp, so my configurations stay in a JS object, not in command line arguments.
Try this:
import webpack from 'webpack';
const common = {
entry: {
style: PATHS.style,
app: [
PATHS.jsComp,
'webpack/hot/dev-server', `webpack-dev-server/client?http://localhost:3000`
]
},
output: {
path: PATHS.build,
filename: '[name].js'
},
module: {
loaders: [
{ test: /\.jade$/, loader: "jade" }
]
},
devServer: {
hot: true
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
title: 'Webpack demo',
template: PATHS.template, // Load a custom template (ejs by default but can be changed)
inject: 'body' // Inject all scripts into the body (this is the default so you can skip it)
})
]
};
Edit:
After discussing in the comments, I think that my answer does not address your case. I thought you were trying to reload the application after some Jade module (say, some AngularJS component were using import with jade-loader to load a Javascript template string from a Jade file) were changed. But as it turns out, you are trying to reload when your base HTML (well, Jade, but the base of your page) file is changed.
If you are using some modern Javascript framework (React, Angular etc), chances are your base HTML will be very small, and the real thing happens in Javascript.
Anyway, I don't think that your need is currently supported neither by webpack-dev-server or html-webpack-plugin.

Related

Build index.html with webpack to use with dev server

Im using webpack for running my Three.js application with the following configuration in the webpack.config file:
module.exports = {
entry: `${__dirname}/src/tut15.js`,
output: {
path: __dirname + '/dist',
filename: 'index_bundle.js'
},
devtool: 'inline-source-map',
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 9000
},
plugins: [
new HtmlWebpackPlugin()
]
}
package.json
"scripts": {
"start": "webpack-dev-server --open",
"build": "webpack --config webpack.config.babel.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
With the HtmlWebpackPlugin it autogenerates the html for me. But since I want to create a custom html index file with some new tags this doesnt work for me. So I build the project
npm run-script build
and runs the index.html in the dist folder manually with my applied edits and everything works.
If I remove the HtmlWebpackPlugin from the webpack.config and build the project again and then run:
npm start
livereload works for my js files together with my new index.html with custom tags in the distfolder.
Questions:
It doesnt feels correct to create the changes in the dist folder. How can I generate a index.html straight from source? I guess that might solve all my problems being able to run dev server with a custom index.html
Or is it possible to get some livereload for the build as well?
after I have built my project it generates index.html and index.bundle in my distfolder. If I remove the index.bundle the project works anyway. What exactly does index.bundle do?
What is the best approach or do I need to build my project each time Im doing an update in my index file?
Thanks!
For questions regarding custom index.html and hot-reloading at least.
The plugin has some config you can add for templating.
new HtmlWebPackPlugin({
filename: 'index.html',
template: './public/index.html',
}),

Setting up webpack/HMR for Shopify development

I am trying to setup webpack's dev server and HMR to work with Shopify theme development. When running the server and opening the local IP, I get this error from Shopify's DNS provider, CloudFlare.
How can I properly setup webpack to inject hot changes (css/JS) to my proxied Shopify store (the mystore.myshopify.com url)?
My webpack config as follows:
const path = require("path");
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
module.exports = {
mode: "development",
devServer: {
contentBase: false,
hot: true,
https: true,
proxy: {
"**": {
target: "http://mystore.myshopify.com",
secure: false
}
},
},
entry: "./src/scripts/index.js",
output: {
filename: "./app.js",
path: path.resolve(__dirname, "dist")
},
plugins: [
],
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
// Creates `style` nodes from JS strings
'style-loader',
//postcss here (autoprefixer, babel etc)
// Translates CSS into CommonJS
'css-loader',
// Compiles Sass to CSS
'sass-loader',
],
},
],
},
};
My proposed solution for hot reloading with webpack and shopify.
In your package.json you will want the following scripts
A webpack build script that watches for changes. I have also added a progress parameter so I can see when it updates. This will be watching your /src folder for changes.
"webpack:build": "cross-env NODE_ENV=development webpack --watch --progress",
A shopify theme serve script that uploads the theme files from a /dist folder that is the output of a webpack build.
"shopify:serve": "cd dist && shopify theme serve"
You can link these two scripts together into one using the following.
"deploy:serve": "run-p -sr webpack:build shopify:serve"
So what happens is the webpack build script listens for changes in your /src code. When a change is main it re-builds the output to the /dist folder that shopify theme serve is listening on. When that updates, shopify uploads the changes.
Voila.
Here is the repo for this implementation if you want to play around - https://github.com/Sambuxc/9119-shopify-theme/
As of writing this, my dev versions are:
Node 18.7.0
Npm 8.15.0
Shopify Cli 2.21.0
Good luck and I hope this helps future developers.
Please reach out to me with any further questions if you get stuck.

Webpack - Bundle multiple/different versions of .css files

I would like to make my bundled .css file being generated by Webpack more configurable, so I can output different 'versions' - based on the same .css file - to make the life of developers working on my project in the future easier.
I would like to have the following steps:
Concat of all SCSS into CSS (bundle.css)
Minimize output of step 1 (bundle.min.css)
Embed all images from step 2 (bundle.b64.min.css)
Embed all fonts from step 3 (bundle.bs64.fonts.min.css)
In the end - after my build process -, I would have 4 distinct files in my dist folder. Would that me possible?
The way I'm currently doing it, I run a different script for each step - deletes dist folder, goes through project, produces the output. I would like to have a single script that does all of it at once without having to go through my project 4 times.
I kind of found a solution for it here:
Webpack Extract-Text-Plugin Output Multiple CSS Files (Both Minified and Not Minified)
But, for my specific case, I would have to return 4 different configurations in a array instead of a single object.
Ok so based on our comment conversation i'm gonna give you a workflow of steps 1-4, but with regular assets handling, not a bundling of assets (which i haven't heard of but maybe someone else can elaborate there).
So the steps:
bundle all scss files into 1 bundle.css
make sure this bundle is minified
add assets management to build for images
add assets management to build for fonts
The important things:
This workflow is basically a built by configuration. configuring the npm scripts with the package.json file, and configuring webpack with config.webpack.js. This will allow you to simply run 1 command to build your project: npm run build. note: For simplicity's sake i am going to ignore production/development/etc environments and focus on a single environment.
package.json:
This is used to set up the command that will actually run when you input npm run build in the terminal (from the project dir of course).
since we are avoiding different environments for now and as you are not using Typescript this is a very simple configuraton:
"scripts": {
"build": "webpack",
},
that's all you have to add. It sound's stupid now but when the project will get more complex you are going to like those scripts so better start off making them already.
webpack.config.js:
The major lifting will be made in this configuration file. This basically tells webpack what to do when you run it (which is what npm run build is doing).
first off let's install some plugins:
npm install --save-dev file-loader
npm install --save-dev html-webpack-plugin
npm install --save-dev mini-css-extract-plugin
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'production',
devtool: 'source-map'
entry: './client/src/app.jsx',
output: {
path: path.join(__dirname, 'client/dist/public'),
filename: 'bundle.[hash].js'
},
module: {
rules: [
{
test: /\.s?css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: false
}
},
'css-loader',
'sass-loader'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader']
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
}
]
},
resolve: {
extensions: ['.js', '.json', '.jsx']
},
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: './client/src/index_template.html'
}),
new MiniCssExtractPlugin({
filename: 'style.[hash].css',
chunkFilename: '[id].[hash].css'
}),
]
};
Notice i've added the htmlWebpackPlugin because it makes it easier to reference the correct hashed bundles automatically. Also I've assumed the app is a react app but you can just change the entry point to where your app loads from.
This is quite hard to do of the fly without testing things out, but i hope this gives you enough reference as to what you should change and do to get going with it.
Again i strognly recommend the webpack.js guides and documentation, they are very thorough and once you start getting the hang of it things start working smoothly.

Webpack: How to compile, write on disk and serve static content (js/css) using webpack-dev-server

I want to build my js/css code, write it on disk and serve it using webpack-dev-server in a single command. I don't want to set-up another server for production mode. How do we do it? Sharing my webpack.config.js file content below:
module.exports = {
watch: true,
entry: [
'./src/index.js'
],
output: {
path: __dirname +'/dist/',
publicPath: '/dist/',
filename: 'bundle.js'
},
module: {
loaders: [
{
exclude:/(node_modules)/,
loader: 'babel',
query: {
presets: ['es2015', 'react']
}
}
]
},
devServer: {
historyApiFallback: true,
contentBase: './'
}
};
Please find the start script used in package.json below:
"start": "webpack-dev-server --progress --colors"
I am running "npm run start". Please help.
New webpack-dev-server is released, and it supports writeToDisk option.
devServer: {
writeToDisk: true
}
With webpack-dev-server v4.0.0+, devMiddleware is used:
devServer: {
devMiddleware: {
writeToDisk: true
}
}
webpack-dev-server uses a "virtual" Express server in conjunction with Sock.js to emulate a server running on your machine. Regarding compilation, webpack-dev-server does recompile the bundle whenever it detects code changes. This recompilation is served from memory, however, as opposed to the project's build directory (or, in your case, the dist directory). From the docs:
Using this configuration, webpack-dev-server will serve the static files in your build folder. It’ll watch your source files, and recompile the bundle whenever they are changed.
Regarding writing to your disk, webpack-dev-server does not do this. This is partially addressed by what's been written above. Additionally, note the following, also from the Webpack docs:
This modified bundle is served from memory at the relative path specified in publicPath (see API). It will not be written to your configured output directory. Where a bundle already exists at the same URL path, the bundle in memory takes precedence (by default).
To write to your disk, use the ordinary webpack module. Of course, as your question hints at, manual recompilation after every change is tedious. To address that chore, include the watch flag. From the Terminal, you could execute the command:
$ webpack --watch
I prefer to delegate this to an NPM script, however. Note that the -w flag below is equivalent to writing --watch.
// NPM `scripts` field:
"watch": "webpack -w"
If you want to run webpack-dev-server while also having your changes get recompiled and written to your output directory, you can add an additional NPM script like so:
"scripts": {
"serve": "npm run watch && npm run start",
"start": "webpack-dev-server --progress --colors",
"watch": "webpack -w"
}
Then, in your Terminal, just execute $ npm run serve to accomplish this.
If you're interested in the added convenience of automatic reload, you can do so by defining the following within the plugins field of your Webpack config file:
new webpack.HotModuleReplacementPlugin()
Note: This will likely require additional configuration settings for Babel. If I were you, I would take out the query field from your babel loader and, instead, delegate your Babel configuration to an external .babelrc file. A good one to use that is compatible with hot reloading might look like this:
{
"presets": ["env", "es2015", "react"],
"plugins": ["react-hot-loader/babel"]
}
On a side note, I've created a boilerplate repo for easily starting out projects with my desired structure. The Webpack configuration may of interest to, specifically. In particular, it employs Webpack 2 and includes other build tools like Babel (for transpilation), ESLint (syntax checker) as well as support for CSS/Sass and a variety of other file formats.
You can change your start script definition to this:
"start": "webpack --watch & webpack-dev-server --inline --progress --colors".
This sends the webpack watch-and-rebuild process to the background so that you can also hot-reload your modified modules as you change them with webpack-dev-server.
EDIT:
Either of these plugins may do what you want:
https://github.com/gajus/write-file-webpack-plugin
https://github.com/FormidableLabs/webpack-disk-plugin
webpack-dev-server serve files from memory, you can replace webpack-dev-server with webpack-simple-serve, it use webpack's watch feature, write the compiled files to disk and use serve-handler to serve.

webpack-dev-server hot reload not working

My file structure is:
dist
css
style.css
index.html
js
bundle.js
src
css
style.css
index.html
js
main.js
node_modules
webpack.config.js
package.json
My webpack.config.js looks like:
module.exports = {
entry: './src/js/main.js',
output: {
path: __dirname,
filename: './dist/js/bundle.js'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /(node_modules)/,
loader: 'babel',
query: {
presets: ['es2015']
}
},
{
test: /\.vue$/,
loader: 'vue'
}
]
}
};
I run:
webpack-dev-server --content-base dist --hot
And it builds and seems like it's working. localhost:8080 shows the expected result but hot-reload does just not work. When I change a file I can see in terminal that a rebuild is happening but nothing happens in the browser. Am I missing something in the config?
What worked for me is to write <script src="bundle.js"> and not <script src="dist/bundle.js"> in my index.html file.
// index.html
<script src="bundle.js"></script> // works
<script src="dist/bundle.js"></script> // doesn't work!
Keeping dist/bundle.js as the output file works perfectly fine if you just build it using webpack. But when using webpack-dev-server, the static file already in the file system continues to be served, and not the latest hot replacement. It seems webpack-dev-server gets confused when it sees dist/bundle.js in the html file and doesn't hot replace it, even though webpack.config.js is configured to that path.
When using webpack-dev-server, it builds all files internally and does not spit them out into your output path. Running webpack alone, without the dev server, does the actual compilation to disk. The dev server does everything in memory which speeds up re-compilation by a lot.
To fix your hot reload issue, set the content base to your source directory and enable inline-mode
Like so:
webpack-dev-server --content-base src --hot --inline
None of the options on this page worked for me. After changing the devServer section to:
devServer: {
port: 8080,
contentBase: ['./src', './public'], // both src and output dirs
inline: true,
hot: true
},
it worked.
For Webpack ^5.72.1
This worked for me,
devServer: {
port: 3000,
hot: false,
liveReload: true,
},
Note: liveReload will reload the whole application on file save but it will lose application state. Hot reloading preserves state. But liveReload seemed to fix the issue for me with css/html not loading on the browser after save, without having to refresh the browser.
--inline --hot wasn't an issue for me
If you are using redux can try this.
For some random reason redux-devtools was not allowing hot reload for me. Try removing it from root component and redux compose config.
Note: Use redux devtool browser extension with this config in your store configuration: window.devToolsExtension ? window.devToolsExtension() : f => f
Also, must read: https://medium.com/#rajaraodv/webpacks-hmr-react-hot-loader-the-missing-manual-232336dc0d96#.ejpsmve8f
Or try hot reload 3:
example: https://github.com/gaearon/redux-devtools/commit/64f58b7010a1b2a71ad16716eb37ac1031f93915
Webpack hot reloading stopped working for me as well. The solution for me was to delete the node_modules folder and fresh install all dependencies.
Just open the parent folder of node_modules in your terminal and run npm install
100% Working Solution
You have to just follow 3 steps and you will get your hot reloading as you expected
Include "publicPath" key in "Output" property of webpack config. "publicPath" should contain path to your bundle.js file so that dev-server will know if there is any change in your bundle.js file and it will reload your application.
Your config should look like this -
output: {
path: __dirname,
publicPath:"/dist/js/",
filename: './dist/js/bundle.js'
}
Add "devServer" option in config file -
devServer:{
contentBase:"/src/",
inline:true,
stats:"errors-only"
}
Please note that contentBase should point to the path where you put your index.html file which contain your script tag in your case it will be "/src/"
At last you have to make sure 'src' attribute of your 'script' tag in index.html points to bundle.js starting from "http://localhost:port" as follow -
<script src="http://localhost:portnumber + value in publicPath + bundle.js"></script>
in your case it will look like this -
<script src="http://localhost:8080/js/dist/bundle.js" type="text/javascript"></script>
And finally remember webpack-dev-server doesn't compile your js file or make build or watch on your js file it dose everything in memory to watch on your js file you have to run
webpack --watch
in seprate window
The only thing that works for me is apply the "hotOnly" inside the configuration of the "devServer" (on the "webpack.config.js"), like this:
devServer: {
hotOnly: true,
},
After reload the "Webpack Dev Server", the "Hot Reload" works, at least, after saving any change in CSS or JS files.
All those who suffer: don’t forget slash before public path:
publicPath:’/assets/scripts/‘ not publicPath:’assets/scripts/’
Three days lost because of 1 forward slash in the path string
Try this:
In your package.json file, delete the line that contains "test" "echo \"Error: no test specified\" && exit 1" under the scripts object, and replace it with:
...
"scripts": {
"start": "webpack-dev-server --hot"
},
...
Then to restart your project, just use npm start.
This worked for me when I ran into this problem.
Edit: Can you share your package.json file?
Try adding this to webpack.config.js as well
devServer: {
inline: true,
port: 3000,
hot: true
},
Check your console logs if it has below error then add cors to your webpack dev server file
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin react hot reload
Ideally add below entry in you dev server js
headers: { "Access-Control-Allow-Origin": "*" },
I increased the max number of file changes that can be watched and it worked for me. I guess the issue for me was too many files.
echo fs.inotify.max_user_watches=1999999 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
source
You can try adding this to your config:
module.exports = {
...
devServer: {
contentBase: './dist/', // Since your index.html is in the "dist" dir
open: true, // Automatically open the browser
hot: true, // Automatically refresh the page whenever bundle.js changes
// (You will have to refresh manually if other files change)
},
...
};
And then running (no options):
webpack-dev-server
With the above settings, while using webpack-dev-server for static page building I add bundle js or whatever js file configured as output to the html page. This way I get refresh on my static page after any changes.
For webpack version 5, the module.loaders is now module.rules. And for the presets change query to options.
Make sure in development mode you are not using a plugin that extract css into files, example MiniCssExtractPlugin. It messes the things up.

Categories