Description
It'd be great to have at least some sort of description for making HMR work. Let me share what I did. Any criticism and suggestions are welcome.
tl;dr
diff --git a/config/webpack/development.js b/config/webpack/development.js
index d98ec5b..53812f7 100644
--- a/config/webpack/development.js
+++ b/config/webpack/development.js
@@ -1,5 +1,6 @@
// Note: You must restart bin/webpack-watcher for changes to take effect
+const webpack = require('webpack')
const merge = require('webpack-merge')
const sharedConfig = require('./shared.js')
@@ -12,5 +13,9 @@ module.exports = merge(sharedConfig, {
output: {
pathinfo: true
- }
+ },
+
+ plugins: [
+ new webpack.HotModuleReplacementPlugin()
+ ],
})
diff --git a/config/webpack/development.server.js b/config/webpack/development.server.js
index fe840c6..e0d95fd 100644
--- a/config/webpack/development.server.js
+++ b/config/webpack/development.server.js
@@ -12,6 +12,8 @@ module.exports = merge(devConfig, {
compress: true,
historyApiFallback: true,
contentBase: resolve(paths.output, paths.entry),
- publicPath
+ publicPath,
+ hot: true,
+ headers: {'Access-Control-Allow-Origin': '*'}
}
})
diff --git a/config/webpack/loaders/sass.js b/config/webpack/loaders/sass.js
index cdc714f..d5d4764 100644
--- a/config/webpack/loaders/sass.js
+++ b/config/webpack/loaders/sass.js
@@ -2,8 +2,8 @@ const ExtractTextPlugin = require('extract-text-webpack-plugin')
module.exports = {
test: /\.(scss|sass|css)$/i,
- use: ExtractTextPlugin.extract({
+ use: ['css-hot-loader'].concat(ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'postcss-loader', 'sass-loader'],
- }),
+ })),
}
diff --git a/config/webpack/shared.js b/config/webpack/shared.js
index ef5fa74..2ea6e62 100644
--- a/config/webpack/shared.js
+++ b/config/webpack/shared.js
@@ -23,7 +23,7 @@ module.exports = {
}, {}
),
- output: { filename: '[name].js', path: resolve(paths.output, paths.entry) },
+ output: { filename: '[name].js', path: resolve(paths.output, paths.entry), publicPath },
module: {
rules: readdirSync(loadersDir).map(file => (
diff --git a/package.json b/package.json
index dcbdec9..f46a81b 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
"coffee-script": "^1.12.5",
"compression-webpack-plugin": "^0.4.0",
"cookies-js": "^1.2.3",
+ "css-hot-loader": "^1.2.0",
"css-loader": "^0.28.0",
"eonasdan-bootstrap-datetimepicker": "^4.17.47",
"extract-text-webpack-plugin": "^2.1.0",
detailed explanation
According to webpack
's documentation I just need to add new webpack.HotModuleReplacementPlugin()
to plugins
section (development.js
) and run webpack-dev-server
with --hot
switch (development.server.js
). But with that you see that HMR doesn't work properly. The whole page gets reloaded (HMR messages in console disappear).
Then you add --hot-only
switch (development.server.js
) for webpack-dev-server
to not fall back to live reload. And see that it can't find hot-update.json
file, whatever that may be:
GET http://localhost:3000/40293e2cd0bae6910c2e.hot-update.json 404 (Not Found)
That happens since it's asking for it your rails
app (localhost:3000
), not webpack-dev-server
(localhost:8080
). And the reason for that is, output.publicPath
option is not set. It's set for webpack-dev-server
, but not for webpack
itself.
The error gets triggered here. Since $require$.p
is empty string. And $require$.p
is empty because it's basically output.publicPath
option.
So, we add output.publicPath
and the next thing you see is webpack-dev-server
asking you to allow your rails
app access to webpack-dev-server
:
XMLHttpRequest cannot load http://localhost:8080/9b1e70204c19ca0472e5.hot-update.json. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
You add it to development.server.js
(headers: {'Access-Control-Allow-Origin': 'http://localhost:3000'}
), and check again. This time your site doesn't see your updates:
[HMR] Checking for updates on the server...
[HMR] Nothing hot updated.
And that has to do with extract-text-webpack-pluging
not meant to be used in development. So, you disable it (new ExtractTextPlugin({disable: env.NODE_ENV != 'production', filename: ...
). Or this way. And now it sort of works, but you see:
in console. That's because <%= stylesheet_pack_tag 'application' %>
in layout still tries to find extracted css file. But we no longer extract it in development env. And thus you end up with:
<%= stylesheet_pack_tag 'application' unless Rails.env.development? %>
The one improvement you can make here is make use of css-hot-loader
package. It allows not to disable extract-text-webpack-plugin
in development environment.