Skip to content

Commit 6650430

Browse files
author
Guillaume Chau
committed
Query components + loading + provider improvements
1 parent f12161f commit 6650430

15 files changed

+790
-376
lines changed

README.md

Lines changed: 115 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22

33
[![npm](https://img.shields.io/npm/v/vue-apollo/next.svg) ![npm](https://img.shields.io/npm/dm/vue-apollo.svg)](https://www.npmjs.com/package/vue-apollo)
44
[![vue1](https://img.shields.io/badge/apollo-2.x-blue.svg)](https://www.apollographql.com/)
5-
[![vue1](https://img.shields.io/badge/vue-1.x-brightgreen.svg) ![vue2](https://img.shields.io/badge/vue-2.x-brightgreen.svg)](https://vuejs.org/)
5+
[![vue1](https://img.shields.io/badge/vue-1.x-brightgreen.svg) ![vue2](https://img.shields.io/badge/vue-2.2+-brightgreen.svg)](https://vuejs.org/)
66

77
![schema](https://cdn-images-1.medium.com/max/800/1*H9AANoofLqjS10Xd5TwRYw.png)
88

99
**Warning! This README is related to the next version of vue-apollo (that supports Apollo 2.x). For the old release (supporting only Apollo 1.x), see [here](https://github.com/Akryum/vue-apollo/tree/master).**
1010

1111
Integrates [apollo](https://www.apollographql.com/) in your [Vue](http://vuejs.org) components with declarative queries. Compatible with Vue 1.0+ and 2.0+. [Live demo](https://jsfiddle.net/Akryum/oyejk2qL/)
1212

13+
[<img src="https://assets-cdn.github.com/favicon.ico" alt="icon" width="16" height="16"/> Vue-cli plugin](https://github.com/Akryum/vue-cli-plugin-apollo)
14+
1315
[<img src="https://assets-cdn.github.com/favicon.ico" alt="icon" width="16" height="16"/> More vue-apollo examples](https://github.com/Akryum/vue-apollo-example)
1416

1517
[<img src="https://assets-cdn.github.com/favicon.ico" alt="icon" width="16" height="16"/> Apollo graphql server example](https://github.com/Akryum/apollo-server-example)
@@ -28,6 +30,7 @@ Integrates [apollo](https://www.apollographql.com/) in your [Vue](http://vuejs.o
2830
- [Queries](#queries)
2931
- [Simple query](#simple-query)
3032
- [Query with parameters](#query-with-parameters)
33+
- [Loading state](#loading-state)
3134
- [Option function](#option-function)
3235
- [Reactive query definition](#reactive-query-definition)
3336
- [Reactive parameters](#reactive-parameters)
@@ -46,14 +49,17 @@ Integrates [apollo](https://www.apollographql.com/) in your [Vue](http://vuejs.o
4649
- [Skip all](#skip-all)
4750
- [Multiple clients](#multiple-clients)
4851
- [Server-Side Rendering](#server-side-rendering)
52+
- [Query Components](#query-components)
4953
- [Migration](#migration)
5054
- [API Reference](#api-reference)
5155

5256
## Installation
5357

58+
**If you are using vue-cli 3.x, you can [use this vue-cli plugin](https://github.com/Akryum/vue-cli-plugin-apollo) to get started in a few minutes!**
59+
5460
Try and install these packages before server side set (of packages), add apollo to meteor.js before then, too.
5561

56-
npm install --save vue-apollo@next graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag
62+
npm install --save vue-apollo graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag
5763

5864
In your app, create an `ApolloClient` instance and install the `VueApollo` plugin:
5965

@@ -91,7 +97,7 @@ const apolloProvider = new VueApollo({
9197

9298
new Vue({
9399
el: '#app',
94-
apolloProvider,
100+
provide: apolloProvider.provide(),
95101
render: h => h(App),
96102
})
97103
```
@@ -267,12 +273,26 @@ And then use it in your vue component:
267273
<div class="apollo">
268274
<h3>Ping</h3>
269275
<p>
270-
{{ping}}
276+
{{ ping }}
271277
</p>
272278
</div>
273279
</template>
274280
```
275281

282+
### Loading state
283+
284+
You can display a loading state thanks to the `$apollo.loading` prop:
285+
286+
```html
287+
<div v-if="$apollo.loading">Loading...</div>
288+
```
289+
290+
Or for this specific `ping` query:
291+
292+
```html
293+
<div v-if="$apollo.queries.ping.loading">Loading...</div>
294+
```
295+
276296
### Option function
277297

278298
You can use a function to initialize the key:
@@ -1260,6 +1280,14 @@ export default willPrefetch({
12601280
})
12611281
```
12621282

1283+
The second parameter is optional: it's a callback that gets the context and should return a boolean indicating if the component should be prefetched:
1284+
1285+
```js
1286+
willPrefetch({
1287+
// Component definition...
1288+
}, context => context.url === '/foo')
1289+
```
1290+
12631291
### On the server
12641292

12651293
To prefetch all the apollo queries you marked, use the `apolloProvider.prefetchAll` method. The first argument is the context object passed to the `prefetch` hooks (see above). It is recommended to pass the vue-router `currentRoute` object. The second argument is the array of component definition to include (e.g. from `router.getMatchedComponents` method). The third argument is an optional `options` object. It returns a promise resolved when all the apollo queries are loaded.
@@ -1492,6 +1520,89 @@ router.onReady(() => {
14921520
})
14931521
```
14941522

1523+
## Query components
1524+
1525+
(WIP) You can use the `ApolloQuery` (or `apollo-query`) component to make watched Apollo queries directly in your template:
1526+
1527+
```html
1528+
<ApolloQuery
1529+
:query="require('../graphql/HelloWorld.gql')"
1530+
:variables="{ name }"
1531+
>
1532+
<template slot-scope="{ result: { loading, error, data } }">
1533+
<!-- Loading -->
1534+
<div v-if="loading" class="loading apollo">Loading...</div>
1535+
1536+
<!-- Error -->
1537+
<div v-else-if="error" class="error apollo">An error occured</div>
1538+
1539+
<!-- Result -->
1540+
<div v-else-if="data" class="result apollo">{{ data.hello }}</div>
1541+
1542+
<!-- No result -->
1543+
<div v-else class="no-result apollo">No result :(</div>
1544+
</template>
1545+
</ApolloQuery>
1546+
```
1547+
1548+
Props:
1549+
1550+
- `query`: GraphQL query (transformed by `graphql-tag`)
1551+
- `variables`: Object of GraphQL variables
1552+
- `fetchPolicy`: See [apollo fetchPolicy](https://www.apollographql.com/docs/react/basics/queries.html#graphql-config-options-fetchPolicy)
1553+
- `pollInterval`: See [apollo pollInterval](https://www.apollographql.com/docs/react/basics/queries.html#graphql-config-options-pollInterval)
1554+
- `notifyOnNetworkStatusChange`: See [apollo notifyOnNetworkStatusChange](https://www.apollographql.com/docs/react/basics/queries.html#graphql-config-options-notifyOnNetworkStatusChange)
1555+
- `context`: See [apollo context](https://www.apollographql.com/docs/react/basics/queries.html#graphql-config-options-context)
1556+
- `skip`: Boolean disabling query fetching
1557+
- `clienId`: Used to resolve the Apollo Client used (defined in ApolloProvider)
1558+
- `tag`: String HTML tag name (default: `div`)
1559+
1560+
Scoped slot props:
1561+
- `result`: Apollo Query result
1562+
- `result.data`: Data returned by the query
1563+
- `result.loading`: Boolean indicating that a request is in flight
1564+
- `result.error`: Eventual error for the current result
1565+
- `result.networkStatus`: See [apollo networkStatus](https://www.apollographql.com/docs/react/basics/queries.html#graphql-query-data-networkStatus)
1566+
- `query`: Smart Query associated with the component
1567+
1568+
(WIP) You can subscribe to mode data with the `ApolloSubscribeToMore` (or `apollo-subscribe-to-more`) component:
1569+
1570+
```html
1571+
<template>
1572+
<ApolloQuery>
1573+
<ApolloSubscribeToMore
1574+
:document="require('../gql/MessageAdded.gql')"
1575+
:variables="{ channel }"
1576+
:updateQuery="onMessageAdded"
1577+
/>
1578+
</ApolloQuery>
1579+
</template>
1580+
1581+
<script>
1582+
export default {
1583+
data () {
1584+
return {
1585+
channel: 'general',
1586+
}
1587+
},
1588+
1589+
methods: {
1590+
onMessageAdded (previousResult, { subscriptionData }) {
1591+
// The previous result is immutable
1592+
const newResult = {
1593+
messages: [...previousResult.messages],
1594+
}
1595+
// Add the question to the list
1596+
newResult.messages.push(subscriptionData.data.messageAdded)
1597+
return newResult
1598+
},
1599+
},
1600+
}
1601+
</script>
1602+
```
1603+
1604+
*You can put as many of those as you want inside a `<ApolloQuery>` component.*
1605+
14951606
---
14961607

14971608
# Migration

build/rollup.config.base.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ const config = require('../package.json')
77

88
export default {
99
input: 'src/index.js',
10-
name: 'vue-apollo',
1110
plugins: [
1211
resolve({
1312
jsnext: true,

build/rollup.config.browser.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ const config = Object.assign({}, base, {
66
output: {
77
file: 'dist/vue-apollo.min.js',
88
format: 'iife',
9+
name: 'VueApollo',
910
},
10-
name: 'VueApollo',
1111
})
1212

1313
config.plugins.push(uglify({}, minify))

build/rollup.config.es.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const config = Object.assign({}, base, {
44
output: {
55
file: 'dist/vue-apollo.esm.js',
66
format: 'es',
7+
name: 'vue-apollo',
78
},
89
})
910

build/rollup.config.umd.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const config = Object.assign({}, base, {
44
output: {
55
file: 'dist/vue-apollo.umd.js',
66
format: 'umd',
7+
name: 'vue-apollo',
78
},
89
})
910

package.json

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,11 @@
1212
"build:es": "rollup --config build/rollup.config.es.js",
1313
"build:umd": "rollup --config build/rollup.config.umd.js",
1414
"prepublishOnly": "npm run test && npm run build",
15-
"dev": "npm-watch",
16-
"test": "npm run test:types",
15+
"dev": "nodemon --exec 'npm run build' --watch src",
16+
"test": "npm run test:eslint && npm run test:types",
17+
"test:eslint": "eslint --ext .js src",
1718
"test:types": "tsc -p types/test"
1819
},
19-
"watch": {
20-
"build": "src/*.js"
21-
},
2220
"repository": {
2321
"type": "git",
2422
"url": "git+https://github.com/Akryum/vue-apollo.git"
@@ -61,7 +59,7 @@
6159
"eslint-plugin-standard": "^3.0.1",
6260
"graphql": "^0.12.3",
6361
"graphql-tag": "^2.5.0",
64-
"npm-watch": "^0.3.0",
62+
"nodemon": "^1.14.12",
6563
"rimraf": "^2.6.1",
6664
"rollup": "^0.55.3",
6765
"rollup-plugin-babel": "^3.0.2",

src/apollo-provider.js

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,20 @@ export class ApolloProvider {
1616
this.prefetchQueries = []
1717
}
1818

19-
willPrefetchQuery (queryOptions, client) {
19+
provide (key = '$apolloProvider') {
20+
return {
21+
[key]: this,
22+
}
23+
}
24+
25+
addQueryToPrefetch (queryOptions, client) {
2026
this.prefetchQueries.push({
2127
queryOptions,
2228
client,
2329
})
2430
}
2531

26-
willPrefetch (component) {
32+
prefetchComponent (component, context) {
2733
component = getMergedDefinition(component)
2834
const apolloOptions = component.apollo
2935

@@ -42,14 +48,14 @@ export class ApolloProvider {
4248
)
4349
)
4450
) {
45-
this.willPrefetchQuery(options, options.client || componentClient)
51+
this.addQueryToPrefetch(options, options.client || componentClient)
4652
}
4753
}
4854
}
4955

50-
willPrefetchComponents (definitions) {
56+
prefetchComponents (definitions) {
5157
for (const def of definitions) {
52-
this.willPrefetch(def)
58+
this.prefetchComponent(def)
5359
}
5460
}
5561

@@ -65,11 +71,21 @@ export class ApolloProvider {
6571
}, options)
6672

6773
if (components) {
68-
this.willPrefetchComponents(components)
74+
this.prefetchComponents(components)
6975
}
7076

7177
if (finalOptions.includeGlobal) {
72-
this.willPrefetchComponents(globalPrefetchs)
78+
this.prefetchComponents(globalPrefetchs.filter(
79+
({ component, contextCallback }) => {
80+
let result = true
81+
if (typeof contextCallback === 'function') {
82+
result = !!contextCallback(context)
83+
}
84+
return result
85+
}
86+
).map(
87+
({ component }) => component
88+
), context)
7389
}
7490

7591
return Promise.all(this.prefetchQueries.map(
@@ -166,7 +182,14 @@ export class ApolloProvider {
166182

167183
const globalPrefetchs = []
168184

169-
export function willPrefetch (component) {
170-
globalPrefetchs.push(component)
185+
export function willPrefetch (component, contextCallback = null) {
186+
globalPrefetchs.push({ component, contextCallback })
171187
return component
172188
}
189+
190+
// Global access for libraries
191+
if (typeof window !== 'undefined') {
192+
window.vueApolloWillPrefetch = willPrefetch
193+
} else if (typeof global !== 'undefined') {
194+
global.vueApolloWillPrefetch = willPrefetch
195+
}

0 commit comments

Comments
 (0)