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. nystudio107 / @nystudio107
    by Andrew Welch
    devMode podcast / devMode.fm
    Solving
    Problems
    with
    Modern
    Tooling

    View Slide

  2. Problems

    View Slide

  3. Math
    Problems

    View Slide

  4. Word
    Problems

    View Slide

  5. Relationship
    Problems

    View Slide

  6. And yet…

    View Slide

  7. That’s What We Do

    View Slide

  8. We Solve Other
    People’s Problems

    View Slide

  9. We Solve Other
    People’s Problems

    View Slide

  10. We Solve Other
    People’s Problems

    View Slide

  11. Client Problems,
    AMIRITE?

    View Slide

  12. Standing on a
    Mountain

    View Slide

  13. Standing on a
    Mountain of
    Solved Problems
    Standing on a
    Mountain

    View Slide

  14. This Old Site

    View Slide

  15. This Old Site

    View Slide

  16. This Old Site
    Custom website
    built in Cake PHP

    View Slide

  17. This Old Site
    Database of food-
    borne illnesses
    dating back to 1993

    View Slide

  18. This Old Site
    (They just didn’t
    want it to look like
    it was from 1993)

    View Slide

  19. View Slide

  20. Project Goals

    View Slide

  21. Project Goals
    Make the outbreak
    database easier to
    maintain for the
    content authors

    View Slide

  22. Project Goals
    Make the frontend
    easier to use by
    researchers and
    journalists

    View Slide

  23. Project Goals
    Modernize the
    website underpinnings

    View Slide

  24. Potentially provide
    an API to allow other
    parties to access the
    database directly
    Project Goals

    View Slide

  25. Modern Tooling

    View Slide

  26. Vue.js
    Modern Tooling

    View Slide

  27. Modern Tooling
    Vuex

    View Slide

  28. Modern Tooling
    Axios

    View Slide

  29. GraphQL
    Modern Tooling

    View Slide

  30. Modern Tooling
    Tailwind CSS

    View Slide

  31. Modern Tooling
    Craft CMS

    View Slide

  32. Shiny New Site

    View Slide

  33. View Slide

  34. Eliminate the SERP

    View Slide

  35. // 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

    View Slide

  36. 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

    View Slide

  37. Auto-Complete Component

    View Slide


  38. v-on="autocompleteEvents"
    >


    {{ result[titleField] }}




    Autocomplete.vue

    View Slide

  39. 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);
    }
    };

    View Slide

  40. 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

    View Slide

  41. View Slide

  42. Live Demo??

    View Slide

  43. devMode podcast /
    devMode.fm
    nystudio107.com @nystudio107 SpeakerDeck.com/
    nystudio107

    View Slide