Skip to content

Commit 9d9b63b

Browse files
committed
wip: hot-reload
1 parent a977487 commit 9d9b63b

File tree

2 files changed

+89
-10
lines changed

2 files changed

+89
-10
lines changed

lib/hot-shim.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// override component directive's resolveComponent function.
2+
// When component is resolved:
3+
// - remove self from previous component's list
4+
// - add self to current component's list
5+
6+
var shimmed = false
7+
module.exports = function (Vue) {
8+
if (shimmed) return
9+
shimmed = true
10+
console.log('[HMR] Vue component hot reload shim applied.')
11+
var map = window.map = Vue.config._hotComponents = Object.create(null)
12+
var componentDir = Vue.internalDirectives.component
13+
var resolve = componentDir.resolveComponent
14+
componentDir.resolveComponent = function (id, cb) {
15+
var view = this
16+
var prevComponent = view.Component
17+
var prevId = prevComponent && prevComponent.options.hotID
18+
resolve.call(this, id, function () {
19+
var Component = view.Component
20+
var newId = Component.options.hotID
21+
if (prevId) {
22+
map[prevId].instances.$remove(view)
23+
}
24+
if (newId) {
25+
if (!map[newId]) {
26+
map[newId] = {
27+
Ctor: Component,
28+
instances: []
29+
}
30+
}
31+
map[newId].instances.push(view)
32+
}
33+
cb()
34+
})
35+
}
36+
}

lib/loader.js

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
var loaderUtils = require('loader-utils')
22
var selectorPath = require.resolve('./selector')
33
var parserPath = require.resolve('./parser')
4+
var hotShimPath = require.resolve('./hot-shim')
45

56
var defaultLang = {
67
template: 'html',
@@ -29,19 +30,23 @@ module.exports = function (content) {
2930

3031
function getRequire (type, part, index, scoped) {
3132
return 'require(' +
32-
loaderUtils.stringifyRequest(self,
33-
// disable system loaders (except post loaders)
34-
'-!' +
35-
// get loader string for pre-processors
36-
getLoaderString(type, part, scoped) +
37-
// select the corresponding part from the vue file
38-
getSelectorString(type, index || 0) +
39-
// the url to the actual vuefile
40-
vueUrl
41-
) +
33+
getRequireString(type, part, index, scoped) +
4234
')\n'
4335
}
4436

37+
function getRequireString (type, part, index, scoped) {
38+
return loaderUtils.stringifyRequest(self,
39+
// disable system loaders (except post loaders)
40+
'-!' +
41+
// get loader string for pre-processors
42+
getLoaderString(type, part, scoped) +
43+
// select the corresponding part from the vue file
44+
getSelectorString(type, index || 0) +
45+
// the url to the actual vuefile
46+
vueUrl
47+
)
48+
}
49+
4550
function getRequireForImport (impt) {
4651
return 'require(' +
4752
loaderUtils.stringifyRequest(self,
@@ -113,6 +118,44 @@ module.exports = function (content) {
113118
getRequire('template', parts.template[0], 0, hasLocalStyles)
114119
}
115120

121+
// hot reload
122+
if (parts.script.length || parts.template.length) {
123+
var scriptString = parts.script.length ? getRequireString('script', parts.script[0], 0) : ''
124+
var templateString = parts.template.length ? getRequireString('template', parts.template[0], 0, hasLocalStyles) : ''
125+
var accepted = []
126+
if (scriptString) {
127+
accepted.push(scriptString.slice(1, -1))
128+
}
129+
if (templateString) {
130+
accepted.push(templateString.slice(1, -1))
131+
}
132+
output +=
133+
'if (module.hot) {\n' +
134+
'(function () {\n' +
135+
// shim the component directive so that it
136+
// registers the instances
137+
'var Vue = require("vue")\n' +
138+
'require("' + hotShimPath + '")(Vue)\n' +
139+
'var map = Vue.config._hotComponents\n' +
140+
'var id = module.exports.hotID = ' + (scriptString || templateString) + '\n' +
141+
'module.hot.accept(' + JSON.stringify(accepted) + ', function () {\n' +
142+
'var Ctor = map[id].Ctor\n' +
143+
// overwrite existing constructor's options
144+
(scriptString ? 'Ctor.options = Vue.util.mergeOptions(Vue.options, require(' + scriptString + '))\n' : '') +
145+
(templateString ? 'Ctor.options.template = require(' + templateString + ')\n' : '') +
146+
// reset linker
147+
'Ctor.linker = null\n' +
148+
// reload directive instances
149+
'map[id].instances.forEach(function (view) {\n' +
150+
'var state = view.childVM.$data\n' +
151+
'view.mountComponent()\n' +
152+
'view.childVM.$data = state\n' +
153+
'})\n' +
154+
'})\n' +
155+
'})()\n' +
156+
'}'
157+
}
158+
116159
// done
117160
cb(null, output)
118161
})

0 commit comments

Comments
 (0)