Skip to content
This repository was archived by the owner on May 29, 2019. It is now read-only.

Unable to HMR (Hot Module Replacement) css/scss with Webpack 2.2.0 and webpack-dev-server 2.2.1 #384

Closed
Rob-Leggett opened this issue Jan 31, 2017 · 21 comments

Comments

@Rob-Leggett
Copy link

Versions

"extract-text-webpack-plugin": "^2.0.0-rc.2",
"webpack": "^2.2.0",
"webpack-dev-server": "^2.2.1"

Issue

"extract-text-webpack-plugin": "^1.0.1",
"webpack": "^1.14.0",
"webpack-dev-server": "^1.16.2"

No longer able to HMR css/scss since upgrading to version 2, changing the styles triggers a change (see output sample below) but I have to manually refresh the page to see the changes the page does not auto refresh, also if I make a change to a js file after changing a scss file the changes are then reflected as the js change trigger a HMR which also includes the style changes, but only changing the styles with no js changes requires a manual page refresh.

Command running:

npm run dev

"scripts": {
    "dev": "webpack-dev-server --hot --inline"
  }

Configuration before upgrade:

const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

const BUILD_DIR = path.resolve(__dirname, 'public');
const APP_DIR = path.resolve(__dirname, 'app');

let generateHtml = new HtmlWebpackPlugin({ title: 'My App' });
let extractCSS = new ExtractTextPlugin('styles/[name].css', { allChunks: true });

const config = {
  entry: APP_DIR + '/index.js',
  output: {
    path: BUILD_DIR,
    filename: 'bundle.js'
  },
  externals: {
    'cheerio': 'window',
    'react/lib/ExecutionEnvironment': true,
    'react/lib/ReactContext': true,
  },
  module : {
    loaders : [
      {
        test : /\.jsx?/,
        include : APP_DIR,
        loader : 'babel'
      },
      {
        test: /\.scss$/,
        loader: extractCSS.extract('style', 'css?modules=true!sass?sourceMap=true')
      }
    ]
  },
  plugins: [
    generateHtml,
    extractCSS
  ]
};

module.exports = config;

Configuration after upgrade:

const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

const BUILD_DIR = path.resolve(__dirname, 'public');
const APP_DIR = path.resolve(__dirname, 'app');

let generateHtml = new HtmlWebpackPlugin({ title: 'My App' });
let extractCSS = new ExtractTextPlugin({ filename: 'styles/[name].css', allChunks: true });

const config = {
  entry: APP_DIR + '/index.js',
  output: {
    path: BUILD_DIR,
    filename: 'bundle.js'
  },
  externals: {
    'cheerio': 'window',
    'react/lib/ExecutionEnvironment': true,
    'react/lib/ReactContext': true,
  },
  module : {
    loaders : [
      {
        test : /\.(js|jsx)?/,
        include : APP_DIR,
        loader : 'babel-loader'
      },
      {
        test: /\.scss$/,
        loader: extractCSS.extract({
          fallbackLoader: 'style-loader',
          loader: ['css-loader?modules', 'sass-loader']
        })
      }
    ]
  },
  plugins: [
    generateHtml,
    extractCSS
  ]
};

module.exports = config;

Output sample initial page load.

> webpack-dev-server --hot --inline

Project is running at http://localhost:8080/
webpack output is served from /
Hash: 0e873f689fcea2b7cee6
Version: webpack 2.2.0
Time: 3350ms
          Asset       Size  Chunks                    Chunk Names
      bundle.js     1.1 MB       0  [emitted]  [big]  main
styles/main.css  634 bytes       0  [emitted]         main
     index.html  223 bytes          [emitted]         
chunk    {0} bundle.js, styles/main.css (main) 1.03 MB [entry] [rendered]
   [19] ./~/react/react.js 56 bytes {0} [built]
   [45] ./~/redux/es/index.js 1.08 kB {0} [built]
  [106] ./~/react-redux/es/index.js 194 bytes {0} [built]
  [129] (webpack)/hot/emitter.js 77 bytes {0} [built]
  [130] ./app/index.js 938 bytes {0} [built]
  [131] (webpack)-dev-server/client?http://localhost:8080 4.66 kB {0} [built]
  [132] (webpack)/hot/dev-server.js 1.57 kB {0} [built]
  [139] ./app/containers/App.js 4.25 kB {0} [built]
  [178] ./~/react-dom/index.js 59 bytes {0} [built]
  [269] ./~/redux-thunk/lib/index.js 529 bytes {0} [built]
  [300] ./~/strip-ansi/index.js 161 bytes {0} [built]
  [305] ./~/url/url.js 23.3 kB {0} [built]
  [307] (webpack)-dev-server/client/socket.js 856 bytes {0} [built]
  [309] (webpack)/hot/log-apply-result.js 1.02 kB {0} [built]
  [310] multi (webpack)-dev-server/client?http://localhost:8080 webpack/hot/dev-server ./app/index.js 52 bytes {0} [built]
     + 296 hidden modules
Child html-webpack-plugin for "index.html":
    chunk    {0} index.html 541 kB [entry] [rendered]
        [0] ./~/lodash/lodash.js 540 kB {0} [built]
        [1] (webpack)/buildin/global.js 509 bytes {0} [built]
        [2] (webpack)/buildin/module.js 517 bytes {0} [built]
        [3] ./~/html-webpack-plugin/lib/loader.js!./~/html-webpack-plugin/default_index.ejs 540 bytes {0} [built]
Child extract-text-webpack-plugin:
    chunk    {0} extract-text-webpack-plugin-output-filename 1.77 kB [entry] [rendered]
        [0] ./~/css-loader/lib/css-base.js 1.51 kB {0} [built]
        [1] ./~/css-loader?modules!./~/sass-loader!./app/components/user/users.scss 267 bytes {0} [built]
Child extract-text-webpack-plugin:
    chunk    {0} extract-text-webpack-plugin-output-filename 1.81 kB [entry] [rendered]
        [0] ./~/css-loader/lib/css-base.js 1.51 kB {0} [built]
        [1] ./~/css-loader?modules!./~/sass-loader!./app/containers/app.scss 307 bytes {0} [built]
Child extract-text-webpack-plugin:
    chunk    {0} extract-text-webpack-plugin-output-filename 2.21 kB [entry] [rendered]
        [0] ./~/css-loader/lib/css-base.js 1.51 kB {0} [built]
        [1] ./~/css-loader?modules!./~/sass-loader!./app/components/navbar/navbar.scss 702 bytes {0} [built]
Child extract-text-webpack-plugin:
    chunk    {0} extract-text-webpack-plugin-output-filename 1.87 kB [entry] [rendered]
        [0] ./~/css-loader/lib/css-base.js 1.51 kB {0} [built]
        [1] ./~/css-loader?modules!./~/sass-loader!./app/components/common/common.scss 361 bytes {0} [built]
webpack: bundle is now VALID.

Output sample after scss change.

webpack: bundle is now INVALID.
Hash: f16b1beda9083db91735
Version: webpack 2.2.0
Time: 251ms
                               Asset       Size  Chunks                    Chunk Names
                           bundle.js     1.1 MB       0  [emitted]  [big]  main
0e873f689fcea2b7cee6.hot-update.json   35 bytes          [emitted]         
                     styles/main.css  626 bytes       0  [emitted]         main
chunk    {0} bundle.js, styles/main.css (main) 1.03 MB [entry] [rendered]
  [143] ./app/components/navbar/navbar.scss 181 bytes {0} [built]
     + 310 hidden modules
Child html-webpack-plugin for "index.html":
    chunk    {0} index.html 541 kB [entry]
         + 4 hidden modules
Child extract-text-webpack-plugin:
    chunk    {0} extract-text-webpack-plugin-output-filename 2.2 kB [entry] [rendered]
        [1] ./~/css-loader?modules!./~/sass-loader!./app/components/navbar/navbar.scss 694 bytes {0} [built]
         + 1 hidden modules
webpack: bundle is now VALID.

You can see the size of the main.css changed, but the page never refreshed until I pressed f5

@Rob-Leggett
Copy link
Author

Rob-Leggett commented Jan 31, 2017

@Rob-Leggett Rob-Leggett changed the title Unable to HMR (Hot Module Reload) css/scss with Webpack 2.2.0 and webpack-dev-server 2.2.1 Unable to HMR (Hot Module Replacement) css/scss with Webpack 2.2.0 and webpack-dev-server 2.2.1 Jan 31, 2017
@sajidali
Copy link

As stated in the github main page of this plugin:
Caveats: "No Hot Module Replacement"

You should not use this plugin while development, it is still useful for creating build for production.
You can create two webpack config files, one for dev and one for prod, that might help for both scenarios.

@Rob-Leggett
Copy link
Author

Fair point but I am confused as to why using version 1 on the library I was getting hot module replacement but version 2 of the library it is not available/working?

@sajidali
Copy link

Even in version 1, extract-text-webpack-plugin don't support HMR.
https://github.com/webpack-contrib/extract-text-webpack-plugin/blob/webpack-1/README.md
you can clearly see in above documentation page for v1 page,

Caveats: "No Hot Module Replacement"

@loilo
Copy link

loilo commented Feb 1, 2017

I've had my own very simple way of HMR with webpack 1 based on the chunk.rendered flag using webpack's watch mode. This flag is now (falsely) set to false all the time.

Is this already part fo HMR? I guess webpack's basic asset watching should work anyway—or am I missing something important?

@Rob-Leggett
Copy link
Author

Rob-Leggett commented Feb 1, 2017

While the documentation states Caveats: "No Hot Module Replacement", the documentation and behaviour do not match.

Checkout the following repo and commit to see HMR working perfectly with version 1, when you have the client running try and change a scss style to see it recompile the css and refreshing the browser to automatically see the styling change.

Repo: https://github.com/Rob-Leggett/react_redux_webpack
Commit: 0d976fa734e6b8d197fe1bee58cd4ed974985854

This all stop working in the next commit, when I upgraded to version 2.

@bebraw
Copy link
Contributor

bebraw commented Feb 2, 2017

The internal API changed in webpack 2. We would welcome a PR adding HMR support, but it's not simply supported at the moment. It's better to have development specific configuration (multiple ways to do that) and it's faster too that way.

There was some initial effort at #89 if you are interested in working on this.

@bebraw bebraw closed this as completed Feb 2, 2017
@zxbe
Copy link

zxbe commented Feb 2, 2017

The 'hot-update.js' file:

webpackHotUpdate(0,{

/***/ "./components/App.css":
/***/ (function(module, exports) {

eval("// removed by extract-text-webpack-plugin\nmodule.exports = {\"app\":\"App__app-26iGG\",\"h2\":\"App__h2-o5GaB\",\"webpack\":\"App__webpack-1iiUZ\"};//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW...joiIn0=");

/***/ })

})

The bowser will reflush , but the method is return null. So the styles is not change.

@sajidali
Copy link

sajidali commented Feb 3, 2017

Can you try this
https://github.com/shepherdwind/css-hot-loader
Give your feedback if it works.

@wshicheng
Copy link

@sajidali,I've been trying to use your suggetion, but it doesn't work

@wshicheng
Copy link

@Rob-Leggett ,hi, i also encountered the same problem with you! if you find the solution,I hope you can also the solution send me , my email address is wshicheng@outlook.com ! thanks a lot

@indreklasn
Copy link

@sajidali This package works wonderfully!

Example of working HMR with styles and javascript.

{
  test: /\.scss$/, // files ending with .scss
  use: ['css-hot-loader'].concat(ExtractTextWebpackPlugin.extract({
    fallback: 'style-loader',
    use: ['css-loader', 'sass-loader'],
  })),
},

@iuliaL
Copy link

iuliaL commented May 30, 2017

@sajidali Great job!

Here my fully working webpack.config.js with Sass compiling and reloading instantly ;)

const config = {
	entry: './app/index.js',
	module: {
		rules: [
			{
				test: /(\.css|\.sass)$/,
				exclude: /node_modules/,
				use: ['css-hot-loader'].concat(ExtractTextPlugin.extract({
					fallback: 'style-loader',
					// Could also be write as follow:
					// use: 'css-loader?modules&importLoader=2&sourceMap&localIdentName=[name]__[local]___[hash:base64:5]!sass-loader'
					use: [
						{
							loader: 'css-loader',
							query: {
								modules: true,
								sourceMap: true,
								importLoaders: 2,
								localIdentName: '[name]__[local]___[hash:base64:5]'
							}
						},
						{
							loader : 'sass-loader',
							options: {
								sourceMap: true
							}
						},
						{
							loader : 'postcss-loader',
							options: {
								plugins: function () {
									return [
										require("autoprefixer")
									];
								}
							}
						}
					]
				})),
			},
			{
				test: /\.(js)$/,
				exclude: /(node_modules|bower_components)/,
				use : ['babel-loader']
			}
		]
	},
	devtool: 'source-map',
	output: {
		path: path.resolve(__dirname, 'dist'),
		filename: 'bundle.js',
		publicPath: '/' // avoid requesting server route instead of client route when hitting refresh /Cannot GET /route
	},
	plugins : [
		new HtmlWebpackPlugin({
			template: 'app/index.html'
		}),
		new ExtractTextPlugin({ filename: 'css/style.css', disable: false, allChunks: true }), // this means dist/css/style.css
	]
		
	
};


if(process.env.NODE_ENV === "production"){ // 'production ready'
	config.plugins.push(
		new webpack.DefinePlugin({
			'process.env' : {
				'NODE_ENV' : JSON.stringify(process.env.NODE_ENV)
			}
		}),
		new webpack.optimize.UglifyJsPlugin({ sourceMap: true, minimize: true })
	)
}

@Oscar-ren
Copy link

@sajidali thanks! it does work

this loader don't refresh browser, don't be confused

@SerhiiSerdiuk
Copy link

SerhiiSerdiuk commented Jun 11, 2017

In my case, the plugin "extract-text-webpack-plugin" began to work with hot reload after I deleted the bracket characters in the name of the project folder and replaced the spaces with "_".
For example, the project directory was named "Project (new)", I replaced it with "Project_new".

@ziyu-93
Copy link

ziyu-93 commented Jun 26, 2017

@iuliaL Thank you solved the problem。love you

@chenjun1127
Copy link

chenjun1127 commented Aug 18, 2017

Thanks,this is good!

@ghost
Copy link

ghost commented Oct 9, 2017

@Oscar-ren Is it possible to make this solution refresh the browser?

I tried browsersync and that works. But I'm wondering if this works wit webpack-dev-server as well. This would be a cleaner solution.

@Oscar-ren
Copy link

@katiasmet I run the webpack-dev-server and webpack -w, css-hot-loader could upload the extract css file , but webpack-dev-server doesn't receive this change, I think there will be have some methods to notice webpack-dev-server, reopen a webpack progress is a temp scheme.

@ghost
Copy link

ghost commented Oct 10, 2017

@Oscar-ren Ok so you have the same problem as me, but couldn't find a solution yet?

Does anybody know how you can hot load sass changes? With or without the extract text webpack plugin?

@sheerun
Copy link

sheerun commented Dec 9, 2017

I've created https://github.com/sheerun/extracted-loader for this use case with no configuration.

config.module.rules.push({
  test: /\.css$/,
  use: ['extracted-loader'].concat(ExtractTextPlugin.extract({
    /* Your configuration here */
  }))
})

config.plugins.push(new ExtractTextPlugin('index.css'))

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests