Building a Progressive Todo Web App with Vuetify, Vuex and GraphQL
TL;DR
Build a progressive todo app with Vuetify, Vuex, VueApollo and integrate GraphQL APIs using Hasura GraphQL Engine.
Instant setup. App Source Code -> vuetify-vuex-todo-graphql
Tech Stack
This progressive web app uses the following frameworks/servers
- Vue.js with Vuetify for Material Design UI, Vuex for state management, VueApollo for making GraphQL queries
- Hasura GraphQL Engine to get instant GraphQL APIs over Postgres
Vuetify Framework
Vuetify is a semantic component framework for Vue. It is built according to Google's Material Design Spec and has intuitive properties without complex classes and markup.
In this app, we make use of Vuetify components like VGrid, VCard, VList, VTextField, VBtn among a bunch of available reusable components.
The progressive todo web app is a fork of davidgaroro/vuetify-todo-pwa which uses
- Vuetify for the TodoMVC UI with material design
- Vuex for state management
Here's how the todo app looks like with Vuetify's material design components:
We added vue-apollo to this app and configured ApolloClient to make GraphQL queries for storing and managing the todos in the database. We will use Hasura to get instant GraphQL APIs.
Hasura + vue-apollo
Hasura is an open-source engine that gives you realtime GraphQL APIs on new or existing Postgres databases, with built-in support for stitching custom GraphQL APIs and triggering webhooks on database changes.
We will integrate Hasura GraphQL APIs with this todo app.
Deploy Hasura to Hasura Cloud
Once we have Hasura deployed, we can configure the frontend to make GraphQL queries. We add all modules required to configure ApolloClient.
npm install --save vue-apollo graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag
Note: You can also use apollo-boost, if you don't need fine grained control over configuration
We define ApolloClient in src/apollo.js
file in the todo app,
import Vue from 'vue'
import VueApollo from 'vue-apollo'
import { ApolloClient } from 'apollo-client'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
const httpLink = new HttpLink({
// You should use an absolute URL here
uri: 'https://myapp.hasura.app/v1/graphql'
})
// Create the apollo client
export const apolloClient = new ApolloClient({
link: httpLink,
cache: new InMemoryCache(),
connectToDevTools: true
})
const apolloProvider = new VueApollo({
defaultClient: apolloClient
})
// Install the vue plugin
Vue.use(VueApollo)
export default apolloProvider
We need to just configure Hasura GraphQL Engine endpoint in the httpLink
and import this apolloProvider in main.js
and add it to the Vue instance like this:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import apolloProvider from './apollo'
import './registerServiceWorker'
import './vuetify'
Vue.config.productionTip = false
new Vue({
router,
store,
apolloProvider,
render: h => h(App)
}).$mount('#app')
Once this is configured, the apolloClient can be imported and used across the app.
We define the GraphQL queries/mutations and trigger them in Vuex store.
For example, to fetch all the todos, we define a simple query to fetch todos sorted by latest id.
const todoQuery = gql`{
todos(order_by: [{id: desc}]) {
id
text
is_completed
}
}`
and in our actions, we make this query using apolloClient and invoke the mutation handler using commit which will update the state.
const actions = {
async fetchTodos ({ commit }) {
const { data } = await apolloClient.query({query: todoQuery})
commit('fetchTodos', data.todos)
},
}
Note that we are making use of async, await which makes the syntax cleaner.
Let's define a GraphQL mutation to insert a new todo.
const todoMutation = gql`
mutation insert_todos($text: String!) {
insert_todos(objects: [{text: $text}]) {
affected_rows
returning {
id
text
is_completed
}
}
}`
This mutation accepts a $text
variable and inserts it into the todos table.
Similarly we define GraphQL mutations for adding/updating/deleting todos and we define actions to make the mutation and update the state in the Vuex store.
Progressive Web App
This todo app is a PWA and comes with boilerplate setup for
- App manifest
- Service worker
- Workbox options - Cache Google Fonts
which can be configured to get a Lighthouse score of 100.
Todo App Source Code
I have put together the app with complete GraphQL integration so that you can get started quickly and extend it further!
Check it out on github.
Note that this app doesn't have any user authentication yet and its currently a demo to integrate GraphQL queries/mutations with Vuetify + Vuex with Hasura.
Take it for a spin and let us know what you think. If you have any questions or run into any trouble, feel free to reach out to us on twitter, github or on our discord server.