var Vue // late bind var version var map = Object.create(null) if (typeof window !== 'undefined') { window.__VUE_HOT_MAP__ = map } var installed = false var isBrowserify = false var initHookName = 'beforeCreate' exports.install = function (vue, browserify) { if (installed) { return } installed = true Vue = vue.__esModule ? vue.default : vue version = Vue.version.split('.').map(Number) isBrowserify = browserify // compat with < 2.0.0-alpha.7 if (Vue.config._lifecycleHooks.indexOf('init') > -1) { initHookName = 'init' } exports.compatible = version[0] >= 2 if (!exports.compatible) { console.warn( '[HMR] You are using a version of vue-hot-reload-api that is ' + 'only compatible with Vue.js core ^2.0.0.' ) return } } /** * Create a record for a hot module, which keeps track of its constructor * and instances * * @param {String} id * @param {Object} options */ exports.createRecord = function (id, options) { if(map[id]) { return } var Ctor = null if (typeof options === 'function') { Ctor = options options = Ctor.options } makeOptionsHot(id, options) map[id] = { Ctor: Ctor, options: options, instances: [] } } /** * Check if module is recorded * * @param {String} id */ exports.isRecorded = function (id) { return typeof map[id] !== 'undefined' } /** * Make a Component options object hot. * * @param {String} id * @param {Object} options */ function makeOptionsHot(id, options) { if (options.functional) { var render = options.render options.render = function (h, ctx) { var instances = map[id].instances if (ctx && instances.indexOf(ctx.parent) < 0) { instances.push(ctx.parent) } return render(h, ctx) } } else { injectHook(options, initHookName, function() { var record = map[id] if (!record.Ctor) { record.Ctor = this.constructor } record.instances.push(this) }) injectHook(options, 'beforeDestroy', function() { var instances = map[id].instances instances.splice(instances.indexOf(this), 1) }) } } /** * Inject a hook to a hot reloadable component so that * we can keep track of it. * * @param {Object} options * @param {String} name * @param {Function} hook */ function injectHook(options, name, hook) { var existing = options[name] options[name] = existing ? Array.isArray(existing) ? existing.concat(hook) : [existing, hook] : [hook] } function tryWrap(fn) { return function (id, arg) { try { fn(id, arg) } catch (e) { console.error(e) console.warn( 'Something went wrong during Vue component hot-reload. Full reload required.' ) } } } function updateOptions (oldOptions, newOptions) { for (var key in oldOptions) { if (!(key in newOptions)) { delete oldOptions[key] } } for (var key$1 in newOptions) { oldOptions[key$1] = newOptions[key$1] } } exports.rerender = tryWrap(function (id, options) { var record = map[id] if (!options) { record.instances.slice().forEach(function (instance) { instance.$forceUpdate() }) return } if (typeof options === 'function') { options = options.options } if (record.Ctor) { record.Ctor.options.render = options.render record.Ctor.options.staticRenderFns = options.staticRenderFns record.instances.slice().forEach(function (instance) { instance.$options.render = options.render instance.$options.staticRenderFns = options.staticRenderFns // reset static trees // pre 2.5, all static trees are cached together on the instance if (instance._staticTrees) { instance._staticTrees = [] } // 2.5.0 if (Array.isArray(record.Ctor.options.cached)) { record.Ctor.options.cached = [] } // 2.5.3 if (Array.isArray(instance.$options.cached)) { instance.$options.cached = [] } // post 2.5.4: v-once trees are cached on instance._staticTrees. // Pure static trees are cached on the staticRenderFns array // (both already reset above) // 2.6: temporarily mark rendered scoped slots as unstable so that // child components can be forced to update var restore = patchScopedSlots(instance) instance.$forceUpdate() instance.$nextTick(restore) }) } else { // functional or no instance created yet record.options.render = options.render record.options.staticRenderFns = options.staticRenderFns // handle functional component re-render if (record.options.functional) { // rerender with full options if (Object.keys(options).length > 2) { updateOptions(record.options, options) } else { // template-only rerender. // need to inject the style injection code for CSS modules // to work properly. var injectStyles = record.options._injectStyles if (injectStyles) { var render = options.render record.options.render = function (h, ctx) { injectStyles.call(ctx) return render(h, ctx) } } } record.options._Ctor = null // 2.5.3 if (Array.isArray(record.options.cached)) { record.options.cached = [] } record.instances.slice().forEach(function (instance) { instance.$forceUpdate() }) } } }) exports.reload = tryWrap(function (id, options) { var record = map[id] if (options) { if (typeof options === 'function') { options = options.options } makeOptionsHot(id, options) if (record.Ctor) { if (version[1] < 2) { // preserve pre 2.2 behavior for global mixin handling record.Ctor.extendOptions = options } var newCtor = record.Ctor.super.extend(options) // prevent record.options._Ctor from being overwritten accidentally newCtor.options._Ctor = record.options._Ctor record.Ctor.options = newCtor.options record.Ctor.cid = newCtor.cid record.Ctor.prototype = newCtor.prototype if (newCtor.release) { // temporary global mixin strategy used in < 2.0.0-alpha.6 newCtor.release() } } else { updateOptions(record.options, options) } } record.instances.slice().forEach(function (instance) { if (instance.$vnode && instance.$vnode.context) { instance.$vnode.context.$forceUpdate() } else { console.warn( 'Root or manually mounted instance modified. Full reload required.' ) } }) }) // 2.6 optimizes template-compiled scoped slots and skips updates if child // only uses scoped slots. We need to patch the scoped slots resolving helper // to temporarily mark all scoped slots as unstable in order to force child // updates. function patchScopedSlots (instance) { if (!instance._u) { return } // https://github.com/vuejs/vue/blob/dev/src/core/instance/render-helpers/resolve-scoped-slots.js var original = instance._u instance._u = function (slots) { try { // 2.6.4 ~ 2.6.6 return original(slots, true) } catch (e) { // 2.5 / >= 2.6.7 return original(slots, null, true) } } return function () { instance._u = original } }