Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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"

like image 295
Ben Avatar asked Jul 07 '17 01:07

Ben


People also ask

How does Vue hot reload work?

"Hot Reload" is not simply reloading the page when you edit a file. With hot reload enabled, when you edit a *. vue file, all instances of that component will be swapped in without reloading the page. It even preserves the current state of your app and these swapped components!

Does Vue support hot reloading?

Vuex supports hot-reloading mutations, modules, actions and getters during development, using webpack's Hot Module Replacement API. You can also use it in Browserify with the browserify-hmr plugin.

How does Vue-loader work?

It's a webpack loader that supports defining Vue. js components in single files known as single-file components (SFCs). These files have the extension . vue and the vue-loader transpiles them into JavaScript so the browser can understand.

What is hot reload?

Hot reloading allows you to see the changes that you have made in the code without reloading your entire app. Whenever you make any changes, all you need to do is save your code. As soon as you save your code, React Native tracks which files have changed since your last saved, and only reload those file for you.


1 Answers

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.

like image 141
Ben Avatar answered Sep 20 '22 08:09

Ben