vue-keep-alive-dev
Version:
A plugin to resolve HMR issues with the core keep-alive plugin
125 lines (109 loc) • 3.18 kB
JavaScript
import Vue from 'vue';
const oldKeepAlive = Vue.component('KeepAlive');
function isDef(v) {
return v !== undefined && v !== null
}
function isAsyncPlaceholder(node) {
return node.isComment && node.asyncFactory
}
function getFirstComponentChild(children) {
if (Array.isArray(children)) {
for (var i = 0; i < children.length; i++) {
var c = children[i]
if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) {
return c
}
}
}
}
function remove(arr, item) {
if (arr.length) {
var index = arr.indexOf(item)
if (index > -1) {
return arr.splice(index, 1)
}
}
}
function getComponentName (opts) {
return opts && (opts.Ctor.options.name || opts.tag)
}
function matches (pattern, name){
if (Array.isArray(pattern)) {
return pattern.indexOf(name) > -1
} else if (typeof pattern === 'string') {
return pattern.split(',').indexOf(name) > -1
} else if (isRegExp(pattern)) {
return pattern.test(name)
}
/* istanbul ignore next */
return false
}
function pruneCache (keepAliveInstance, filter) {
const { cache, keys, _vnode } = keepAliveInstance
for (const key in cache) {
const cachedNode = cache[key]
if (cachedNode) {
const name = getComponentName(cachedNode.componentOptions)
if (name && !filter(name)) {
pruneCacheEntry(cache, key, keys, _vnode)
}
}
}
}
function pruneCacheEntry (cache, key, keys, current) {
const cached = cache[key]
if (cached && (!current || cached.tag !== current.tag)) {
cached.componentInstance.$destroy()
}
cache[key] = null
remove(keys, key)
}
const newKeepAlive = Vue.extend({
name: 'keep-alive',
mixins: [oldKeepAlive],
render () {
const slot = this.$slots.default
const vnode = getFirstComponentChild(slot)
const componentOptions = vnode && vnode.componentOptions
if (componentOptions) {
// check pattern
const name = getComponentName(componentOptions)
const { include, exclude } = this
if (
// not included
(include && (!name || !matches(include, name))) ||
// excluded
(exclude && name && matches(exclude, name))
) {
return vnode
}
const { cache, keys } = this
const key = vnode.key == null
? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
: vnode.key + `::${componentOptions.Ctor.cid}`;
if (cache[key]) {
vnode.componentInstance = cache[key].componentInstance
// make current key freshest
remove(keys, key)
keys.push(key)
} else {
cache[key] = vnode
keys.push(key)
// prune oldest entry
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
}
vnode.data.keepAlive = true
}
return vnode || (slot && slot[0])
}
});
export default {
install(Vue, options = {}) {
// override original keep-alive if in development
if (process.env.NODE_ENV === options.environment || 'development') {
Vue.component('keep-alive', newKeepAlive)
}
}
};