Skip to content

Commit

Permalink
More special options, default options, provider options, better doc (…
Browse files Browse the repository at this point in the history
…wip)
  • Loading branch information
Guillaume Chau committed Aug 28, 2017
1 parent 086b486 commit d07900c
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 25 deletions.
165 changes: 165 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@ Integrates [apollo](http://www.apollostack.com/) in your [Vue](http://vuejs.org)
- [Skipping the subscription](#skipping-the-subscription)
- [Manually adding a smart Subscription](#manually-adding-a-smart-subscription)
- [Pagination with `fetchMore`](#pagination-with-fetchmore)
- [Special options](#special-options)
- [Skip all](#skip-all)
- [Multiple clients](#multiple-clients)
- [Server-Side Rendering](#server-side-rendering)
- [API Reference](#api-reference)

## Installation

Expand Down Expand Up @@ -1040,6 +1042,48 @@ export default {

**Don't forget to include the `__typename` to the new result.**

## Special options

The special options being with `$` in the `apollo` object.

- `$skip` to disable all queries and subscriptions (see below)
- `$skipAllQueries` to disable all queries (see below)
- `$skipAllSubscriptions` to disable all subscriptions (see below)
- `$client` to use a client by default (see below)
- `$loadingKey` for a default loading key (see `loadingKey` advanced options for smart queries)
- `$error` to catch errors in a default handler (see `error` advanced options for smart queries)

Example:

```html
<script>
export default {
data () {
return {
loading: 0,
}
},
apollo: {
$loadingKey: 'loading',
query1: { ... },
query2: { ... },
},
}
</script>
```

You can define in the apollo provider a default set of options to apply to the `apollo` definitions. For example:

```javascript
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
defaultOptions: {
// apollo options applied to all components that are using apollo
$loadingKey: 'loading',
},
})
```

## Skip all

You can disable all the queries for the component with `skipAllQueries`, all the subscriptions with `skipAllSubscriptions` and both with `skipAll`:
Expand Down Expand Up @@ -1409,4 +1453,125 @@ router.onReady(() => {

---

# API Reference

WIP (PR welcome!)

## ApolloProvider

### Constructor

```javascript
const apolloProvider = new VueApollo({
// Multiple clients support
// Use the 'client' option inside queries
// or '$client' on the apollo definition
clients: {
a: apolloClientA,
b: apolloClientB,
},
// Default client
defaultClient: apolloClient,
// Default 'apollo' definition
defaultOptions: {
// See 'apollo' defintion
},
// Watch loading state for all queries
// See the 'watchLoading' advanced option
watchLoading (state, mod) {
loading += mod
console.log('Global loading', loading, mod)
},
// Global error handler for all smart queries and subscriptions
errorHandler (error) {
console.log('Global error handler')
console.error(error)
},
})
```

Use the apollo provider into your Vue app:

```javascript
new Vue({
el: '#app',
apolloProvider,
render: h => h(App),
})
```

### Methods

#### prefetchAll

(SSR) Prefetch all queued component definitions and returns a promise resolved when all corresponding apollo data is ready.

```javascript
await apolloProvider.prefetchAll (context, componentDefs, options)
```

`context` is passed as the argument to the `prefetch` options inside the smart queries. It may contain the route and the store.

`options` defaults to:

```javascript
{
// Include components outside of the routes
// that are registered with `willPrefetch`
includeGlobal: true,
}
```

#### getStates

(SSR) Returns the apollo stores states as JavaScript objects.

```JavaScript
const states = apolloProvider.getStates(options)
```

`options` defaults to:

```javascript
{
// Prefix for the keys of each apollo client state
exportNamespace: '',
}
```

#### exportStates

(SSR) Returns the apollo stores states as JavaScript code inside a String. This code can be directly injected to the page HTML inside a `<script>` tag.

```javascript
const js = apolloProvider.exportStates(options)
```

`options` defaults to:

```javascript
{
// Global variable name
globalName: '__APOLLO_STATE__',
// Global object on which the variable is set
attachTo: 'window',
// Prefix for the keys of each apollo client state
exportNamespace: '',
}
```

## Dollar Apollo

This is the apollo manager added to any component that uses apollo. It can be accessed inside a component with `this.$apollo`.

## Smart Query

Each query declared in the `apollo` definition (that is, which doesn't start with a `$` char) in a component results in the creation of a smart query object.

## Smart Subscription

Each subscription declared in the `apollo.$subscribe` option in a component results in the creation of a smart subscription object.

---

LICENCE ISC - Created by Guillaume CHAU (@Akryum)
3 changes: 3 additions & 0 deletions src/apollo-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ export class ApolloProvider {
}
this.clients = options.clients || {}
this.clients.defaultClient = this.defaultClient = options.defaultClient
this.defaultOptions = options.defaultOptions
this.watchLoading = options.watchLoading
this.errorHandler = options.errorHandler

this.prefetchQueries = []
}
Expand Down
2 changes: 2 additions & 0 deletions src/dollar-apollo.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export class DollarApollo {
this.queries = {}
this.subscriptions = {}
this.client = undefined
this.loadingKey = undefined
this.error = undefined
}

get provider () {
Expand Down
42 changes: 25 additions & 17 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,32 @@ const keywords = [
]

const prepare = function prepare () {
let apolloProvider
if (this.$options.apolloProvider) {
this._apolloProvider = this.$options.apolloProvider
apolloProvider = this._apolloProvider = this.$options.apolloProvider
} else {
apolloProvider = this.$root._apolloProvider
}

if (this._apolloPrepared) return
this._apolloPrepared = true

// Prepare properties
let apollo = this.$options.apollo

if (apollo) {
this._apolloQueries = {}
this._apolloInitData = {}
this.$apollo = new DollarApollo(this)

if (!apollo.$init) {
apollo.$init = true

// Default options applied to `apollo` options
if (apolloProvider.defaultOptions) {
apollo = this.$options.apollo = Object.assign({}, apolloProvider.defaultOptions, apollo)
}
}

// watchQuery
for (let key in apollo) {
Expand All @@ -35,14 +49,23 @@ const launch = function launch () {
if (this._apolloLaunched) return
this._apolloLaunched = true

let apollo = this.$options.apollo
if (apollo) {
defineReactiveSetter(this.$apollo, 'skipAll', apollo.$skipAll)
defineReactiveSetter(this.$apollo, 'skipAllQueries', apollo.$skipAllQueries)
defineReactiveSetter(this.$apollo, 'skipAllSubscriptions', apollo.$skipAllSubscriptions)
defineReactiveSetter(this.$apollo, 'client', apollo.$client)
defineReactiveSetter(this.$apollo, 'loadingKey', apollo.$loadingKey)
defineReactiveSetter(this.$apollo, 'error', apollo.$error)
}

if (this._apolloQueries) {
// watchQuery
for (let key in this._apolloQueries) {
this.$apollo.addSmartQuery(key, this._apolloQueries[key])
}
}

let apollo = this.$options.apollo
if (apollo) {
if (apollo.subscribe) {
Globals.Vue.util.warn('vue-apollo -> `subscribe` option is deprecated. Use the `$subscribe` option instead.')
Expand All @@ -53,11 +76,6 @@ const launch = function launch () {
this.$apollo.addSmartSubscription(key, apollo.$subscribe[key])
}
}

defineReactiveSetter(this.$apollo, 'skipAll', apollo.$skipAll)
defineReactiveSetter(this.$apollo, 'skipAllQueries', apollo.$skipAllQueries)
defineReactiveSetter(this.$apollo, 'skipAllSubscriptions', apollo.$skipAllSubscriptions)
defineReactiveSetter(this.$apollo, 'client', apollo.$client)
}
}

Expand Down Expand Up @@ -95,16 +113,6 @@ export function install (Vue, options) {
return Object.assign(map, merge(toData, fromData))
}

// Lazy creation
Object.defineProperty(Vue.prototype, '$apollo', {
get () {
if (!this._apollo) {
this._apollo = new DollarApollo(this)
}
return this._apollo
},
})

Vue.mixin({

// Vue 1.x
Expand Down
29 changes: 21 additions & 8 deletions src/smart-apollo.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@ class SmartApollo {
throw new Error('Not implemented')
}

errorHandler (...args) {
this.options.error && this.options.error.call(this.vm, ...args)
this.vm.$apollo.error && this.vm.$apollo.error.call(this.vm, ...args)
this.vm.$apollo.provider.errorHandler && this.vm.$apollo.provider.errorHandler.call(this.vm, ...args)
}

catchError (error) {
if (error.graphQLErrors && error.graphQLErrors.length !== 0) {
console.error(`GraphQL execution errors for ${this.type} '${this.key}'`)
Expand All @@ -132,9 +138,7 @@ class SmartApollo {
}
}

if (typeof this.options.error === 'function') {
this.options.error.call(this.vm, error)
}
this.errorHandler(error)
}

destroy () {
Expand Down Expand Up @@ -233,14 +237,23 @@ export class SmartQuery extends SmartApollo {
this.loadingDone()
}

get loadingKey () {
return this.options.loadingKey || this.vm.$apollo.loadingKey
}

watchLoading (...args) {
this.options.watchLoading && this.options.watchLoading.call(this.vm, ...args)
this.vm.$apollo.watchLoading && this.vm.$apollo.watchLoading.call(this.vm, ...args)
this.vm.$apollo.provider.watchLoading && this.vm.$apollo.provider.watchLoading.call(this.vm, ...args)
}

applyLoadingModifier (value) {
if (this.options.loadingKey) {
this.vm[this.options.loadingKey] += value
const loadingKey = this.loadingKey
if (loadingKey && typeof this.vm[loadingKey] === 'number') {
this.vm[loadingKey] += value
}

if (this.options.watchLoading) {
this.options.watchLoading.call(this.vm, value === 1, value)
}
this.watchLoading(value === 1, value)
}

loadingDone () {
Expand Down

0 comments on commit d07900c

Please sign in to comment.