Build a JamStack food ordering application with Strapi, Gridsome and Snipcart (2)
Ekene Eze (Kenny)
Posted on December 13, 2020
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. Afterwards, we will set up some components, pages and layouts to get the application ready.
Table of Contents:
- Part 1 - Generating a Strapi app and creating products
- Part 2 - Setting up a Gridsome project
- Part 3 - Consuming products with Gridsome and GraphQL
- Part 4 - Creating single product views with Gridsome templates
- Part 5 - Implementing cart and checkout with Snipcart
- 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 to 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 <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:
<!-- 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-comnerce 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 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!
Posted on December 13, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.