Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Solving Problems with Modern Tooling

Solving Problems with Modern Tooling

Our job as developers is solving problems. When we use tooling, we're standing on a mountain of solved problems that allows us to focus on the unique task at hand.

In this annotated postmortem, learn how using Craft CMS 3.4's built-in GraphQL combined with the modern frontend tooling Vue.js, Vuex, and Axios allowed us to improve the UX of a client project.

Related articles:

Post-Mortem: Outbreak Database

Using the Craft CMS "headless" with the GraphQL API

Andrew Welch

March 04, 2020
Tweet

More Decks by Andrew Welch

Other Decks in Technology

Transcript

  1. // Home page import { OutbreakMixins } from '../mixins/outbreak.js'; import

    '@trevoreyre/autocomplete-vue/dist/style.css' import { createStore } from '../store/store.js'; // App main const main = async() => { // Async load the vue module const [ Vue, VueSmoothScroll ] = await Promise.all([ import(/* webpackChunkName: "vue" */ 'vue'), import(/* webpackChunkName: "vue" */ 'vue2-smooth-scroll'), ]); const store = await createStore(Vue.default); Vue.default.use(VueSmoothScroll.default); // Create our vue instance const vm = new Vue.default({ render: (h) => { return h('search-form'); }, mixins: [OutbreakMixins], store, components: { 'search-form': () => import(/* webpackChunkName: "searchform" */ '../../vue/SearchForm.vue'), }, }); return vm; }; home.js
  2. import * as actions from './actions.js'; import * as mutations

    from './mutations.js'; import * as getters from './getters.js'; // Store main export const createStore = async(Vue) => { const { default: Vuex } = await import(/* webpackChunkName: "vuex" */ 'vuex'); Vue.use(Vuex); return new Vuex.Store({ state: { csrf: null, gqlToken: null, outbreakSlug: null, outbreakDetail: null, states: null, vehicles: null, searchForm: null, organisms: null, outbreaks: null, months: null, countries: null, }, getters, mutations, actions, modules: {} }); }; store.js
  3. <template> <Autocomplete v-bind="autocompleteProps" v-on="autocompleteEvents" > <template v-slot:result="{ result, props }">

    <li v-bind="props"> {{ result[titleField] }} </li> </template> </Autocomplete> </template> Autocomplete.vue
  4. gql.js // Configure the GraphQL api endpoint export const configureGqlApi

    = (url, token) => ({ baseURL: url, headers: { 'X-Requested-With': 'XMLHttpRequest', ...(token && { 'Authorization': `Bearer ${token}` }), } }); // Execute a GraphQL query by sending an XHR to our api endpoint export const executeGqlQuery = async(api, query, variables, callback) => { // Execute the GQL query try { const response = await api.post('', { query: query, variables: variables }); if (callback && response.data.data) { callback(response.data.data); } // Log any errors if (response.data.errors) { console.error(response.data.errors); } } catch (error) { console.error(error); } };
  5. export const outbreaksQuery = (additionalParams) => { let queryAdditionalParams =

    ''; let entryAdditionalParams = ''; additionalParams.forEach((item) =>{ queryAdditionalParams += `, $${item.fieldName}: [QueryArgument]`; entryAdditionalParams += `, ${item.fieldName}: $${item.fieldName}`; }); return ` query outbreaksQuery($needle: String!${queryAdditionalParams}) { entries(section: "outbreaks", search: $needle${entryAdditionalParams}) { title, url, slug, ...on outbreaks_outbreaks_Entry { summary, beginningDate, vehicles { title }, organisms { title }, tags { title } } } } `; queries.js