From 70762e57b25f7641a3033e7ac82f5f0c8c9e84b9 Mon Sep 17 00:00:00 2001 From: Sid Chang <37400982+SidStraw@users.noreply.github.com> Date: Wed, 28 Feb 2024 23:46:04 +0800 Subject: [PATCH] feat: [SPMVP-6868] Lazy load subscriber client in karbon (#335) Co-authored-by: DanSnow --- packages/karbon/package.json | 3 ++- packages/karbon/src/module.ts | 5 +++- .../karbon/src/runtime/api/siteTemplate.ts | 9 +++++++ packages/karbon/src/runtime/api/track.ts | 9 ++++--- .../composables/storipress-base-client.ts | 19 ++++++++++++-- .../runtime/composables/storipress-client.ts | 17 ++++++++++--- .../runtime/composables/subscriber-client.ts | 25 ++++++++++++++++--- .../src/runtime/plugins/paywall.client.ts | 6 +++-- .../src/runtime/plugins/storipress-client.ts | 4 +-- yarn.lock | 1 + 10 files changed, 80 insertions(+), 18 deletions(-) diff --git a/packages/karbon/package.json b/packages/karbon/package.json index 80fbd802..1914b577 100644 --- a/packages/karbon/package.json +++ b/packages/karbon/package.json @@ -147,6 +147,7 @@ "find-cache-dir": "^5.0.0", "fs-extra": "^11.2.0", "graphql": "^16.7.1", + "graphql-tag": "^2.12.6", "hookable": "^5.5.3", "js-yaml": "^4.1.0", "jszip": "^3.10.1", @@ -232,4 +233,4 @@ "access": "public" }, "gitHead": "8df1f4d5837a7e2ddbff6cc79f5fec256c34a394" -} \ No newline at end of file +} diff --git a/packages/karbon/src/module.ts b/packages/karbon/src/module.ts index e8704ecb..c9e8fece 100644 --- a/packages/karbon/src/module.ts +++ b/packages/karbon/src/module.ts @@ -478,7 +478,10 @@ const karbon = defineNuxtModule({ flags.lazySearch ? './runtime/plugins/storipress-search-client-noop' : './runtime/plugins/storipress-search-client', - './runtime/plugins/storipress-client', + { + src: './runtime/plugins/storipress-client', + mode: 'server', + }, './runtime/plugins/debug-info.client', './runtime/plugins/track.client', './runtime/plugins/iframely.client', diff --git a/packages/karbon/src/runtime/api/siteTemplate.ts b/packages/karbon/src/runtime/api/siteTemplate.ts index 6a5252b0..cabdf718 100644 --- a/packages/karbon/src/runtime/api/siteTemplate.ts +++ b/packages/karbon/src/runtime/api/siteTemplate.ts @@ -6,6 +6,7 @@ import consola from 'consola' import type { ZodError } from 'zod' import { z } from 'zod' import { fromZodError } from 'zod-validation-error' +import { ApolloClient, ApolloLink, HttpLink, InMemoryCache, Observable } from '@apollo/client/core/index.js' import { createStoripressBaseClient } from '../composables/storipress-base-client' export enum TemplateType { @@ -61,6 +62,13 @@ export async function uploadSiteTemplate(key: string) { return data.uploadSiteTemplate } +const apollo = { + ApolloClient, + ApolloLink, + HttpLink, + InMemoryCache, + Observable, +} async function createStoripressClient() { const { loadNuxtConfig } = await import('@nuxt/kit') const { @@ -69,6 +77,7 @@ async function createStoripressClient() { const { apiHost, apiToken, clientId } = assertConfig(storipress) return createStoripressBaseClient( + apollo, () => ({ authorization: `Bearer ${apiToken}`, }), diff --git a/packages/karbon/src/runtime/api/track.ts b/packages/karbon/src/runtime/api/track.ts index f1018fa1..e71c3e19 100644 --- a/packages/karbon/src/runtime/api/track.ts +++ b/packages/karbon/src/runtime/api/track.ts @@ -1,5 +1,5 @@ -import { gql } from '@apollo/client/core/index.js' -import { useStorage } from '@vueuse/core' +import { gql } from 'graphql-tag' +import { until, useStorage } from '@vueuse/core' import { useSubscriberClient } from '../composables/subscriber-client' type JSONValue = string | number | boolean | JSONObject | Array @@ -34,7 +34,10 @@ export async function track(input: TrackSubscriberActivityInput) { try { const client = useSubscriberClient() - const { data } = await client.mutate({ + await until(client).toBeTruthy({ timeout: 2000 }) + if (!client.value) return false + + const { data } = await client.value.mutate({ mutation: TrackMutation, variables: { input, diff --git a/packages/karbon/src/runtime/composables/storipress-base-client.ts b/packages/karbon/src/runtime/composables/storipress-base-client.ts index dbf58e5c..e64c0c15 100644 --- a/packages/karbon/src/runtime/composables/storipress-base-client.ts +++ b/packages/karbon/src/runtime/composables/storipress-base-client.ts @@ -1,5 +1,11 @@ -import type { Operation } from '@apollo/client/core/index.js' -import { ApolloClient, ApolloLink, HttpLink, InMemoryCache, Observable } from '@apollo/client/core/index.js' +import type { + ApolloClient, + ApolloLink, + HttpLink, + InMemoryCache, + Observable, + Operation, +} from '@apollo/client/core/index.js' import { setContext } from '@apollo/client/link/context/index.js' import { fetch } from 'cross-fetch' import { withHttps } from 'ufo' @@ -78,11 +84,20 @@ export interface CreateBaseClientInput { name?: string } +export interface Apollo { + ApolloClient: typeof ApolloClient + ApolloLink: typeof ApolloLink + HttpLink: typeof HttpLink + InMemoryCache: typeof InMemoryCache + Observable: typeof Observable +} export function createStoripressBaseClient( + apollo: Apollo, getHeaders: () => Record, uri: string, opt: CreateBaseClientInput = {}, ) { + const { ApolloClient, ApolloLink, HttpLink, InMemoryCache, Observable } = apollo const tapClient = new ApolloLink((operation, forward) => { const id = crypto.randomUUID() diff --git a/packages/karbon/src/runtime/composables/storipress-client.ts b/packages/karbon/src/runtime/composables/storipress-client.ts index 51b4e1f1..33880e5b 100644 --- a/packages/karbon/src/runtime/composables/storipress-client.ts +++ b/packages/karbon/src/runtime/composables/storipress-client.ts @@ -1,11 +1,22 @@ -import type { ApolloClient, NormalizedCacheObject } from '@apollo/client/core/index.js' +import type { NormalizedCacheObject } from '@apollo/client/core/index.js' import { useStorage } from '@vueuse/core' import { createContext } from 'unctx' +import { ApolloClient, ApolloLink, HttpLink, InMemoryCache, Observable } from '@apollo/client/core/index.js' +import type { Apollo } from './storipress-base-client' import { createStoripressBaseClient, getStoripressConfig } from './storipress-base-client' +const apollo = { + ApolloClient, + ApolloLink, + HttpLink, + InMemoryCache, + Observable, +} + export function createStoripressClient() { const storipress = getStoripressConfig() return createStoripressBaseClient( + apollo, () => ({ authorization: `Bearer ${storipress?.apiToken}`, }), @@ -26,7 +37,7 @@ export function useStoripressClient() { return client } -export function createSubscriberClient() { +export function createSubscriberClient(apollo: Apollo) { const authorization = () => { const token = useStorage('storipress-token', '') return { @@ -34,7 +45,7 @@ export function createSubscriberClient() { } } - return createStoripressBaseClient(authorization, getUri(), { name: 'storipress-subscriber' }) + return createStoripressBaseClient(apollo, authorization, getUri(), { name: 'storipress-subscriber' }) } export function getUri() { diff --git a/packages/karbon/src/runtime/composables/subscriber-client.ts b/packages/karbon/src/runtime/composables/subscriber-client.ts index 48f1f070..01c98336 100644 --- a/packages/karbon/src/runtime/composables/subscriber-client.ts +++ b/packages/karbon/src/runtime/composables/subscriber-client.ts @@ -1,6 +1,25 @@ -import { useNuxtApp } from '#imports' +import { createSubscriberClient } from './storipress-client' +import { ref } from '#imports' export function useSubscriberClient() { - const { $storipress } = useNuxtApp() - return $storipress.subscriberClient + type SubscriberClient = ReturnType + const subscriberClient = ref() + + if (process.server) return subscriberClient + + async function createClient() { + const { ApolloClient, ApolloLink, HttpLink, InMemoryCache, Observable } = await import( + '@apollo/client/core/index.js' + ) + const apollo = { + ApolloClient, + ApolloLink, + HttpLink, + InMemoryCache, + Observable, + } + subscriberClient.value = createSubscriberClient(apollo) + } + createClient() + return subscriberClient } diff --git a/packages/karbon/src/runtime/plugins/paywall.client.ts b/packages/karbon/src/runtime/plugins/paywall.client.ts index 3c6d87e0..6dc6bd98 100644 --- a/packages/karbon/src/runtime/plugins/paywall.client.ts +++ b/packages/karbon/src/runtime/plugins/paywall.client.ts @@ -1,4 +1,4 @@ -import { useEventBus, useStorage } from '@vueuse/core' +import { until, useEventBus, useStorage } from '@vueuse/core' import { once } from 'remeda' import '@storipress/builder-component/dist/style.css' import { waitFirstInteractive } from '../utils/defer-load' @@ -87,11 +87,13 @@ export default defineNuxtPlugin((_nuxtApp) => { query, }, } + await until(client).toBeTruthy({ timeout: 2000 }) + if (!client.value) return paywall.value = mountPaywall({ el: '#paywall', router: routerLink, - client, + client: client.value, favicon: runtimeConfig.public.storipress.paywall.logo, logo: paywallLogo, token, diff --git a/packages/karbon/src/runtime/plugins/storipress-client.ts b/packages/karbon/src/runtime/plugins/storipress-client.ts index 2a31081f..451d4075 100644 --- a/packages/karbon/src/runtime/plugins/storipress-client.ts +++ b/packages/karbon/src/runtime/plugins/storipress-client.ts @@ -1,4 +1,4 @@ -import { createStoripressClient, createSubscriberClient, storipressClientCtx } from '../composables/storipress-client' +import { createStoripressClient, storipressClientCtx } from '../composables/storipress-client' import { storipressConfigCtx } from '../composables/storipress-base-client' import { defineNuxtPlugin, useRuntimeConfig } from '#imports' @@ -7,7 +7,6 @@ export default defineNuxtPlugin((_nuxtApp) => { storipressConfigCtx.set({ ...runtimeConfig.public.storipress, ...runtimeConfig.storipress }) const apolloClient = createStoripressClient() - const subscriberClient = createSubscriberClient() storipressClientCtx.set(apolloClient, true) @@ -15,7 +14,6 @@ export default defineNuxtPlugin((_nuxtApp) => { provide: { storipress: { client: apolloClient, - subscriberClient, }, }, } diff --git a/yarn.lock b/yarn.lock index ff4798b3..2f1c3809 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2992,6 +2992,7 @@ __metadata: fs-extra: "npm:11.2.0" globby: "npm:14.0.1" graphql: "npm:^16.7.1" + graphql-tag: "npm:^2.12.6" hookable: "npm:^5.5.3" js-yaml: "npm:^4.1.0" jszip: "npm:^3.10.1"