Skip to content
πŸš€πŸŒ› Use the Launch Platform πŸ‘©β€πŸš€πŸ‘¨β€πŸš€
Branch: master
Clone or download
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.circleci chore: update gh-pages deploy script Mar 5, 2019
.github/ISSUE_TEMPLATE
docs
packages
scripts
.codeclimate.yml Refactors to monorepo Jan 7, 2019
.eslintignore
.eslintrc.json
.gitignore
LICENCE.md Initial commit 🍰 May 27, 2018
README.md docs: update build status badge Feb 28, 2019
commitlint.config.js
husky.config.js
lerna.json
logo.png
logo.sketch
nodemon.json
package-lock.json
package.json
tsconfig.json

README.md

Rocket Ship in Angle Brackets

πŸš€ Apollo Elements πŸ‘©β€πŸš€

πŸš€ Custom elements meet Apollo GraphQL 🌜

πŸ‘©β€πŸš€ It's one small step for a dev, one giant leap for the web platform! πŸ‘¨β€πŸš€

Maintained with Lerna Contributions Welcome Build Status Test Coverage Demo Online

πŸ““ Contents

πŸ€– Demo

#leeway is a progressive web app that uses lit-apollo to make it easier for you to avoid doing actual work. Check out the source repo for an example of how to build apps with Apollo Elements. The demo includes:

  • SSR
  • Code Splitting
  • Aggressive minification, including lit-html template literals
  • CSS-in-CSS ( e.g. import shared from '../shared-styles.css';)
  • GQL-in-GQL ( e.g. import query from './my-component-query.graphql';)
  • GraphQL Subscriptions over websocket

Lighthouse Scores: 98 (performance), 100 (accessibility), 93 (best practises), 100 (SEO), 12/12 (PWA)

πŸ“¦ Packages

Apollo Elements offers packages based on a variety of underlying web component authoring libraries. You can pick the one that suits your project in order to keep your app sizes small.

πŸ”₯ lit-apollo

These base classes extend from LitElement, so you can quickly get up and running creating declarative front-ends with Apollo GraphQL.

npm i -S @apollo-elements/lit-apollo
<!-- index.html -->
<script type="module" src="app.bundle.js"></script>
<script nomodule src="app.bundle.system.js"></script>
<apollo-app>
  <script type="application/graphql">
    query {
      helloWorld {
        greeting
        name
      }
    }
  </script>
</apollo-app>
// app.js
import gql from 'graphql-tag'
import { ApolloQuery, html } from '@apollo-elements/lit-apollo';
import { client } from './apollo-client';
import { render } from ''

customElements.define('apollo-app', class ApolloApp extends ApolloQuery {
  render() {
    const { data, error, loading } = this;
    return (
        loading ? html`<what-spin></what-spin>`
      : error ? html` <h1>😒 Such Sad, Very Error! 😰</h1> <div>${error.message}</div>`
      : html`<div>${data.helloWorld.greeting}, ${helloWorld.name}</div>`
    );
   }
});

πŸ‘©β€πŸ”¬ gluon

These base classes extend from GluonElement, a simplified wc library that uses lit-html for templating while keeping component state and lifecycle concerns 'close to the metal'.

npm i -S @apollo-elements/gluon
import gql from 'graphql-tag'
import { ApolloQuery, html } from '@apollo-elements/gluon';
import { client } from './apollo-client';

customElements.define('apollo-app', class ApolloApp extends ApolloQuery {
  get template() {
    const { data, error, loading } = this;
    return (
        loading ? html`<what-spin></what-spin>`
      : error ? html` <h1>😒 Such Sad, Very Error! 😰</h1> <div>${error.message}</div>`
      : html`<div>${data.helloWorld.greeting}, ${helloWorld.name}</div>`
    );
   }
});

πŸ¦„ hybrids

A set of objects you can roll into your hybrids to make it easier to connect to your Apollo cache.

npm i -S @apollo-elements/hybrids
import { ApolloQuery, queryFactory, define, html } from '@apollo-elements/hybrids';
import gql from 'graphql-tag';

export const ConnectedElement = {
  ...ApolloQuery,
  query: queryFactory(gql`query { hello }`),
  render: ({data}) => html`<div>${data.hello}</div>`
};

define('connected-element', ConnectedElement);

🧱 polymer

These custom elements fire polymer-style *-changed events when the Apollo cache updates their state. They extend directly from HTMLElement so they're small in size, and their notifying properties make them perfect for use in Polymer templates.

npm i -S @apollo-elements/polymer
// app.js
import { client } from './apollo-client.js'
import '@apollo-elements/polymer/apollo-query.js';
window.__APOLLO_CLIENT__ = client
import { PolymerElement, html } from '@polymer/polymer';
import '@apollo-elements/polymer/apollo-query.js';
import '@polymer/paper-card/paper-card.js';

customElements.define('my-app', class MyTemplate extends PolymerElement {
  static get template() {
    return html`
    <apollo-query data="{{data}}" variables="[[variables]]">
      <script type="application/graphql">
        query User($id: ID!)
          user(id: $id) {
            name
            picture
          }
        }
      </script>
    </apollo-query>

    <paper-card heading="[[data.name]]" image="[[data.picture]]"></paper-card>
    `;
  }

  static get properties() {
    return {
      variables: {
        type: Object,
        value: () => ({id: ''});
      }
    }
  }

  async connectedCallback() {
    super.connectedCallback();
    const { id = '' } = await getToken();
    this.variables = { id };
  }
}

🍸 mixins

These custom element class mixins give you all the features you need to connect your components to your Apollo cache without imposing a specific component library.

npm i -S @apollo-elements/mixins
import { ApolloQueryMixin } from '@apollo-elements/mixins/apollo-query-mixin.js';

customElements.define('vanilla-query', class VanillaQuery extends ApolloQueryMixin(HTMLElement) {
  get data() {
    return this.__data;
  }

  set data(data) {
    this.__data = data;
    this.shadowRoot.innerText = `${data.helloWorld.greeting}, ${data.helloWorld.name}`;
  }  
});

πŸ—ž 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:

import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';

export default {
  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: 'system',
    sourcemap: true,
  }],

  plugins: [

    // REQUIRED to roll apollo-client up
    resolve({
      browser: true,
      jsnext: true,
      module: true,
    }),

    commonjs({
      namedExports: {
        // Necessary to roll apollo-link-state up.
        // until graphql-anywhere 5.0
        'graphql-anywhere/lib/async': ['graphql'],
        // Needed to roll up apollo-cache-persist
        'apollo-cache-persist': ['persistCache']
      }
    }),

  ]
}

Alternatively, you might bundle and export your Apollo client separately, then import it into your browser-friendly component modules.

😎 Cool Tricks

πŸ“œ Inline Query Scripts

You can provide a GraphQL query string in your markup by appending a GraphQL script element to your connected element, like so:

<apollo-app>
  <script type="application/graphql">
    query {
      helloWorld {
        name
        greeting
      }
    }
  </script>
</apollo-app>

πŸ‘·β€β™‚οΈ Maintainers

apollo-elements is a community project maintained by Benny Powers.

Contact me on Codementor

You can’t perform that action at this time.