53

I am using webpack-dev-server for development with html-webpack-plugin to generated the index.html with revision sources. The thing is every time I change the index.html the bundle system will not rebuild again. I know the index is not in the entry, but is there a way to solve this?

hjl
  • 2,642
  • 2
  • 14
  • 25
  • 1
    Did my solution resolve your issue? I'd love to know if you've found some other way of doing this. – Gabriel Kunkel Dec 08 '15 at 23:21
  • I'm in the same boat.. I'm trying hard to avoid two different index.html, one for production and one for development, referencing different assets.. – Spock Jan 11 '16 at 22:20
  • 1
    @Spock See my answer below. You can require your template in your entry point. Every time you change your template, the dev-server should update. – Gabriel Kunkel Jan 25 '16 at 17:54

4 Answers4

48

The problem is that index.html is not being watched by Webpack. It only watches those files that are "required" or "imported" somewhere in your code and the loaders are testing for.

The solution has two parts.

First require the index.html file in your entry point. Technically, you can require it anywhere in your application, but this is pretty convenient. I'm sure you could also just require your template if you were using a template with your html-webpack-plugin.

I required my index.html in my index.js file, which is my entry point:

require('./index.html')
const angular = require('angular')
const app = angular.module('app', [])
//...so on and so forth

Finally, install and add the raw-loader with all of your other loaders, to your Webpack config file. Thus:

{
   test: /\.html$/,
   loader: "raw-loader"
}

The raw loader will convert just about any file that is "required" into a string of text and, then, Webpack will watch it for you and refresh the dev-server every time you make a change.

Neither Webpack, itself, nor your program will actually do anything with the index.html file (or template) at the stage in which it is loaded. It's completely unnecessary for your production or testing environments, so just for good measure, I only add it if I'm running the development server:

/* eslint no-undef: 0 */

if (process.env.NODE_ENV === 'development') {
  require('./index.html')
}

const angular = require('angular')
const app = angular.module('app', [])
//...so on and so forth

In theory you can "require in" a bunch of other static html files you'd like it to watch. ...or text files for that matter. I use the raw-loader, myself, for Angular directive templates, but I don't have to add those to the beginning of my entry point. I can just require inside the directive template property, like this:

module.exports = function(app) {
  app.directive('myDirective', function(aListItem) {
    return {
      template: require('./myTemplate.html'),
      restrict: 'E',
      controller: function($scope) {
        $scope.someThingThatGoesInMyTemplate = 'I love raw-loader!'
      }
    }
  })
}
Gabriel Kunkel
  • 2,211
  • 3
  • 20
  • 35
  • Jesus, how time flies! I'm sorry I didn't get back to this. This is great, works beautifully! – Spock Jan 26 '16 at 10:13
  • i'm confused about getting the status of process.env here. is this being run server side? using that code snippet in my index.js doesn't work. there's no recognition of that variable and it's undefined since it's client side, i guess. can you clarify how you make this work? – spb Mar 08 '16 at 21:34
  • @spb Sorry about that. That can be frustrating. I didn't mean for my example to be copy and paste. process.env.NODE_ENV can be set when you might run webpack from the command line. I just prepend "NODE_ENV=development" or "NODE_ENV=production" to my webpack command (or webpack-dev-sever command, depending on what I'm going to run). Then I can elicit that setting from within my code using "process.env.NODE_ENV". This gives further explanation if needed: http://stackoverflow.com/questions/9198310/how-to-set-node-env-to-production-development-in-os-x – Gabriel Kunkel Mar 08 '16 at 21:49
  • @GabrielKunkel, thanks for the reply. I did those steps all (setting on the command line, and running webpack, etc), but when I try to read in the updated NODE_ENV in my entrypoint file (index.js) it comes back as undefined, presumably because it's not accessible from where I try to use it. So i guess I don't understand when you say "from within your code"... which part, if can you speak to that. is this within your sever-side code? thanks so much – spb Mar 08 '16 at 22:01
  • @spb This all happens with "server-side code" in that it all runs in node.js. Webpack runs in node.js. "From within my code," just means that I can use it in a way similar to how it's used in the example. I can check what value is being held (process.env.NODE_ENV === 'development') and run parts of the code depending on whether that bool check comes back true or false using if-else statements, for example. Your issues seem to be more grand than this question. I recommend posting a new question that includes your webpack.config.js + file structure details + how you're running webpack. goodluck! – Gabriel Kunkel Mar 08 '16 at 22:15
  • 1
    nah, it's not that serious. it just looks like you used that process.env evaluation inside of an angular file, but presumably it was handled maybe in your webpack config or something? something running on node, is i guess the bottom line. in any case, i got what i immediately needed working using your raw-loader tip, and that's sufficient. so thanks for that. :) – spb Mar 08 '16 at 23:23
  • 2
    @spb I think you need to use the `DefinePlugin` webpack plugin in order to use environment variables in your front-end javascript code. Something like: `new webpack.DefinePlugin({ NODE_ENV: JSON.stringify(process.env.NODE_ENV) })` and then in your `app.js`: `if (NODE_ENV === 'development') { ... }` But maybe @GabrielKunkel can be a bit more specific how they are using `process.env.VARIABLE` in front-end code... – adam-beck Mar 25 '16 at 12:55
  • Although the solution described above is indeed correct; I've spent several days trying to get it to work only to find out this solution ONLY works if you've setup the HtmlWebpackHarddiskPlugin in combination with HtmlWebpackPlugin. - Adding comment on behalf of a low-rep user who cannot add comment. – Tushar Nov 30 '16 at 03:03
  • I'm trying this but it's failing. Webpack says it doesnt accept index.html and need to do a full reload :( – pailhead Dec 23 '16 at 00:06
  • @pailhead Haven't had that reaction from Webpack, myself. I recommend creating a new question with some more details/screenshots with a reference to this question. raw-loader should just include anything as raw text. Does raw-loader work with other files in your project or other contexts for you? – Gabriel Kunkel Dec 24 '16 at 00:54
42

Simply add watchContentBase: true to your devServer's config. webpack-dev-server will watch for changes in all files that are located in contentBase dir. Here we watch all files inside ./src

webpack.config.js:

...
 devServer: {
   port: 8080,
   contentBase: './src',
   watchContentBase: true

} 
SuperDJ
  • 6,224
  • 7
  • 36
  • 62
B. Laskowski
  • 431
  • 5
  • 3
  • I've been searching around for far too long to find a simple solution to watch my html / twig (templates) directory and simply reload the page when those change. I'm using webpack & dev-server for a Non-SPA site (Craft CMS). All I had to do was change my `contentBase` to `'./templates'` . A simple solution that was right in the docs the whole time, but didn't pickup on the use-case for. Thank you for this answer! – Chase Giunta Dec 03 '17 at 16:53
  • 5
    How simple. This I think should be the accepted answer. –  Mar 23 '18 at 22:22
  • 1
    I would upvote this twenty times if I could! So much simpler than needlessly processing my HTML through some webpack plugin just to get auto-reload. – David Jun 02 '19 at 10:39
3

If you are building it using just npx webpack --watch, you can set cache to false to generate the file everytime.

new HtmlWebpackPlugin({
  cache: false,
})

Read this link for further customisation, htmlwebpackplugin.

Cloverr
  • 176
  • 9
1

Another solution is to use file-loader to import html file at the entry javascript file.

import 'file-loader!../templates/index.html';

You can have your html-webpack-plugin configuration as usual

plugins: [
 new HtmlWebPackPlugin({
  template: path.resolve(__dirname, 'src/templates/index.html'),
  filename: path.resolve(__dirname, 'dist/index.html'),
  files: {
   css: ['style.css'],
   js: ['main.js'],
  }
 })
]

This does not write anything to the disc when webpack-dev-server is running

ibex
  • 838
  • 7
  • 16