Skip to content

Commit fd8d63b

Browse files
committed
Multiple clients & initial SSR support
1 parent 98ad783 commit fd8d63b

File tree

6 files changed

+310
-140
lines changed

6 files changed

+310
-140
lines changed

README.md

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Integrates [apollo](http://www.apollostack.com/) in your [Vue](http://vuejs.org)
1818
## Table of contents
1919

2020
- [Installation](#installation)
21-
- [Configuration](#configuration)
21+
- [Create a provider](#create-a-provider)
2222
- [Usage in components](#usage-in-components)
2323
- [Queries](#queries)
2424
- [Simple query](#simple-query)
@@ -36,14 +36,16 @@ Integrates [apollo](http://www.apollostack.com/) in your [Vue](http://vuejs.org)
3636
- [Skipping the subscription](#skipping-the-subscription)
3737
- [Pagination with `fetchMore`](#pagination-with-fetchmore)
3838
- [Skip all](#skip-all)
39+
- [Multiple clients](#multiple-clients)
40+
- [Server-Side Rendering](#server-side-rendering)
3941

4042
## Installation
4143

4244
Try and install this packages before server side set (of packages), add apollo to meteor.js before then, too.
4345

4446
npm install --save vue-apollo apollo-client@^0.5.0
4547

46-
## Configuration
48+
In your app, create an `ApolloClient` instance and install the `VueApollo` plugin:
4749

4850
```javascript
4951
import Vue from 'vue'
@@ -60,11 +62,23 @@ const apolloClient = new ApolloClient({
6062
})
6163

6264
// Install the vue plugin
63-
Vue.use(VueApollo, {
64-
apolloClient,
65+
Vue.use(VueApollo)
66+
```
67+
68+
## Create a provider
69+
70+
Like `vue-router` or `vuex`, you need to specify the `apolloProvider` object on your root components. A provider holds the apollo client instances that can then be used by all the child components.
71+
72+
```javascript
73+
const apolloProvider = new VueApollo({
74+
defaultClient: apolloClient,
6575
})
6676

67-
// Your Vue app is now Apollo-enabled!
77+
new Vue({
78+
el: '#app',
79+
apolloProvider,
80+
render: h => h(App),
81+
})
6882
```
6983

7084
## Usage in components
@@ -987,6 +1001,57 @@ apollo: {
9871001
}
9881002
```
9891003

1004+
## Multiple clients
1005+
1006+
You can specify multiple apollo clients if your app needs to connect to different GraphQL endpoints:
1007+
1008+
```javascript
1009+
const apolloProvider = new VueApollo({
1010+
clients: {
1011+
a: apolloClient,
1012+
b: otherApolloClient,
1013+
},
1014+
defaultClient: apolloClient,
1015+
})
1016+
```
1017+
1018+
In the component `apollo` option, you can define the client for all the queries, subscriptions and mutations with `$client` (only for this component):
1019+
1020+
```javascript
1021+
export default {
1022+
apollo: {
1023+
$client: 'b',
1024+
},
1025+
}
1026+
```
1027+
1028+
You can also specify the client in individual queries, subscriptions and mutations with the `client` property in the options:
1029+
1030+
```javascript
1031+
tags: {
1032+
query: gql`...`,
1033+
client: 'b',
1034+
}
1035+
```
1036+
1037+
## Server-Side Rendering
1038+
1039+
(Work in progress)
1040+
1041+
```javascript
1042+
const ensureReady = apolloProvider.collect()
1043+
1044+
new Vue({
1045+
el: '#app',
1046+
apolloProvider,
1047+
render: h => h(App),
1048+
})
1049+
1050+
ensureReady().then((...results) => {
1051+
console.log('ready', results.length)
1052+
})
1053+
```
1054+
9901055
---
9911056

9921057
LICENCE ISC - Created by Guillaume CHAU (@Akryum)

package.json

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
{
22
"name": "vue-apollo",
3-
"version": "2.0.0-beta.2",
43
"description": "Vue apollo integration",
5-
"main": "lib/vue-plugin.js",
4+
"main": "lib/index.js",
65
"scripts": {
76
"compile": "babel --presets es2015,stage-0 -d lib/ src/",
87
"prepublish": "npm run compile",
@@ -27,10 +26,10 @@
2726
},
2827
"homepage": "https://github.com/Akryum/vue-apollo#readme",
2928
"peerDependencies": {
30-
"apollo-client": "^1.0.0-rc.7"
29+
"apollo-client": "^1.0.1"
3130
},
3231
"dependencies": {
33-
"graphql-tag": "^1.3.2",
32+
"graphql-tag": "^2.0.0",
3433
"lodash.debounce": "^4.0.8",
3534
"lodash.omit": "^4.5.0",
3635
"lodash.throttle": "^4.1.1"

src/apollo-provider.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
export class ApolloProvider {
2+
constructor (options) {
3+
if (!options) {
4+
throw new Error('Options argument required')
5+
}
6+
this.clients = options.clients
7+
this.defaultClient = options.defaultClient
8+
this._collecting = false
9+
}
10+
11+
collect () {
12+
this._promises = []
13+
this._isCollecting = true
14+
return () => this._ensureReady()
15+
}
16+
17+
_waitFor (promise) {
18+
if (this._isCollecting) {
19+
this._promises.push(promise)
20+
}
21+
}
22+
23+
_ensureReady () {
24+
this._isCollecting = false
25+
return Promise.all(this._promises)
26+
}
27+
}

src/dollar-apollo.js

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import { SmartQuery, SmartSubscription } from './smart-apollo'
2+
3+
export class DollarApollo {
4+
constructor (vm) {
5+
this._apolloSubscriptions = []
6+
this._watchers = []
7+
8+
this.vm = vm
9+
this.queries = {}
10+
this.subscriptions = {}
11+
this.client = undefined
12+
}
13+
14+
get provider () {
15+
return this._apolloProvider || this.vm.$root._apolloProvider
16+
}
17+
18+
_autoCollect (query) {
19+
if (this.provider._isCollecting) {
20+
let sub
21+
this.provider._waitFor(new Promise((resolve, reject) => {
22+
sub = query.subscribe({
23+
next: result => {
24+
resolve(result)
25+
},
26+
error: error => {
27+
reject(error)
28+
},
29+
})
30+
}).then(result => {
31+
sub.unsubscribe()
32+
return result
33+
}, error => {
34+
sub.unsubscribe()
35+
return error
36+
}))
37+
}
38+
return query
39+
}
40+
41+
query (options) {
42+
return this._autoCollect(this.getClient(options).query(options))
43+
}
44+
45+
getClient (options) {
46+
if (!options || !options.client) {
47+
if (typeof this.client === 'object') {
48+
return this.client
49+
}
50+
if (this.client) {
51+
if (!this.provider.clients) {
52+
throw new Error(`[vue-apollo] Missing 'clients' options in 'apolloProvider'`)
53+
} else {
54+
const client = this.provider.clients[this.client]
55+
if (!client) {
56+
throw new Error(`[vue-apollo] Missing client '${this.client}' in 'apolloProvider'`)
57+
}
58+
return client
59+
}
60+
}
61+
return this.provider.defaultClient
62+
}
63+
const client = this.provider.clients[options.client]
64+
if (!client) {
65+
throw new Error(`[vue-apollo] Missing client '${options.client}' in 'apolloProvider'`)
66+
}
67+
return client
68+
}
69+
70+
watchQuery (options) {
71+
const observable = this.getClient(options).watchQuery(options)
72+
const _subscribe = observable.subscribe.bind(observable)
73+
observable.subscribe = (options) => {
74+
let sub = _subscribe(options)
75+
this._apolloSubscriptions.push(sub)
76+
return sub
77+
}
78+
return this._autoCollect(observable)
79+
}
80+
81+
mutate (options) {
82+
return this.getClient(options).mutate(options)
83+
}
84+
85+
subscribe (options) {
86+
const observable = this.getClient(options).subscribe(options)
87+
const _subscribe = observable.subscribe.bind(observable)
88+
observable.subscribe = (options) => {
89+
let sub = _subscribe(options)
90+
this._apolloSubscriptions.push(sub)
91+
return sub
92+
}
93+
return observable
94+
}
95+
96+
option (key, options) {
97+
this.queries[key] = new SmartQuery(this.vm, key, options)
98+
}
99+
100+
subscribeOption (key, options) {
101+
this.subscriptions[key] = new SmartSubscription(this.vm, key, options)
102+
}
103+
104+
defineReactiveSetter (key, func) {
105+
this._watchers.push(this.vm.$watch(func, value => {
106+
this[key] = value
107+
}, {
108+
immediate: true,
109+
}))
110+
}
111+
112+
set skipAllQueries (value) {
113+
for (let key in this.queries) {
114+
this.queries[key].skip = value
115+
}
116+
}
117+
118+
set skipAllSubscriptions (value) {
119+
for (let key in this.subscriptions) {
120+
this.subscriptions[key].skip = value
121+
}
122+
}
123+
124+
set skipAll (value) {
125+
this.skipAllQueries = value
126+
this.skipAllSubscriptions = value
127+
}
128+
129+
destroy () {
130+
for (const unwatch of this._watchers) {
131+
unwatch()
132+
}
133+
for (let key in this.queries) {
134+
this.queries[key].destroy()
135+
}
136+
for (let key in this.subscriptions) {
137+
this.subscriptions[key].destroy()
138+
}
139+
this._apolloSubscriptions.forEach((sub) => {
140+
sub.unsubscribe()
141+
})
142+
this._apolloSubscriptions = null
143+
this.vm = null
144+
}
145+
}

0 commit comments

Comments
 (0)