Hot reload on vue-loader only works with structural changes to the template
Asked Answered
T

1

6

I've setup vue + vue-loader + HMR on an existing project.

It works mostly well, vue components are loaded and rendered correctly.

The hot module reload part is configured and loading.

However, it doesn't seem to apply updates when the change is only a text node of the component.

For example, if I have a component like this:

<template lang="html">
  <div>
    <h1>I'm a Component</h1>
  </div>
</template>

<script>
export default {
}
</script>

And I change it to this:

<template lang="html">
  <div>
    <h1>I'm a Component updated</h1>
  </div>
</template>

<script>
export default {
}
</script>

Then I can see the HMR updates in the browser console.

console output

But the component doesn't update, it still says "I'm a Component".

However, if I slightly alter the html structure of the component like this:

<template lang="html">
  <div>
    <h1>I'm a Component updated</h1>
    <p>do it</p>
  </div>
</template>

<script>
export default {
}
</script>

Then the console shows the HMR log but this time the component update.

The behaviour is consistently the same, text change = no update.

The loader doesn't have anything particular in its config.

{
test: /\.vue$/,
loader: 'vue-loader',
options: {
    loaders: {
    }

}

The dev server is launch via gulp with this task:

// Start a webpack-dev-server
const hot_webpack_config = cloneDeep(webpack_config)

hot_webpack_config.output.filename = 'frontend.hot.js'
hot_webpack_config.output.publicPath = PUBLIC_DEV_SERVER
hot_webpack_config.entry.unshift("webpack-dev-server/client?"+PUBLIC_DEV_SERVER, "webpack/hot/dev-server");
hot_webpack_config.plugins.push(new webpack.HotModuleReplacementPlugin())

var compiler = webpack(hot_webpack_config)

var WebpackDevServer = require("webpack-dev-server")

new WebpackDevServer(compiler, {
    //noInfo: true,
    hot: true,
    stats: {
      assets: false,
      colors: true,
      version: false,
      timings: false,
      chunks: false,
      chunkModules: false
    },
    inline: true,
    publicPath: hot_webpack_config.output.publicPath,
    headers: { "Access-Control-Allow-Origin": "*" }

}).listen(4000, "localhost", function(err) {
    if(err) throw new gutil.PluginError("webpack-dev-server", err)
    // Server listening
    gutil.log(chalk.blue("Hot server listening at http://0.0.0.0:4000"))

})

Not sure where else to look to fix this. As mentioned, it kinda works, just not for text node updates.

I've looked at the template generated by the vue-cli webpack-simple sample and the code is somewhat similar (except dev server is launch from node command line rather than manually building it), theirs does update text node, mine doesn't :(

Any clues?

Update: versions of relevant dependencies

vue 2.3.4
vue-loader 13.0.0 
vue-template-compiler 2.3.4 
webpack 2.6.1 
webpack-dev-server 2.5.0 

Update 2: applying any modification to the <script> part of the component does cause the text nodes to refresh.

Update 3:

// webpack_config.js
/* jshint node: true */
var webpack = require('webpack'),
    path = require('path'),
    package = require('./package.json'),
    gutil = require('gulp-util'),
    chalk = require('chalk');

const PUBLIC_DEV_SERVER = package.config.build.PUBLIC_DEV_SERVER
const ENTRY = package.config.build.ENTRY

var PROD = process.env.NODE_ENV == 'production';

let config = {
    entry: [
        ENTRY
    ],
    output: {
        path: path.join(__dirname, 'resources', 'js'),
        filename: 'frontend.min.js'
    },
    module: {

        rules: [{
                test: /\.vue$/,
                loader: 'vue-loader',
                options: {
                    loaders: {
                    }

                }
            }, {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/,
                query: {
                    presets: ['es2015', 'stage-0'],
                }
            }
        ]
    },
    resolve: {
        alias: {
            'vue$': 'vue/dist/vue.esm.js'
        }
    }

};

if (process.env.NODE_ENV === 'production') {
    gutil.log(chalk.red("Build for production"));
    config.devtool = '#source-map'
    config.entry = [
        ENTRY
    ];
    // http://vue-loader.vuejs.org/en/workflow/production.html
    config.plugins = (config.plugins || []).concat([
        new webpack.DefinePlugin({
          'process.env': {
            NODE_ENV: '"production"'
          }
        }),
        new webpack.optimize.UglifyJsPlugin({
          sourceMap: true,
          compress: {
            warnings: false
          }
        }),
        new webpack.LoaderOptionsPlugin({
          minimize: true
        })
      ])
} else {
    gutil.log(chalk.red("Build for development"));
    config.devtool = '#eval-source-map' //"cheap-module-eval-source-map"
    config.plugins = [
    ]
}

module.exports = config

PUBLIC_DEV_SERVER is set to "http://localhost:4000/"

ENTRY is set to "./src/js/frontend.js"

Trumpery answered 7/7, 2017 at 1:30 Comment(8)
do you have link to a git repo to try it?Accumulative
@francoisromain It's not in a state to easily put in a repo but I'm happy to supply any particular relevant file if you need...Trumpery
Could you show webpack_config?Accumulative
and what is the value of PUBLIC_DEV_SERVER?Accumulative
@francoisromain Thanks for looking into it. See Update 3 with the details you requested.Trumpery
Again, it almost works.. just not for a particular case scenario..Trumpery
I was not able to reproduce the bug, sorry. Just in case, I have a boilerplate using the webpack api, with a similar config, maybe this could help: github.com/francoisromain/test-vue-hmr-nodeapiAccumulative
Thanks François, as mentioned I wasn't able to reproduce it either with the cli generated sample either. I'll take a look at your boilerplate, maybe I can find a clue there. Will report back if I do..Trumpery
T
3

I've tried multiple things to fix this, I thought some settings fixed it but reverting back to previous versions suddenly started working too.

At the end, i think the fix was simply:

rm -rf node_modules/
npm i

But I don't know exactly which part of it made it fall apart.

Trumpery answered 17/7, 2017 at 6:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.