|
|
- 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
- }
- }
|