lit-apollo
🚀 Custom element base classes & mixins that connect to your Apollo cache 🌜
👩🚀 It's one small step for a dev, one giant leap for the web platform! 👨🚀
📓 Contents
- 🔧 Installation
- 👩🚀 Usage
- 🍹 Mixins
- 📖 Subscriptions
- ☝️ Notifying Elements for Polymer Templates
- 📦 Bundling
- 😎 Cool Tricks
🔧 Installation
lit-apollo
is distributed through npm
the node package manager. To install a copy of the latest version of lit-apollo
in your project's node_modules
directory, first Install npm on your system, then run the following command in your project's root directory:
npm install --save lit-apollo
👩🚀 Usage
You'll need to bundle the Apollo library with a tool like Rollup. See instructions for bundling Apollo for advice on how to build a working Apollo client. After that, typical usage involves importing the base class and extending from it to define your component:
;;;; // Create the Apollo Clientconst client = cache link ; // Compute graphql documents statically for performanceconst query = gql` query { helloWorld { name greeting } }`; const childQuery = gql` query { child { foo bar } }`; { const data error loading = this; const helloWorld = {} } = data || {} return loading ? html` ` : error ? html` 😢 Such Sad, Very Error! 😰 ` : html` , ` ; { super; thisclient = client; thisquery = query; }}; customElements
NOTE: By default, components will only render while loading or after receiving data or an error. Override the shouldUpdate
method to control when the component renders.
{ return changedProps || thisloading != null || thisdata || thiserror ;}
🍹 Mixins
You don't need to use LitElement
base class for your components if you use the mixins. You just have to handle the rendering part on your own: e.g. for a query component, you'd implement yourself what happens after data
, error
, loading
, or networkStatus
change.
Here's an example that uses GluonElement
instead of LitElement
.
;; GluonElement { this__data = data; this; } { return this__data; } { return html` `; }
📖 Subscriptions
You can create components which use GraphQL subscriptions to update over websockets.
;;;;;; const messageTemplate = html` : `; const subscription = gql` subscription { messageSent { date message user } }` /** * <chat-query> * @customElement * @extends LitElement */ { return html` `; } { super; thisclient = client; thisonSubscriptionData = thisonSubscriptionData; thisquery = gql` query { messages { date message user } }`; } { const query = this; const messages = client; const data = messages: ...messages messageSent ; client; } customElements;
Alternatively, you can call subscribeToMore
on a query component with a subscription document
and an updateQuery
function to have your component update it's data based on subscription results:
{ if !subscriptionDatadata return prev; return ...prev messages: ...prevmessages subscriptionDatadatamessageSent ;} { const updateQuery = this; this;}
See this simple chat-app demo which demonstrates building custom elements which subscribe to a GraphQL server over websockets: Chat App Demo
☝️ Notifying Elements for Polymer Templates
If you want data elements which notify about changes to their properties,
import them from lit-apollo/elements
:
;;
You could then use the <apollo-query>
element inside a polymer template:
[[data.user.picture]] [[data.user.name]]
Always make sure that any required variables (e.g. id
here) are defined in variables
before adding your query element, or else an error will be thrown.
If you would like to control which properties notify, set notifyingProps
to an array of property names:
console // ["data", "error", "loading", "networkStatus"] // excludes `loading` and `networkStatus`queryElementnotifyingProps = 'data' 'error';
📦 Bundling
Since Apollo client cannot be imported directly into the browser, you must transpile and bundle apollo-client in order to use it in your app. We recommend using Rollup for this. Your rollup.config.js
might look something like this:
// rollup 0.62.0;; experimentalCodeSplitting: true experimentalDynamicImport: true input: 'src/components/app-shell/app-shell.js' 'src/components/app-view1/app-view1.js' 'src/components/app-view2/app-view2.js' 'src/components/app-view404/app-view404.js' output: dir: 'build/modern' format: 'es' sourcemap: true dir: 'build/nomodule' format: 'amd' sourcemap: true plugins: // REQUIRED to roll apollo-client up
You may also need to patch certain versions of some apollo packages in order for them to play nicely with standard tools. See the chat app demo for examples of how to patch packages.
An alternative to bundling your whole app is to bundle and export your apollo-client separately, then import it into your browser-friendly component modules.
😎 Cool Tricks
📜 Inline Query Scripts
You can also provide a graphql query string in your markup by appending a graphql script element to your connected element, like so:
🏦 Managing the Cache
When defining components that issue graphql mutations, you may want to take control over how and when Apollo updates it's local cache. You can do this with the onUpdate
property on elements that extend from ApolloMutation
;;;; { return html` `; } customElements; const mutation = gql` mutation($id: ID!) { MyMutation(id: $id) { mutationResult } }`; /** * Example update function which reads a cached query result, merges * it with the mutation result, and then writes it back to the cache. */const updateFunc = { // ostensibly looks up the cached object for mutationResult const query = MyQuery; const variables = id: 1 ; const cached = cache; const changed = ; // mergeMutationResult is a made-up function. const mutationResult = ; return cache;}; const template = html` `; ;
⌚️ Asynchronous Client
In some cases, you may want to wait for your ApolloClient to do some initial asynchronous setup before rendering your components' DOM. In that case, you can import a promise of a client and wait for it in connectedCallback
: