index.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. var Vue // late bind
  2. var version
  3. var map = window.__VUE_HOT_MAP__ = Object.create(null)
  4. var installed = false
  5. var isBrowserify = false
  6. var initHookName = 'beforeCreate'
  7. exports.install = function (vue, browserify) {
  8. if (installed) return
  9. installed = true
  10. Vue = vue.__esModule ? vue.default : vue
  11. version = Vue.version.split('.').map(Number)
  12. isBrowserify = browserify
  13. // compat with < 2.0.0-alpha.7
  14. if (Vue.config._lifecycleHooks.indexOf('init') > -1) {
  15. initHookName = 'init'
  16. }
  17. exports.compatible = version[0] >= 2
  18. if (!exports.compatible) {
  19. console.warn(
  20. '[HMR] You are using a version of vue-hot-reload-api that is ' +
  21. 'only compatible with Vue.js core ^2.0.0.'
  22. )
  23. return
  24. }
  25. }
  26. /**
  27. * Create a record for a hot module, which keeps track of its constructor
  28. * and instances
  29. *
  30. * @param {String} id
  31. * @param {Object} options
  32. */
  33. exports.createRecord = function (id, options) {
  34. var Ctor = null
  35. if (typeof options === 'function') {
  36. Ctor = options
  37. options = Ctor.options
  38. }
  39. makeOptionsHot(id, options)
  40. map[id] = {
  41. Ctor: Vue.extend(options),
  42. instances: []
  43. }
  44. }
  45. /**
  46. * Make a Component options object hot.
  47. *
  48. * @param {String} id
  49. * @param {Object} options
  50. */
  51. function makeOptionsHot (id, options) {
  52. injectHook(options, initHookName, function () {
  53. map[id].instances.push(this)
  54. })
  55. injectHook(options, 'beforeDestroy', function () {
  56. var instances = map[id].instances
  57. instances.splice(instances.indexOf(this), 1)
  58. })
  59. }
  60. /**
  61. * Inject a hook to a hot reloadable component so that
  62. * we can keep track of it.
  63. *
  64. * @param {Object} options
  65. * @param {String} name
  66. * @param {Function} hook
  67. */
  68. function injectHook (options, name, hook) {
  69. var existing = options[name]
  70. options[name] = existing
  71. ? Array.isArray(existing)
  72. ? existing.concat(hook)
  73. : [existing, hook]
  74. : [hook]
  75. }
  76. function tryWrap (fn) {
  77. return function (id, arg) {
  78. try { fn(id, arg) } catch (e) {
  79. console.error(e)
  80. console.warn('Something went wrong during Vue component hot-reload. Full reload required.')
  81. }
  82. }
  83. }
  84. exports.rerender = tryWrap(function (id, options) {
  85. var record = map[id]
  86. if (typeof options === 'function') {
  87. options = options.options
  88. }
  89. record.Ctor.options.render = options.render
  90. record.Ctor.options.staticRenderFns = options.staticRenderFns
  91. record.instances.slice().forEach(function (instance) {
  92. instance.$options.render = options.render
  93. instance.$options.staticRenderFns = options.staticRenderFns
  94. instance._staticTrees = [] // reset static trees
  95. instance.$forceUpdate()
  96. })
  97. })
  98. exports.reload = tryWrap(function (id, options) {
  99. if (typeof options === 'function') {
  100. options = options.options
  101. }
  102. makeOptionsHot(id, options)
  103. var record = map[id]
  104. if (version[1] < 2) {
  105. // preserve pre 2.2 behavior for global mixin handling
  106. record.Ctor.extendOptions = options
  107. }
  108. var newCtor = record.Ctor.super.extend(options)
  109. record.Ctor.options = newCtor.options
  110. record.Ctor.cid = newCtor.cid
  111. record.Ctor.prototype = newCtor.prototype
  112. if (newCtor.release) {
  113. // temporary global mixin strategy used in < 2.0.0-alpha.6
  114. newCtor.release()
  115. }
  116. record.instances.slice().forEach(function (instance) {
  117. if (instance.$vnode && instance.$vnode.context) {
  118. instance.$vnode.context.$forceUpdate()
  119. } else {
  120. console.warn('Root or manually mounted instance modified. Full reload required.')
  121. }
  122. })
  123. })