Strapi blog logo
  • Product

      Why Strapi?Content ArchitectureRoadmapIntegrationsTry live demo
      OverviewContent Types BuilderCustomizable APIMedia LibraryRoles & Permissions
      Discover Strapi Enterprise EditionDiscover our partners
  • Pricing

  • Solutions

      Static WebsitesMobile ApplicationsCorporate websitesEditorial SitesEcommerce
      Delivery HeroL'EquipeSociete GeneralePixelDustBanco International
      Discover all our user stories
  • Community

      CommunityWrite for the communityWall of LoveStrapi Conf 2021
      SlackGitHubYoutubeCommunity Forum
      Meet the Strapi Community StarsDiscover the Strapi Showcase
  • Resources

      BlogStartersNewsroomSupport
      Strapi AcademyTutorialsVideosWebinars
      The Guide to Headless CMS Strapi Community Forum
  • Docs

      InstallationConfigurationsDeploymentUpdate versionContent API
      Getting StartedContent ManagerContent-Types BuilderUsers, Roles & PermissionsPluginsSettings
      Developer DocumentationStrapi User Guide

Looking for our logo ?

Logo Brand download
Download Logo Pack
See more Strapi assets
Strapi blog logo
  • Product

    Product

    • Why Strapi?
    • Content Architecture
    • Roadmap
    • Integrations
    • Try live demo

    Features

    • Overview
    • Content Types Builder
    • Customizable API
    • Media Library
    • Roles & Permissions
    • Discover Strapi Enterprise Edition
    • Discover our partners
    Features cover

    Unlock the full potential of content management

    See all features
    Strapi Enterprise Edition

    Discover the advanced features included in Strapi Enterprise Edition.

    Get Started
  • Pricing
  • Solutions

    Solutions

    • Static Websites
    • Mobile Applications
    • Corporate websites
    • Editorial Sites
    • Ecommerce

    Stories

    • Delivery Hero
    • L'Equipe
    • Societe Generale
    • PixelDust
    • Banco International
    • Discover all our user stories
    Delivery Hero team

    Delivery Hero manages their partner portal with Strapi.

    Read their story
    turn 10 studios website

    How 1minus1 delivered a creative website for Turn10 Studios 25% faster with Strapi

    Discover their story
  • Community

    Community

    • Community
    • Write for the community
    • Wall of Love
    • Strapi Conf 2021

    Resources

    • Slack
    • GitHub
    • Youtube
    • Community Forum
    • Meet the Strapi Community Stars
    • Discover the Strapi Showcase
    Strapi Conf

    The first Strapi Global User Conference.

    Register now
    Write for the community

    Contribute on educational content for the community

    Discover the program
  • Resources

    Resources

    • Blog
    • Starters
    • Newsroom
    • Support

    Learning

    • Strapi Academy
    • Tutorials
    • Videos
    • Webinars
    • The Guide to Headless CMS
    • Strapi Community Forum
    Introducing Strapi Academy

    Everything you need to know to master Strapi.

    Go to the academy
    Strapi Repository on GitHub

    Get started with the Strapi repository

    Go to repository
  • Docs

    Developers

    • Installation
    • Configurations
    • Deployment
    • Update version
    • Content API

    User Guide

    • Getting Started
    • Content Manager
    • Content-Types Builder
    • Users, Roles & Permissions
    • Plugins
    • Settings
    • Developer Documentation
    • Strapi User Guide
    Install Strapi

    Install Strapi locally or wherever you need.

    Get Started
    Migration Guides Strapi

    Using a previous version of Strapi? Migrate to the latest.

    Read Guides
Get Started
Back to articles

Building a Jamstack Food Ordering App with Strapi, Gridsome & Snipcart 2/6

Building a Jamstack Food Ordering App with Strapi, Gridsome & Snipcart
  • Share on facebook
  • Share on linkedin
  • Share on twitter
  • Share by email
Ekene Eze

Ekene Eze

December 7, 2020

This article is a guest series by the great Ekene Eze. He’s leading the Developer Experience team at Flutterwave and wrote this blog post through the Write for the Community program.

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.

In the first part, 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. Afterward, 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 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:

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:

gridsome create mealzers

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

cd mealzers

And start the project development server with:

gridsome develop

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

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:

# 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:

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:

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

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

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:

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:

 <!-- 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:

<!-- 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 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:

 <!-- 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:

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-commerce application.

Hero

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

<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:

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 in 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!

  • Share on facebook
  • Share on linkedin
  • Share on twitter
  • Share by email

You might also be interested in...

Build a blog with Vue, Strapi and Apollo
  • Guides & Tutorials

Build a blog with Vue, Strapi and Apollo

This tutorial will show you how to build a blog using Vue for the frontend, Apollo for requesting the Strapi API and Strapi as the backend.

Maxime Castres

February 13, 2020

Announcing StrapiConf - Our First Global User Conference
  • Strapi
  • Announcement

Announcing StrapiConf - Our First Global User Conference

Announcing the first Strapi global user conference! It's a one day conference for the Strapi Community to learn, contribute, and collaborate on the future of the leading open source Headless CMS.

Victor Coisne

Victor Coisne

November 12, 2020

Building a Jamstack Food Ordering App with Strapi, Gridsome & Snipcart 3/6
  • Guides & Tutorials

Building a Jamstack Food Ordering App with Strapi, Gridsome & Snipcart 3/6

Learn how to create your own food ordering application and by extension any e-commerce app using modern development tools like Strapi, Gridsome & Snipcart. Consuming products with Gridsome and GraphQL

Ekene Eze

Ekene Eze

December 7, 2020

Unleash content.

Starters
Get Started

Strapi is the leading open-source Headless CMS. Strapi gives developers the freedom to use their favorite tools and frameworks while allowing editors to easily manage their content and distribute it anywhere.

Product

  • Why Strapi?
  • Content Architecture
  • Features
  • Enterprise Edition
  • Partner Program
  • Roadmap
  • Support
  • Try live demo
  • Changelog

Resources

  • How to get started
  • Meet the community
  • Tutorials
  • API documentation
  • GitHub repository
  • Starters
  • Strapi vs Wordpress
  • The Guide to headless CMS

Integrations

  • All integrations
  • React CMS
  • Next.js CMS
  • Gatsby CMS
  • Vue.js CMS
  • Nuxt.js CMS
  • Gridsome CMS
  • Flutter CMS
  • Hugo CMS
  • Typescript CMS

Company

  • About us
  • Blog
  • Careers
  • Contact
  • Newsroom
  • © 2021, Strapi
  • LicenseTermsPrivacy