feat: ssr provider default options + config + globalPrefetch + mockInstance

This commit is contained in:
Guillaume Chau
2018-10-03 14:06:44 +02:00
committed by Guillaume Chau
parent cd47404435
commit 11fc590ea8
3 changed files with 118 additions and 13 deletions
+66
View File
@@ -6,6 +6,35 @@ See [SSR guide](../guide/ssr.md).
## Methods
### install
Install the SSR plugin only on the server with:
```js
Vue.use(ApolloSSR)
```
You can pass additional options like this:
```js
Vue.use(ApolloSSR, {
fetchPolicy: 'network-only',
suppressRenderErrors: false,
})
```
#### fetchPolicy
When an Apollo query is prefetched, it's recommended to override `fetchPolicy` to force the queries to happen.
Default value: `'network-only'`.
#### suppressRenderErrors
Silent the fake render errors.
Default value: `false`.
### prefetchAll
Prefetches all queued component definitions and returns a promise resolved when all corresponding apollo data is ready.
@@ -53,3 +82,40 @@ const js = ApolloSSR.exportStates(apolloProvider, options)
exportNamespace: '',
}
```
### globalPrefetch
Allow you to register a component to be prefetched explicitely.
Simple example:
```js
import MyComponent from '@/components/MyComponent.vue'
ApolloSSR.globalPrefetch(() => MyComponent)
```
You can disable prefetching depending on context:
```js
ApolloSSR.globalPrefetch(context => {
if (context.route.name === 'foo'){
return MyComponent
}
})
```
### mockInstance
During `prefetchAll`, the app components tree is re-created with fake instances so the process is faster. You can apply plugins to modify the fake instances to prevent their render functions to crash if you have helpers like `this.$http` that is accessed in the template or render function (typically `Undefined error`). It's recommended to mock those helpers to improve performance.
```js
const noop = () => {}
ApolloSSR.mockInstance({
apply: vm => {
// Mock $http
vm.$http = noop
},
})
```
+8 -2
View File
@@ -140,7 +140,11 @@ import Vue from 'vue'
import ApolloSSR from 'vue-apollo/ssr'
import App from './App.vue'
Vue.use(ApolloSSR)
Vue.use(ApolloSSR, {
// SSR config
fetchPolicy: 'network-only',
suppressRenderErrors: false,
})
export default () => new Promise((resolve, reject) => {
const { app, router, store, apolloProvider } = CreateApp({
@@ -360,4 +364,6 @@ export default () => new Promise((resolve, reject) => {
// Prefetch, render HTML (see above)
})
})
```
```
See the [SSR API](../api/ssr.md) for more details and other features.
+44 -11
View File
@@ -3,12 +3,29 @@ const { VUE_APOLLO_QUERY_KEYWORDS } = require('../lib/consts')
const { createFakeInstance, resolveComponent } = require('./utils')
const { Globals, getMergedDefinition, omit } = require('../lib/utils')
exports.install = function (Vue) {
Globals.Vue = Vue
const config = exports.config = {
globalPrefetchs: [],
fakeInstanceMocks: [],
fetchPolicy: 'network-only',
suppressRenderErrors: false,
}
exports.prefetchAll = function (apolloProvider, components, context) {
return exports.getQueriesFromTree(components, context)
exports.install = function (Vue, options = {}) {
Globals.Vue = Vue
Object.assign(config, options)
}
exports.globalPrefetch = function (handler) {
config.globalPrefetchs.push(handler)
}
exports.mockInstance = function (plugin) {
config.fakeInstanceMocks.push(plugin)
}
exports.prefetchAll = function (apolloProvider, components = [], context = {}) {
const globalPrefetchs = config.globalPrefetchs.map(handler => handler(context)).filter(Boolean)
return exports.getQueriesFromTree(components.concat(globalPrefetchs), context)
.then(queries => Promise.all(queries.map(
query => prefetchQuery(apolloProvider, query, context)
)))
@@ -27,6 +44,13 @@ function walkTree (component, data, parent, children, context, queries, componen
const queue = []
data = data || {}
const vm = createFakeInstance(component, data, parent, children, context)
// Mocks
for (const mock of config.fakeInstanceMocks) {
mock.apply(mock)
}
// Render h function
vm.$createElement = (el, data, children) => {
if (typeof data === 'string' || Array.isArray(data)) {
children = data
@@ -58,8 +82,10 @@ function walkTree (component, data, parent, children, context, queries, componen
try {
component.render.call(vm, vm.$createElement)
} catch (e) {
console.log(chalk.red(`Error while rendering ${component.name || component.__file}`))
console.log(e.stack)
if (!config.suppressRenderErrors) {
console.log(chalk.red(`Error while rendering ${component.name || component.__file}`))
console.log(e.stack)
}
}
Promise.all(queue).then(queue => queue.filter(child => !!child).map(
@@ -163,15 +189,22 @@ function prefetchQuery (apolloProvider, query, context) {
queryOptions.query = queryOptions.query.call(vm)
}
const options = omit(queryOptions, [
...VUE_APOLLO_QUERY_KEYWORDS,
'fetchPolicy',
])
// Default query options from apollo provider
if (apolloProvider.defaultOptions && apolloProvider.defaultOptions.$query) {
queryOptions = Object.assign({}, apolloProvider.defaultOptions.$query, queryOptions)
}
// Remove vue-apollo specific options
const options = omit(queryOptions, VUE_APOLLO_QUERY_KEYWORDS)
options.variables = variables
options.fetchPolicy = 'network-only'
// Override fetchPolicy
if (config.fetchPolicy != null) {
options.fetchPolicy = config.fetchPolicy
}
return client.query(options)
} catch (e) {
console.log(chalk.red(`[ERROR] While prefetching query`), query, chalk.grey(`Error stack trace:`))
console.log(e.stack)
}
}