In this tutorial we will implement a shop that retrieves items from an eCommerce server using Vue.js. Therefore, ensure you have a running eCommerce server. However, this tutorial will use an eCommerce CMS to create a ready-to-use eCommerce server. We will use the open-source medusa cms to create a basic eCommerce server and demonstrate how to use Nuxt to create a basic eCommerce app. You can skip the medusa setup if you have a working primary eCommerce server.
To proceed with the tutorial it is recommended to have:
Node.js installed and ready to use.
Basic knowledge of working with JavaScript and Vue.
Ensure that you have the medusa-cli
installed:npm install @medusajs/medusa-cli -g
Proceed to your preferred hosting directory and set up a new medusa project from there:medusa new local-medusa-server --seed
The --seed
command populates some test data once the setup is done. The option is crucial for this case since we will display the test data on the frontend.
Proceed to the newly created folder and start your medusa server:
1 2
cd local - medusa - server medusa develop
Launch Postman and send a GET request to http://localhost:9000/store/products
. At this point, you should receive a similar response as shown below:
From your terminal on your preferred directory, initialize the application by running the following command:
npx create-nuxt-app nuxtjs-storefront
On the upcoming prompts, select the options below:
Feel free to change the package manager from npm to yarn.
When the installation process is done, proceed to the newly created folder:cd nuxtjs-storefront
Finally, test the development server using:npm run dev
From http://localhost:3000
, the following default page will be loaded:
We will set up the components:
Product Card
Create a ProductCard.vue
file inside the components
folder. Add the following view:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
<template> /* create a flexbox grid using these elements of predefined classes */ <div class="col-12 col-md-3 mt-3 mb-3"> /* each product will be contained inside a card */ <div class="card"> <nuxt-link :to="`/products/{item.id}`"> /* process the image data for each product */ <img class="card-img-top" :src="item.thumbnail" style="height:150px" alt="Card image cap"> /* display the product content */ <div class="card-body"> /* Add a header to display the detailed product title */ <h5 class="card-title">{{ item.title }}</h5> /* Add a paragraph to display the text info on the product price range */ <p class="card-text">From {{ lowestPrice.amount }} {{ lowestPrice.currency_code }} </p> </div> </nuxt-link> </div> </div> </template >
Add the following in the JavaScript section:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<script>
export default {
name: "ProductCard",
props: {// props for the product object
item: {
type: Object,
}
},
computed: { // compute the product prices and price info
lowestPrice() {
const lowestPrice = this.item.variants.reduce((acc, curr) => { // Get the lowest price
return curr.prices.reduce((lowest, current) => {
if (lowest.amount > current.amount) {
return current
}
return lowest
})
}, { amount: 0 });
// the price and the currency code
return lowestPrice || { amount: 10, currency_code: 'EUR' };
}
}
}
</script>
To start off, we will need to install the Axios package. Therefore, close the running development server and run the following:npm i -s axios
Following installation, we will be required to configure a specific port through which the application will run. This is because Nuxt.js changes ports each time you restart the development server.
To maintain one port during your application development, add the following line after the SSR
configuration on your project’s nuxt.config.js
file:
1
2
3
server: {
port: 3333
},
Now the application will run on port 3333
every time.
Additionally, we will configure the URL of the application on the local medusa server.
To configure it on the local medusa server, on the project root directory, in the .env file, add the following line:
STORE_CORS=http://localhost:3333
With that change, restart the development server.
On the Nuxt application, under pages, edit the index.vue file as follows:
The view:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
<template> <div> <div class="row"> /* arrange all the displayed cards*/ <div class="col-md-12"> /* A dummy text header above the displayed cards */ <h4 class="text-center mt-5 mb-5">All Products</h4> </div> </div> /* display the cards for all products */ <div v-if="products.length"> <div class="row"> /* Render the card component to display the products*/ <ProductCard v-for="product in products" :key="product.id" :item="product" /> </div> </div> </div> </template>
The JS:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<script>
/* import the Axios library to process the data from the server on the client */
import Axios from 'axios';
export default {
name: 'ProductsIndex',
data() {
// Display some dummy content
return {
products: [{ // Dummy to display while loading
id: 1,
title: 'Dummy Product',
thumbnail: 'ADD AN IMAGE URL TO LOAD AS DUMMY WHILE WAITING FOR THE SERVER IMAGE',
variants: [{ prices: [{ amount: 100, currency_code: 'eur' }] }]
}]
}
},
async fetch() { // Fetching the products from Medusa server
try {
const { data: { products } } = await Axios.get('http://localhost:9000/store/products');
this.products = products
} catch (e) {
console.log('An error occured', e)
}
}
}
</script>
With the above change, ensure that the development server is started. At this point, you can now view the following items from your application:
On the pages
directory, create a products
directory. Inside the products
directory, create an _id.vue
file. _id
to imply dynamic.
The view section:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
<template> /* This view will display the individual product details */ <div class="mt-10 mb-10"> <div class="row"> /* we need to display all the available images for each product */ <img v-for="image in product.images" :key="image.id" width="150" alt="" :src="image.url" class="cursor-pointer" @click="imageToShow = image.id"> </div> <div class="row"> /* Arrange how to display the textual details, i.e., title, price, description */ <div class="col-md-12 mb-10 mt-10"> <h1 class="font-semibold text-3xl"> {{ product.title }} </h1> <p class="font-light"> {{ product.description }} </p> <p class="font-light"> From {{ lowestPrice.amount/100 }} {{ lowestPrice.currency_code.toUpperCase() }} </p> </div> </div> </div> </template>
The JS section:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<script>
/* import the Axios library to process the data from the server on the client */
import Axios from 'axios';
export default {
name: 'ProductDetail',
// set up the data to load on the client by default
data() {
return {
// dummy to display while loading data from the server
showDetails: false,
imageToShow: 'default_image',
product: {
id: 1,
title: 'Medusa Coffee Mug',
description: 'Every programmer\'s best friend.',
thumbnail: '',
variants: [{ prices: [{ amount: 0, currency_code: 'EUR' }] }],
images: [
{ id: 'default_image', url: 'ADD AN IMAGE URL TO LOAD AS DUMMY WHILE WAITING FOR THE SERVER IMAGE' },
{ id: 'another_image', url: 'ADD AN IMAGE URL TO LOAD AS DUMMY WHILE WAITING FOR THE SERVER IMAGE' }
]
}
}
},
computed: {
lowestPrice() { // Getting the lowest price
const lowestPrice = this.product.variants.reduce((acc, curr) => {
return curr.prices.reduce((lowest, current) => {
if (lowest.amount > current.amount) {
return current
}
return lowest
})
}, { amount: 0 })
return lowestPrice || { amount: 10, currency_code: 'usd' }
},
},
async fetch() { // Fetching from Medusa Server
try {
const { data: { product } } = await Axios.get(`http://localhost:9000/store/products/{this.$route.params.id}`)
this.product = product
this.imageToShow = this.product.images[0].id
} catch (e) {
// Log an error message in case the client fails to reach the server
console.log('The server is not responding')
}
}
}
</script>
Ensure that your development server is up and running. When you click on one product, you should be redirected to a page similar to the one below:
And these you have a basic eCommerce application. You can go ahead and try to implement other eCommerce store functionalities.