Files
apollo/ssr/utils.js
T
2018-09-08 15:21:06 +02:00

198 lines
4.6 KiB
JavaScript

const { VM_HELPERS, SSR_HELPERS, COMPONENT_BLACKLIST } = require('./consts')
const { Globals, getMergedDefinition, noop } = require('../lib/utils')
/* Fake instance creation */
function emptyString () {
return ''
}
const computedPropDef = {
enumerable: true,
configurable: true,
get: noop,
set: noop,
}
function defineComputed (target, key, userDef) {
if (typeof userDef === 'function') {
computedPropDef.get = userDef
computedPropDef.set = noop
} else {
computedPropDef.get = userDef.get || noop
computedPropDef.set = userDef.set || noop
}
Object.defineProperty(target, key, computedPropDef)
}
function resolveScopedSlots (fns, res) {
res = res || {}
for (var i = 0; i < fns.length; i++) {
if (Array.isArray(fns[i])) {
resolveScopedSlots(fns[i], res)
} else {
res[fns[i].key] = fns[i].fn
}
}
return res
}
function findRouteMatch (component, route) {
for (const r of route.matched) {
for (const key in r.components) {
if (r.components[key] === component) {
return r
}
}
}
}
exports.createFakeInstance = function (options, data, parent, children, context) {
const vm = Object.assign(
{},
data.attrs,
data.props,
{
$prefetch: true,
$options: options,
$parent: parent,
$children: children,
$attrs: data.attrs,
$props: data.props,
$slots: {},
$scopedSlots: {},
$set: Globals.Vue.set,
$delete: Globals.Vue.delete,
$route: context.route,
$store: context.store,
$apollo: {
queries: {},
loading: false,
},
$apolloData: {
loading: false,
},
_self: {},
_staticTrees: [],
_u: resolveScopedSlots,
}
)
// Render and other helpers
VM_HELPERS.forEach(helper => vm[helper] = noop)
SSR_HELPERS.forEach(helper => vm[helper] = emptyString)
// Scoped slots
if (data.scopedSlots) {
vm.$scopedSlots = data.scopedSlots
}
// Route props
if (context && context.route) {
const { route } = context
const matchedRoute = findRouteMatch(options, route)
if (matchedRoute && matchedRoute.props) {
const { props } = matchedRoute
if (props === true) {
Object.assign(vm, matchedRoute.params)
} else if (typeof props === 'function') {
Object.assign(vm, props(matchedRoute))
} else if (typeof props === 'object') {
Object.assign(vm, props)
}
}
}
// Methods
const methods = options.methods
for (const key in methods) {
vm[key] = methods[key].bind(vm)
}
// Computed
const computed = options.computed
for (const key in computed) {
defineComputed(vm, key, computed[key])
}
// Data
const localData = options.data
if (typeof localData === 'function') {
vm._data = localData.call(vm, vm)
} else if (typeof localData === 'object') {
vm._data = localData
} else {
vm._data = {}
}
vm.$data = vm._data
Object.assign(vm, vm._data)
// Prefetch state
const prefetch = options.prefetch
if (typeof prefetch === 'function') {
Object.assign(vm, prefetch(context))
} else if (typeof prefetch === 'object') {
Object.assign(vm, prefetch)
}
return vm
}
/* Component resolution */
function cached (fn) {
const cache = Object.create(null)
return function cachedFn (str) {
const hit = cache[str]
return hit || (cache[str] = fn(str))
}
}
const camelizeRE = /-(\w)/g
const camelize = cached(function (str) {
return str.replace(camelizeRE, function (_, c) { return c ? c.toUpperCase() : '' })
})
const capitalize = cached(function (str) {
return str.charAt(0).toUpperCase() + str.slice(1)
})
const hasOwnProperty = Object.prototype.hasOwnProperty
function hasOwn (obj, key) {
return hasOwnProperty.call(obj, key)
}
function resolveAsset (assets, id) {
if (typeof id !== 'string') return
if (hasOwn(assets, id)) return assets[id]
const camelCaseId = camelize(id)
if (hasOwn(assets, camelCaseId)) return assets[camelCaseId]
const pascalCaseId = capitalize(camelCaseId)
if (hasOwn(assets, pascalCaseId)) return assets[pascalCaseId]
}
exports.resolveComponent = function (name, options) {
return new Promise((resolve) => {
if (options.components) {
const component = resolveAsset(options.components, name)
if (component !== undefined) {
resolve(component)
}
}
return resolve(Globals.Vue.options.components[name])
}).then(component => {
if (component) {
component = getMergedDefinition(component)
if (!component.functional && (
!component.name ||
!COMPONENT_BLACKLIST.includes(component.name)
)) {
return component
}
}
})
}