Introduction
This is a short post about my small library.
Apollo Client is a library for GraphQL. Apollo Link is an interface to extend Apollo Client.
Typically, you would initialize apollo client like this.
import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { HttpLink } from 'apollo-link-http';
const cache = new InMemoryCache();
const link = new HttpLink({ uri });
const client = new ApolloClient({
cache: cache,
link: link,
});
I want to define the link in another file and lazy load it, because it is not an HttpLink but a complicated large link.
How to use
We use dynamic imports for this.
Let’s assmume we have link.js
file that exports an apollo link.
It’d be nice to dynamic import it.
import { lazy } from 'apollo-link-lazy';
const link = lazy(() => import('./link'));
import()
returns a promise, but there’s no await
.
How is this possible?
How to implement
Interestingly, Apollo Link is asynchronous by nature. However, it’s not promise based. It has observable interface.
So, all you need is to covert a promise into an observable.
Here’s the code.
import { ApolloLink, fromPromise, toPromise, Observable } from 'apollo-link';
export const lazy = (factory) => new ApolloLink(
(operation, forward) => fromPromise(
factory().then((resolved) => {
const link = resolved instanceof ApolloLink ? resolved : resolved.default;
return toPromise(link.request(operation, forward) || Observable.of());
}),
),
);
Luckily, apollo-client exports fromPromise
and toPromise
utility functions. Hence, it can be implemented so easily.
A little trick here is to support both ApolloLink promises and default exports.
Demo
I developed this code as a library.
https://github.com/dai-shi/apollo-link-lazy
You can install it and use it. It supports TypeScript.
Here’s also a demo in codesandbox.
https://codesandbox.io/s/github/dai-shi/apollo-link-lazy/tree/master/examples/02_typescript
Closing notes
As my motivation was code splitting, supporting default exports like React.lazy was actually enough. Because it also supports direct promises, we can use it for any async initialization like the following.
import { lazy } from 'apollo-link-lazy';
const link = lazy(async () => {
// await ...
return new ApolloLink(...);
});
I hope this may help other developers who try lazy loading of apollo links.