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

Avatar for Andrew Welch

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