Skip to content

Commit 5967e16

Browse files
committed
feat: allow global tracking outside of components
1 parent d5f6275 commit 5967e16

File tree

5 files changed

+61
-45
lines changed

5 files changed

+61
-45
lines changed

packages/test-e2e-composable-vue3/src/components/App.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<template>
2+
<GlobalLoading />
23
<div class="flex h-screen items-stretch bg-gray-100">
34
<ChannelList class="w-1/4 border-r border-gray-200" />
45
<router-view class="flex-1 overflow-auto" />
@@ -8,12 +9,14 @@
89
<script lang="ts">
910
import { defineComponent } from 'vue'
1011
import ChannelList from './ChannelList.vue'
12+
import GlobalLoading from './GlobalLoading.vue'
1113
1214
export default defineComponent({
1315
name: 'App',
1416
1517
components: {
1618
ChannelList,
19+
GlobalLoading,
1720
},
1821
})
1922
</script>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<script lang="ts" setup>
2+
import { useGlobalQueryLoading } from '@vue/apollo-composable'
3+
4+
const loading = useGlobalQueryLoading()
5+
</script>
6+
7+
<template>
8+
<div
9+
class="fixed bg-white p-4 rounded-br top-0 right-0"
10+
data-test-id="global-loading"
11+
>
12+
<div v-if="loading">
13+
Global loading...
14+
</div>
15+
</div>
16+
</template>

packages/test-e2e-composable-vue3/tests/e2e/specs/test.cy.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,4 +128,21 @@ describe('Vue 3 + Apollo Composable', () => {
128128
cy.get('input[type="checkbox"]').click()
129129
cy.get('[data-test-id="data"]').should('contain', 'Loaded channel: General')
130130
})
131+
132+
it('global loading', () => {
133+
cy.get('[data-test-id="global-loading"]').should('contain', 'Global loading...')
134+
cy.get('.channel-link').should('have.lengthOf', 2)
135+
cy.get('[data-test-id="global-loading"]').should('not.contain', 'Global loading...')
136+
cy.get('.channel-link').eq(0).click()
137+
cy.get('[data-test-id="global-loading"]').should('contain', 'Global loading...')
138+
cy.contains('#app', 'Currently viewing # General')
139+
cy.get('[data-test-id="global-loading"]').should('not.contain', 'Global loading...')
140+
cy.get('.channel-link').eq(1).click()
141+
cy.get('[data-test-id="global-loading"]').should('contain', 'Global loading...')
142+
cy.contains('#app', 'Currently viewing # Random')
143+
cy.get('[data-test-id="global-loading"]').should('not.contain', 'Global loading...')
144+
cy.get('.channel-link').eq(0).click()
145+
cy.get('[data-test-id="global-loading"]').should('not.contain', 'Global loading...')
146+
cy.contains('#app', 'Currently viewing # General')
147+
})
131148
})
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
1-
import { getCurrentTracking, getAppTracking } from './util/loadingTracking'
1+
import { getCurrentTracking, globalTracking } from './util/loadingTracking'
22
import { computed } from 'vue-demi'
33

44
export function useQueryLoading () {
55
const { tracking } = getCurrentTracking()
6+
if (!tracking) throw new Error('useQueryLoading must be called inside a setup function.')
67
return computed(() => tracking.queries.value > 0)
78
}
89

910
export function useMutationLoading () {
1011
const { tracking } = getCurrentTracking()
12+
if (!tracking) throw new Error('useMutationLoading must be called inside a setup function.')
1113
return computed(() => tracking.mutations.value > 0)
1214
}
1315

1416
export function useSubscriptionLoading () {
1517
const { tracking } = getCurrentTracking()
18+
if (!tracking) throw new Error('useSubscriptionLoading must be called inside a setup function.')
1619
return computed(() => tracking.subscriptions.value > 0)
1720
}
1821

1922
export function useGlobalQueryLoading () {
20-
const { appTracking } = getAppTracking()
21-
return computed(() => appTracking.queries.value > 0)
23+
return computed(() => globalTracking.queries.value > 0)
2224
}
2325

2426
export function useGlobalMutationLoading () {
25-
const { appTracking } = getAppTracking()
26-
return computed(() => appTracking.mutations.value > 0)
27+
return computed(() => globalTracking.mutations.value > 0)
2728
}
2829

2930
export function useGlobalSubscriptionLoading () {
30-
const { appTracking } = getAppTracking()
31-
return computed(() => appTracking.subscriptions.value > 0)
31+
return computed(() => globalTracking.subscriptions.value > 0)
3232
}

packages/vue-apollo-composable/src/util/loadingTracking.ts

Lines changed: 18 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Ref, watch, onUnmounted, ref, getCurrentInstance, onBeforeUnmount } from 'vue-demi'
2-
import type { CurrentInstance } from './types'
2+
import { isServer } from './env.js'
33

44
export interface LoadingTracking {
55
queries: Ref<number>
@@ -11,80 +11,60 @@ export interface AppLoadingTracking extends LoadingTracking {
1111
components: Map<any, LoadingTracking>
1212
}
1313

14-
export function getAppTracking () {
15-
const vm = getCurrentInstance() as CurrentInstance | null
16-
const root = vm?.$root ?? vm?.root ?? vm?.proxy?.$root as CurrentInstance | null | undefined
17-
if (!root) {
18-
throw new Error('Instance $root not found')
19-
}
20-
21-
let appTracking: AppLoadingTracking
22-
23-
if (!root._apolloAppTracking) {
24-
// Add per Vue tracking
25-
appTracking = root._apolloAppTracking = {
26-
queries: ref(0),
27-
mutations: ref(0),
28-
subscriptions: ref(0),
29-
components: new Map(),
30-
}
31-
} else {
32-
appTracking = root._apolloAppTracking
33-
}
34-
35-
return {
36-
appTracking,
37-
}
14+
export const globalTracking: AppLoadingTracking = {
15+
queries: ref(0),
16+
mutations: ref(0),
17+
subscriptions: ref(0),
18+
components: new Map(),
3819
}
3920

4021
export function getCurrentTracking () {
4122
const vm = getCurrentInstance()
4223
if (!vm) {
43-
throw new Error('getCurrentTracking must be used during a component setup')
24+
return {}
4425
}
4526

46-
const { appTracking } = getAppTracking()
47-
4827
let tracking: LoadingTracking
4928

50-
if (!appTracking.components.has(vm)) {
29+
if (!globalTracking.components.has(vm)) {
5130
// Add per-component tracking
52-
appTracking.components.set(vm, tracking = {
31+
globalTracking.components.set(vm, tracking = {
5332
queries: ref(0),
5433
mutations: ref(0),
5534
subscriptions: ref(0),
5635
})
5736
// Cleanup
5837
onUnmounted(() => {
59-
appTracking.components.delete(vm)
38+
globalTracking.components.delete(vm)
6039
})
6140
} else {
62-
tracking = appTracking.components.get(vm) as LoadingTracking
41+
tracking = globalTracking.components.get(vm) as LoadingTracking
6342
}
6443

6544
return {
66-
appTracking,
6745
tracking,
6846
}
6947
}
7048

7149
function track (loading: Ref<boolean>, type: keyof LoadingTracking) {
72-
const { appTracking, tracking } = getCurrentTracking()
50+
if (isServer) return
51+
52+
const { tracking } = getCurrentTracking()
7353

7454
watch(loading, (value, oldValue) => {
7555
if (oldValue != null && value !== oldValue) {
7656
const mod = value ? 1 : -1
77-
tracking[type].value += mod
78-
appTracking[type].value += mod
57+
if (tracking) tracking[type].value += mod
58+
globalTracking[type].value += mod
7959
}
8060
}, {
8161
immediate: true,
8262
})
8363

8464
onBeforeUnmount(() => {
8565
if (loading.value) {
86-
tracking[type].value--
87-
appTracking[type].value--
66+
if (tracking) tracking[type].value--
67+
globalTracking[type].value--
8868
}
8969
})
9070
}

0 commit comments

Comments
 (0)