Repository: parcel-bundler/parcel
File: packages/core/parcel-bundler/src/builtins/hmr-runtime.js (JavaScript)

Code before:

  module.bundle.hotData = null;
}

module.bundle.Module = Module;
var updatedAssets;

var parent = module.bundle.parent;
if ((!parent || !parent.isParcelRequire) && typeof WebSocket !== 'undefined') {
  var hostname = process.env.HMR_HOSTNAME || location.hostname;
  var protocol = location.protocol === 'https:' ? 'wss' : 'ws';
  var ws = new WebSocket(protocol + '://' + hostname + ':' + process.env.HMR_PORT + '/');
  ws.onmessage = function(event) {
    updatedAssets = {};

    var data = JSON.parse(event.data);

    if (data.type === 'update') {
      var handled = false;
      data.assets.forEach(function(asset) {
        handled =
          handled ||
          (global.parcelRequire.cache[asset.id] &&
            (Boolean(global.parcelRequire.cache[asset.id].hot._acceptCallbacks.length) ||
             Boolean(global.parcelRequire.cache[asset.id].hot._disposeCallbacks.length)
             )
          );
      });

      if(handled){
        console.clear();

        data.assets.forEach(function (asset) {
          hmrApply(global.parcelRequire, asset);
        });

        data.assets.forEach(function (asset) {
          if (!asset.isNew) {
            hmrAccept(global.parcelRequire, asset.id);
          }
        });
      } else {
        window.location.reload();
      }
    }

    if (data.type === 'reload') {
      ws.close();
      ws.onclose = function () {
        location.reload();
      }

Review comment (suggestion):
This isn't quite enough. You need to traverse upward from the asset to the root asset and check if any of the parents accept the update as well as the asset itself. Basically, we need to split `hmrAccept` up into two functions. One that traverses upward and checks if an update should be accepted, but without actually re-executing them. It can also keep track of all of the assets that need to be re-executed in a list. Then, if an update is accepted, go through the list we tracked earlier, and re-execute them.

Code after:

  module.bundle.hotData = null;
}

module.bundle.Module = Module;
var checkedAssets, assetsToAccept;

var parent = module.bundle.parent;
if ((!parent || !parent.isParcelRequire) && typeof WebSocket !== 'undefined') {
  var hostname = process.env.HMR_HOSTNAME || location.hostname;
  var protocol = location.protocol === 'https:' ? 'wss' : 'ws';
  var ws = new WebSocket(protocol + '://' + hostname + ':' + process.env.HMR_PORT + '/');
  ws.onmessage = function(event) {
    checkedAssets = {};
    assetsToAccept = [];

    var data = JSON.parse(event.data);

    if (data.type === 'update') {
      var handled = false;
      data.assets.forEach(function(asset) {
        if (!asset.isNew) {
          var didAccept = hmrAcceptCheck(global.parcelRequire, asset.id);
          if (didAccept) {
            handled = true;
          }
        }
      });

      if(handled){
        console.clear();

        data.assets.forEach(function (asset) {
          hmrApply(global.parcelRequire, asset);
        });

        assetsToAccept.forEach(function (v) {
          hmrAcceptRun(v[0], v[1]);
        });
      } else {
        window.location.reload();
      }
    }

    if (data.type === 'reload') {
      ws.close();
      ws.onclose = function () {
        location.reload();
      }
    }