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
Before we get started, here are some prerequisites:
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.
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:
1# npm
2npm install vuetify --save
3#OR
4# yarn
5yarn 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:
1import Vuetify from 'vuetify'
2import 'vuetify/dist/vuetify.min.css'
3import DefaultLayout from '~/layouts/Default.vue'
4
5export default function (Vue, { appOptions, head }) {
6 head.link.push({
7 rel: 'stylesheet',
8 href: 'https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css',
9 })
10
11 head.link.push({
12 rel: 'stylesheet',
13 href: 'https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900',
14 });
15 Vue.use(Vuetify)
16 const opts = {}; //opts includes, vuetify themes, icons, etc.
17 appOptions.vuetify = new Vuetify(opts);
18
19 // Set default layout as a global component
20 Vue.component('Layout', DefaultLayout)
21}
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 :
1const nodeExternals = require('webpack-node-externals')
2
3module.exports = function (api) {
4 api.chainWebpack((config, { isServer }) => {
5 if (isServer) {
6 config.externals([
7 nodeExternals({
8 allowlist: [/^vuetify/]
9 })
10 ])
11 }
12 })
13
14 api.loadSource(store => {
15 // Use the Data store API here: https://gridsome.org/docs/data-store-api
16 })
17}
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.
Create a src/components/Footer.vue file and add the following snippet to it:
1 <!-- src/components/Footer.vue -->
2<template>
3 <v-footer absolute padless>
4 <v-card flat tile class="orange lighten-1 white--text text-center">
5 <v-card-text>
6 <v-btn v-for="icon in icons" :key="icon" class="mx-4 white--text" icon>
7 <v-icon size="24px">{{ icon }}</v-icon>
8 </v-btn>
9 </v-card-text>
10 <v-card-text class="white--text pt-0">
11 Phasellus feugiat arcu sapien, et iaculis ipsum elementum sit amet.
12 Mauris cursus commodo interdum. Praesent ut risus eget metus luctus
13 accumsan id ultrices nunc. Sed at orci sed massa consectetur dignissim a
14 sit amet dui. Duis commodo vitae velit et faucibus. Morbi vehicula
15 lacinia malesuada. Phasellus feugiat arcu sapien, et iaculis ipsum
16 elementum sit amet. Mauris cursus commodo interdum. Praesent ut risus
17 eget metus luctus accumsan id ultrices nunc. Sed at orci sed massa
18 consectetur dignissim a sit amet dui. Duis commodo vitae velit et
19 faucibus. Morbi vehicula lacinia malesuada.
20 </v-card-text>
21 <v-divider></v-divider>
22 <v-card-text class="white--text">
23 {{ new Date().getFullYear() }} — <strong>Mealsers</strong>
24 </v-card-text>
25 </v-card>
26 </v-footer>
27</template>
28<script>
29export default {
30 data: () => ({
31 icons: ["mdi-facebook", "mdi-twitter", "mdi-linkedin", "mdi-instagram"],
32 }),
33};
34</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.
Next, open the src/layouts/Default.vue file and update it with the code snippet below:
1<!-- src/layouts/Default.vue -->
2 <template>
3 <v-app>
4 <div>
5 <v-app-bar
6 absolute color="orange"
7 dark shrink-on-scroll
8 scroll-target="#scrolling-techniques-2"
9 >
10 <v-app-bar-nav-icon class="mt-5" @click="drawer = !drawer">
11 </v-app-bar-nav-icon>
12 <g-link
13 class="mt-7 ml-3"
14 style="text-decoration: none; color: inherit"
15 to="/"
16 >Mealzers</g-link
17 >
18 <v-spacer></v-spacer>
19 <v-btn outlined rounded dense class="mt-5 mr-3">
20 <g-link style="text-decoration: none; color: inherit" to="/shop/"
21 >Shop</g-link
22 >
23 </v-btn>
24 <v-btn outlined rounded dense class="mt-5 mr-3">
25 <g-link style="text-decoration: none; color: inherit" to="/support/"
26 >Support</g-link
27 >
28 </v-btn>
29 <v-text-field
30 v-model="searchText" @click:clear="searchText = ''"
31 placeholder="Search products ..." class="mt-5 mr-4"
32 style="max-width: 350px" prepend-inner-icon="mdi-magnify"
33 clearable outlined rounded dense hide-details
34 />
35 <v-btn class="mt-4 mr-4 ml-4 snipcart-checkout" icon>
36 <v-icon>mdi-cart</v-icon>
37 <span class="snipcart-total-items"></span>
38 <span class="snipcart-total-price">{{ this.totalPrice }}</span>
39 </v-btn>
40 </v-app-bar>
41 <v-navigation-drawer v-model="drawer" absolute bottom temporary>
42 <v-list nav dense>
43 <v-list-item-group
44 v-model="group"
45 active-class="deep-purple--text text--accent-4"
46 >
47 <v-list-item>
48 <v-list-item-title>
49 <v-btn elevation="0" rounded>
50 <g-link
51 style="text-decoration: none; color: orange"
52 to="/shop/"
53 >Shop</g-link
54 >
55 </v-btn>
56 </v-list-item-title>
57 </v-list-item>
58 <v-list-item>
59 <v-list-item-title>
60 <v-btn elevation="0" rounded dense>
61 <g-link
62 style="text-decoration: none; color: orange"
63 to="/support/"
64 >Support</g-link
65 >
66 </v-btn>
67 </v-list-item-title>
68 </v-list-item>
69 </v-list-item-group>
70 </v-list>
71 </v-navigation-drawer>
72 <v-sheet
73 id="scrolling-techniques-2"
74 class="overflow-y-auto"
75 max-height="600"
76 >
77 <v-container style="height: 120px"></v-container>
78 </v-sheet>
79 <slot />
80 </div>
81 <Footer />
82 </v-app>
83 </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
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:
1 <!-- src/layouts/Default.vue -->
2<script>
3import Footer from "@/components/Footer.vue";
4export default {
5 components: {
6 Footer,
7 },
8 data() {
9 const drawer = false;
10 const group = null;
11 return {
12 drawer,
13 group
14 };
15 },
16 watch: {
17 group() {
18 this.drawer = false;
19 },
20 },
21
22};
23</script>
24<static-query>
25query {
26 metadata {
27 siteName
28 }
29}
30</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.
Next, update your src/pages/index.vue file with the snippet below:
1<template>
2 <Layout>
3 <template>
4 <v-carousel
5 *cycle*
6 *height*="400"
7 *hide-delimiter-background*
8 :*show-arrows*="false"
9 >
10<v-carousel-item *v-for*="(image, i) in images" :*key*="i">
11<v-sheet *height*="100%">
12<v-row *class*="fill-height" *align*="center" *justify*="center">
13<div *class*="display-3">
14 <img :*src*="image" />
15 </div>
16 </v-row>
17 </v-sheet>
18 </v-carousel-item>
19 </v-carousel>
20<div *class*="separator"></div>
21 </template>
22 </Layout>
23</template>
24<script>
25*export* *default* {
26 metaInfo: {
27 title: "Mealzers",
28 },
29 *data*() {
30 *return* {
31 images: [
32 "https://bit.ly/33Ehev5",
33 "https://bit.ly/33Ehev5",
34 "https://bit.ly/33Ehev5",
35 "https://bit.ly/33Ehev5",
36 ],
37 };
38 },
39};
40</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:
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! https://mealzers.netlify.app
Ekene is a Developer Experience Engineer and Technical Writer. He is currently working with the Developer Experience team at Netlify where they build tools, create content, open-source repos, and demos to teach and also help developers build a better web with Netlify's products and services.