index.js
3.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
var Vue // late bind
var map = window.__VUE_HOT_MAP__ = Object.create(null)
var installed = false
var isBrowserify = false
var initHookName = 'beforeCreate'
exports.install = function (vue, browserify) {
if (installed) return
installed = true
Vue = vue
isBrowserify = browserify
// compat with < 2.0.0-alpha.7
if (Vue.config._lifecycleHooks.indexOf('init') > -1) {
initHookName = 'init'
}
exports.compatible = Number(Vue.version.split('.')[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) {
var Ctor = null
if (typeof options === 'function') {
Ctor = options
options = Ctor.options
}
makeOptionsHot(id, options)
map[id] = {
Ctor: Vue.extend(options),
instances: []
}
}
/**
* Make a Component options object hot.
*
* @param {String} id
* @param {Object} options
*/
function makeOptionsHot (id, options) {
injectHook(options, initHookName, function () {
map[id].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.')
}
}
}
exports.rerender = tryWrap(function (id, options) {
var record = map[id]
if (typeof options === 'function') {
options = options.options
}
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
instance._staticTrees = [] // reset static trees
instance.$forceUpdate()
})
})
exports.reload = tryWrap(function (id, options) {
if (typeof options === 'function') {
options = options.options
}
makeOptionsHot(id, options)
var record = map[id]
record.Ctor.extendOptions = options
var newCtor = record.Ctor.super.extend(options)
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()
}
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.')
}
})
})