Build a JamStack food ordering application with Strapi, Gridsome and Snipcart (2)
Published: 2020-12-13 08:47:14

---
title: Build a JamStack food ordering application with Strapi, Gridsome and Snipcart (2)
published: true
description: This series will walk you through the processes of setting up your own food ordering application and by extension any e-commerce app using modern development tools like Strapi, Gridsome and Snipcart.
tags: 
cover_image: https://d2zv2ciw0ln4h1.cloudfront.net/uploads/Snipcart_Strapi_1_69a3c61d41.png
---

In the [first part](https://dev.to/strapi/build-a-jamstack-food-ordering-application-with-strapi-gridsome-and-snipcart-1-dlg), we walked through the process of setting up a Strapi application and creating products for our application. In this part, we will concentrate more on how to set up the Gridsome application. Afterwards, we will set up some components, pages and layouts to get the application ready. 

### Table of Contents:

1. Part 1 - [Generating a Strapi app and creating products]((https://dev.to/strapi/build-a-jamstack-food-ordering-application-with-strapi-gridsome-and-snipcart-1-dlg))
2. Part 2 - Setting up a Gridsome project 
3. Part 3 - Consuming products with Gridsome and GraphQL
4. Part 4 - Creating single product views with Gridsome templates
5. Part 5 - Implementing cart and checkout with Snipcart
6. Part 6 - Deploying the apps
Setting up a new Gridsome application.

Before we get started, here are some prerequisites:

- Node v8.0 or higher
- Working knowledge of JavaScript and Vue


### Installing Gridsome

With Node installed, you can install the Gridsome CLI by running the command below:

```bash
    yarn global add @gridsome/cli
    #OR
    npm install --global @gridsome/cli
```

Having installed the Gridsome CLI, you can use it to create a new Gridsome project by running the following command:

```bash
    gridsome create mealzers
```

The above command will create a Gridsome project named `mealzers`. Navigate into to the created project folder with:

```bash
    cd mealzers
```

And start the project development server with:

```bash
    gridsome develop
```

The project will be available for preview on the browser. Navigate to `localhost:8080` to view the app.


![](https://paper-attachments.dropbox.com/s_4C4B40BDEDEA79572FC2D1BA037986FFCAE7A1438BBE35F2740B5EBA4BA8556E_1603491680563_image.png)


There, you have a Gridsome application running on the browser in minutes. Next, let's add Vuetify for styling. 


### Setting up Vuetify

Vuetify is a UI framework built on top of Vue.js. Whenever I'm working on a Vue project, Vuetify is by default my goto UI framework for styling. It is the most popular design framework for Vue.js and it comes packaged with tons of prebuilt components. 

Amongst other things, it is mobile-first which ensures that my applications perform responsively irrespective of device or orientation. It is also simple to understand and use. Let's quickly add Vuetify to our Gridsome application by running the installation command below:

```bash
    # npm
    npm install vuetify --save
    #OR
    # yarn
    yarn add vuetify
```

Now that you've installed Vuetify, you need to register it as a plugin in your Gridsome application. You will also need to add Vuetify CSS file and a link to Google's material design icons to your app. To do that, copy the code snippet below into your project's  `main.js` file and save:


```javascript
    import Vuetify from 'vuetify'
    import 'vuetify/dist/vuetify.min.css'
    import DefaultLayout from '~/layouts/Default.vue'
    
    export default function (Vue, { appOptions, head }) {
      head.link.push({
        rel: 'stylesheet',
        href: 'https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css',
      })
      
      head.link.push({
        rel: 'stylesheet',
        href: 'https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900',
      });
      Vue.use(Vuetify)
      const opts = {}; //opts includes, vuetify themes, icons, etc.
      appOptions.vuetify = new Vuetify(opts);
      
      // Set default layout as a global component
      Vue.component('Layout', DefaultLayout)
    }

```

Next, you need to whitelist Vuetify in Webpack so that your application can build properly. To do that, first, you need to install the `webpack-node-externals` plugin with the command below:

```bash
    npm install webpack-node-externals --save-dev
``` 

Then replace your project's `gridsome.server.js` file with the snippet below :


```javascript
    const nodeExternals = require('webpack-node-externals')
    
    module.exports = function (api) {
      api.chainWebpack((config, { isServer }) => {
        if (isServer) {
          config.externals([
            nodeExternals({
              allowlist: [/^vuetify/]
            })
          ])
        }
      })
    
      api.loadSource(store => {
        // Use the Data store API here: https://gridsome.org/docs/data-store-api
      })
    }
```

Great! so we've just added Vuetify to our Gridsome project. But don't take my words for it. Let's quickly run the Gridsome app again and see if we observe any changes in the UI:


![](https://paper-attachments.dropbox.com/s_4C4B40BDEDEA79572FC2D1BA037986FFCAE7A1438BBE35F2740B5EBA4BA8556E_1603574198794_image.png)


And we do. The presence of Vuetify in this application has already impacted the existing style which is why the app looks all jumbled up. Next, let's create a default layout that will cater to the applications Header and Footer needs. Let's start with the footer. 


### Footer component

Create a `src/components/Footer.vue` file and add the following snippet to it:

```javascript

     <!-- src/components/Footer.vue -->
    <template>
      <v-footer absolute padless>
        <v-card flat tile class="orange lighten-1 white--text text-center">
          <v-card-text>
            <v-btn v-for="icon in icons" :key="icon" class="mx-4 white--text" icon>
              <v-icon size="24px">{{ icon }}</v-icon>
            </v-btn>
          </v-card-text>
          <v-card-text class="white--text pt-0">
            Phasellus feugiat arcu sapien, et iaculis ipsum elementum sit amet.
            Mauris cursus commodo interdum. Praesent ut risus eget metus luctus
            accumsan id ultrices nunc. Sed at orci sed massa consectetur dignissim a
            sit amet dui. Duis commodo vitae velit et faucibus. Morbi vehicula
            lacinia malesuada. Phasellus feugiat arcu sapien, et iaculis ipsum
            elementum sit amet. Mauris cursus commodo interdum. Praesent ut risus
            eget metus luctus accumsan id ultrices nunc. Sed at orci sed massa
            consectetur dignissim a sit amet dui. Duis commodo vitae velit et
            faucibus. Morbi vehicula lacinia malesuada.
          </v-card-text>
          <v-divider></v-divider>
          <v-card-text class="white--text">
            {{ new Date().getFullYear() }} — <strong>Mealsers</strong>
          </v-card-text>
        </v-card>
      </v-footer>
    </template>
    <script>
    export default {
      data: () => ({
        icons: ["mdi-facebook", "mdi-twitter", "mdi-linkedin", "mdi-instagram"],
      }),
    };
    </script>

```


Here, we defined a basic Vuetify footer component with a bunch of dummy text and social media icons. The icons are made available through the material design icons link we added in the applications `main.js` file. 


### Default layout

Next, open the `src/layouts/Default.vue` file and update it with the code snippet below:

```javascript 
     <!-- src/layouts/Default.vue -->
      <template>
        <v-app>
          <div>
            <v-app-bar
              absolute color="orange"
              dark shrink-on-scroll
              scroll-target="#scrolling-techniques-2"
            >
              <v-app-bar-nav-icon class="mt-5" @click="drawer = !drawer">
              </v-app-bar-nav-icon>
              <g-link
                class="mt-7 ml-3"
                style="text-decoration: none; color: inherit"
                to="/"
                >Mealzers</g-link
              >
              <v-spacer></v-spacer>
              <v-btn outlined rounded dense class="mt-5 mr-3">
                <g-link style="text-decoration: none; color: inherit" to="/shop/"
                  >Shop</g-link
                >
              </v-btn>
              <v-btn outlined rounded dense class="mt-5 mr-3">
                <g-link style="text-decoration: none; color: inherit" to="/support/"
                  >Support</g-link
                >
              </v-btn>
              <v-text-field
                v-model="searchText" @click:clear="searchText = ''"
                placeholder="Search products ..." class="mt-5 mr-4"
                style="max-width: 350px" prepend-inner-icon="mdi-magnify"
                clearable outlined rounded dense hide-details
              />
              <v-btn class="mt-4 mr-4 ml-4 snipcart-checkout" icon>
                <v-icon>mdi-cart</v-icon>
                <span class="snipcart-total-items"></span>
                <span class="snipcart-total-price">{{ this.totalPrice }}</span>
              </v-btn>
            </v-app-bar>
            <v-navigation-drawer v-model="drawer" absolute bottom temporary>
              <v-list nav dense>
                <v-list-item-group
                  v-model="group"
                  active-class="deep-purple--text text--accent-4"
                >
                  <v-list-item>
                    <v-list-item-title>
                      <v-btn elevation="0" rounded>
                        <g-link
                          style="text-decoration: none; color: orange"
                          to="/shop/"
                          >Shop</g-link
                        >
                      </v-btn>
                    </v-list-item-title>
                  </v-list-item>
                  <v-list-item>
                    <v-list-item-title>
                      <v-btn elevation="0" rounded dense>
                        <g-link
                          style="text-decoration: none; color: orange"
                          to="/support/"
                          >Support</g-link
                        >
                      </v-btn>
                    </v-list-item-title>
                  </v-list-item>
                </v-list-item-group>
              </v-list>
            </v-navigation-drawer>
            <v-sheet
              id="scrolling-techniques-2"
              class="overflow-y-auto"
              max-height="600"
            >
              <v-container style="height: 120px"></v-container>
            </v-sheet>
            <slot />
          </div>
          <Footer />
        </v-app>
      </template>

```

In the template section above, we've defined a basic Vuetify header that features a navigation drawer and a few buttons to switch pages. We are using the custom Gridsome `<g-link>` tag to handle navigation between pages. 

At the moment, we have a shop page, and a support page, which we'll create later in the next part of this series. So don't bother about them just yet. Next, let set up the script section of the layout file above using the code snippet below:


```javascript

     <!-- src/layouts/Default.vue -->
    <script>
    import Footer from "@/components/Footer.vue";
    export default {
      components: {
        Footer,
      },
      data() {
        const drawer = false;
        const group = null;
        return {
          drawer,
          group
        };
      },
      watch: {
        group() {
          this.drawer = false;
        },
      },
    
    };
    </script>
    <static-query>
    query {
      metadata {
        siteName
      }
    }
    </static-query>
```


If you save the changes and run the application again, you should get the following output on the browser where the app is running:


![](https://paper-attachments.dropbox.com/s_4C4B40BDEDEA79572FC2D1BA037986FFCAE7A1438BBE35F2740B5EBA4BA8556E_1603581056468_image.png)


At the moment, the buttons and navigation on the app will lead to a 404 page. This is because we haven't created the `/shop` and `/support` pages yet. We'll get to that eventually in the next part of this series, but in the meantime, let's add some Hero images to make this app look even more like an e-comnerce application. 


### Hero

Next, update your `src/pages/index.vue` file with the snippet below:


```javascript

    <template>
      <Layout>
        <template>
          <v-carousel
            cycle
            height="400"
            hide-delimiter-background
            :show-arrows="false"
          >
            <v-carousel-item v-for="(image, i) in images" :key="i">
              <v-sheet height="100%">
                <v-row class="fill-height" align="center" justify="center">
                  <div class="display-3">
                    <img :src="image" />
                  </div>
                </v-row>
              </v-sheet>
            </v-carousel-item>
          </v-carousel>
          <div class="separator"></div>
        </template>
      </Layout>
    </template>
    <script>
    export default {
      metaInfo: {
        title: "Mealzers",
      },
      data() {
        return {
          images: [
            "https://bit.ly/33Ehev5",
            "https://bit.ly/33Ehev5",
            "https://bit.ly/33Ehev5",
            "https://bit.ly/33Ehev5",
          ],
        };
      },
    };
    </script>
```


Here, we define an array of 5 images and loop through them to display each one in the Vuetify `v-carousel` UI component we specified in the component template. If you save this snippet and check back on the browser, you should get an updated view like so:


![](https://paper-attachments.dropbox.com/s_4C4B40BDEDEA79572FC2D1BA037986FFCAE7A1438BBE35F2740B5EBA4BA8556E_1603582341672_ezgif.com-gif-maker.gif)



## Conclusion

We've come to the end of this part. Before we jump on to the next part, here's a quick
recap on what we've done. In the first part, we set up a Strapi application and created a bunch of products we'll sell on our store. In this part, we just set up a Gridsome application and modified the UI to get it ready. In the next part, we'll connect this application to display the products we created with Strapi using Gridsome's GraphQL data layer. See you on the next one!