Build a High-Performing Ecommerce with Svelte and Medusa Backend
Tags: svelte, javascript, medusa, ecommerce
Published: 2023-02-21 11:32:39

## Introduction

Online shopping, referred to as ecommerce or electronic commerce, involves purchasing and selling goods and services. The ease of use and security of online transactions has made them increasingly popular among individuals and businesses. However, setting up an ecommerce site is not a simple task. This process requires delivering excellent customer service, processing orders efficiently, and storing customer data.

In this tutorial, you will learn how to build a performant ecommerce site using [Medusa](https://github.com/medusajs/medusa) and [Svelte](https://svelte.dev/).

The Svelte ecommerce tutorial source code is readily available on [GitHub](https://github.com/femakin/Best-Store).

Here is a brief preview of the application. 

![https://dev-to-uploads.s3.amazonaws.com/uploads/articles/it63nlrgsbver6w05lux.gif](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/it63nlrgsbver6w05lux.gif)

## What is Svelte?

[Svelte](https://svelte.dev/tutorial/basics) is a tool that helps you create fast web applications. It works similarly to other JavaScript frameworks like React and Vue, which make it easy to build interactive user interfaces.

However, Svelte has an advantage in converting your app into ideal JavaScript during development rather than interpreting the code at runtime.

You don't experience the performance cost of implementation or a delay when your application first loads. You can use Svelte to build your entire app or add it to an existing codebase. You can also create standalone components that work anywhere without the additional burden of working with a traditional framework.

## What is Medusa?

[Medusa](https://docs.medusajs.com/) is an open source Node.js-based [composable commerce](https://medusajs.com/blog/composable-commerce/) engine that offers a flexible and modular solution for ecommerce businesses. Its architecture consists of three essential components: the Medusa server, the admin dashboard, and the storefront.

It includes many powerful features, such as currency support, product configurations, multi-currency support, and the ability to process manual orders.

Medusa also provides essential ecommerce components like the headless server, the admin, and the storefront as building blocks for an ecommerce stack. With the Medusa storefront, you can build ecommerce stores for any platform as Android, iOS, and the web.

## Prerequisites

To follow along, be sure you have the following:

- Basic knowledge of [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
- [Node.js](https://nodejs.org/en/) ( v16+) installed
- [Npm](https://www.npmjs.com/) (v8+) installed

## Setup

### Medusa server installation

To install Medusa on your computer, follow these steps:

Install Medusa CLI by running the following command in your terminal:

```bash

npm install @medusajs/medusa-cli -g
```

Now create a new Medusa server by running the following command:

```bash
medusa new my-medusa-store --seed
```

Using the `--seed` flag, the database is populated with demo data that serves as a starting point for the ecommerce store.

Start the Medusa server by running the following command in the ecommerce-store-server directory:

```bash
cd my-medusa-store
medusa develop
```

You can now use a tool like Postman or a browser to test it out.

Open your browser and go to the URL `localhost:9000/store/products`

If you find something like this in the browser, your connection to the Medusa server is working. Otherwise, review all the steps and ensure nothing is missing.

![https://res.cloudinary.com/practicaldev/image/fetch/s--NUoLM-9e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6s6kc31skpgjsjso9b23.png](https://res.cloudinary.com/practicaldev/image/fetch/s--NUoLM-9e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6s6kc31skpgjsjso9b23.png)

### Medusa Admin Installation

In this section, you will install the Medusa Admin. The Medusa Admin provides many e-commerce features, including managing Return Merchandise Authorization (RMA) flows, store settings, order management, and product management from an interactive dashboard. You can learn more about Medusa admin and its features in this [User Guide](https://docs.medusajs.com/user-guide/).

Here are the steps you will need to follow to set up your Medusa admin dashboard.

- Clone the Admin GitHub repository by running:

```bash
git clone https://github.com/medusajs/admin medusa-admin
```

- Change to the newly created directory by running:

```bash
cd medusa-admin
```

- Install the necessary dependencies by running:

```bash
npm install
```

- Test it out by navigating into the directory holding your Medusa admin and run:

```bash
npm run start
```

The admin runs by default on port `7000`. You can access the administration page at `localhost:7000`. You should see a login page like this one: 

![https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7nsr3vitrb24elw95p36.png](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7nsr3vitrb24elw95p36.png)

Using the `--seed` option when setting up Medusa will create a fake admin account for you. The email is `admin@medusa-test.com` and the password is `supersecret`. With the Medusa admin account, you can manage your store's products and collections, view orders, manage products, and configure your store and regions.

You can edit or create products through the Medusa admin.

![https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wr8bob9yl6x71mjv0aos.png](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wr8bob9yl6x71mjv0aos.png)

### Create and Set Up A Svelte Project

The next step is to create and set up a new [Svelte](https://svelte.dev/) project for the ecommerce project. This Svelte commerce will use [SvelteKit](https://kit.svelte.dev/) since it is the recommended setup method.

To create a new SvelteKit project, run the command below:

```javaScript
npm create svelte@latest svelte-eCommerce
```

The command above creates a new Svelte project.

![https://res.cloudinary.com/practicaldev/image/fetch/s--3DGXDL2t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ehdxq8zdmwk0nk5anm32.png](https://res.cloudinary.com/practicaldev/image/fetch/s--3DGXDL2t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ehdxq8zdmwk0nk5anm32.png)

During installation, there will be prompts for several optional features, such as `ESLint` for code linting and `Prettier` for code formatting. Make sure you select the same option as shown in the image.

The next step is to run the following command:

```bash
cd svelte-eCommerce
npm install
npm run dev
```

This code sets up and runs a development server for a Svelte project. Here's what each line does:

1. `cd svelte-eCommerce` changes the current directory to the project directory.
2. You install dependencies by running `npm install`.
3. Running the development server via `npm run dev` starts the project's development environment. This will compile the project and start a local server, allowing you to view and test the project in your browser.

### Setup of Tailwind CSS

You can style this Svelte ecommerce site using Tailwind CSS. Follow this [guide on Setting up Tailwind CSS in a SvelteKit project](https://tailwindcss.com/docs/guides/sveltekit) in your `svelte-eCommerce` directory.

## Install Dependencies

Navigate into your `svelte-eCommerce`  directory and install the below dependencies

```javaScript
npm i axios svelte-icons-pack sweetalert2
```

This command installs three npm packages: axios, svelte-icons-pack, and sweetalert2.

- **`axios`** is a popular JavaScript library that provides a simple API for making HTTP requests to a server. It works in the browser and Node.js environments and is often used to send and receive data from web APIs.
- **`svelte-icons-pack`** is a package of icons for use with the Svelte framework. This package provides a collection of icons that can be easily used in Svelte applications.
- **`sweetalert2`** is a JavaScript library for creating beautiful, responsive, and customizable alert dialogs. It is often used to provide feedback to users or prompt them for input in web applications.

## Medusa with Svelte Storefront

You start building the Svelte ecommerce app here. 

### Change Svelte Port

In the `svelte-eCommerce/vite.config.js` file, replace the existing code with the code below

```javaScript
import { sveltekit } from '@sveltejs/kit/vite';

/** @type {import('vite').UserConfig} */
const config = {
	plugins: [sveltekit()],
	server: {
		port: 8000,
		strictPort: false,
	},
};

export default config;

```

The configuration object specifies the following options:

1. The **`server`** option specifies the port that the development server should listen on (8000) and whether the server should only listen on that exact port or allow any available port (**`strictPort: false`**).

> By default, the Medusa server allows connections for the storefront on port `8000`.
> 

### Create a Base URL Environment Variable

Creating an environment file to store your base URL can make switching between development and production environments a breeze. It keeps sensitive information, such as API keys, separate from your codebase.

Create a `.env` file in the `svelte-eCommerce` directory with the following content:

```
VITE_API_BASE_URL="http://localhost:9000"
```

The `BASE_URL` environment variable is the URL of your Medusa server.

### Create Utility Function

In the `src` directory, create a folder with the name `util`. This folder will contain the `sharedload` function for the products. The `sharedload` function, located in this directory, is responsible for retrieving data from an `API` and is designed to be reusable throughout the project where necessary.

In the `src/util/shared.js` file, paste the code below:

```javaScript
// @ts-nocheck

export const getProducts = async () => {
  try {
const productres = await fetch(`${import.meta.env.VITE_API_BASE_URL}/store/products/`);
    const productdata = await productres.json();
    const products = productdata?.products;
    return {
      products: products,
    };
  } catch (error) {
    console.log("Error: " + error);
  }
};
```

The preceding code exports a `getProducts` function that gets data from an API. A list of products is requested using the fetch API. This results in the API response providing the product list. Finally, the function returns an object with the list of products as a property. Notice how you use the `BASE_URL` defined in the `.env` file.

## Store Components

It's now time to create a reusable component to display products.

The `Header`, the `Footer,` and the `Products` all fall under this section. Each of these components will appear on a different page of your storefront.

### Components Directory

In the `src` directory, create a folder with the name `components`. It is the directory that will contain all the reusable components for the products.

### Navbar Component

In the `src` directory, create the file `src/components/Navbar.svelte` and add the following code:

```javaScript
<script>
  export let productId;
  import Icon from "svelte-icons-pack/Icon.svelte";
  import AiOutlineShoppingCart from "svelte-icons-pack/ai/AiOutlineShoppingCart";
</script>

<div>
  <div class="fixed z-50 bg-white topNav w-full top-0 p-3 md:bg-opacity-0">
    <div class="max-w-6xl relative flex mx-auto flex-col md:flex-row">
      <a href="#/" class="md:hidden absolute top-1 right-14">
        <div class="relative">
          <div class="relative">
            <Icon src="{AiOutlineShoppingCart}" />
            {#if productId?.length >= 1}
            <div
              class="absolute px-1 bg-red-400 -top-1 -right-1 rounded-full border-2 border-white text-white"
              id="cart"
              style="font-size: 10px"
            >
              {productId?.length}
            </div>
            {/if}
          </div>
        </div>
      </a>

      <div class="flex-grow font-bold text-lg">
        <a href="/">
          <span>Best Store</span>
        </a>
      </div>
      
      <div class="menu hidden md:flex flex-col md:flex-row mt-5 md:mt-0 gap-16">
        <div class="flex flex-col md:flex-row gap-12 capitalize">
          <div class="text-red-400 font-bold border-b border-red-400">
            <a href="/"> home</a>
          </div>
          <div class="text-red-400 font-bold border-b border-red-400">
            <a href="/products">products</a>
          </div>
        </div>
        <div class="flex gap-12">
          <a href="#/" class="hidden md:block">
            <div class="relative">
              <Icon src="{AiOutlineShoppingCart}" />
              {#if productId?.length >= 1}
              <div
                class="absolute px-1 bg-red-400 -top-1 -right-1 rounded-full border-2 border-white text-white"
                id="cart"
                style="font-size: 10px"
              >
                {productId?.length}
              </div>
              {/if}
            </div>
          </a>
        </div>
      </div>
    </div>
  </div>
</div>
```

The code above is the head section component that renders a navigation bar at the top of the page. Home, products, and a shopping cart icon are all displayed in the navigation bar. If the shopping cart has ordered items, a badge will appear on the icon showing the number of items in the cart.

The navigation bar is hidden on small screens and appears as a dropdown menu on larger screens. The component also includes logic for handling key presses and clicks on the links and the shopping cart icon.

### Footer Component

In the `src` directory, create the file `src/components/Footer.svelte` and add the following code: 

```javaScript
<div>
  <div>
    <div class="bg-red-400 py-32 PX-4">
      <div class="max-w-6xl gap-6 mx-auto grid grid-cols-1 md:grid-cols-9">
        <div class="md:col-span-3 py-3 space-y-4">
          <div class="text-2xl font-bold text-gray-100">Best Store</div>
          <div class="text-gray-300 w-60 pr-0">
            At best store, we offer top-quality Hoddies, Joggers, Shorts and a
            variety of other items. We only sell the best grade of products.
          </div>
        </div>
        <div class="md:col-span-2 py-3 space-y-4">
          <div class="text-2xl font-bold text-gray-100">Information</div>
          <div class="text-gray-300 w-60 space-y-2 pr-0">
            <div class="">About Us</div>
            <div class="">Career</div>
          </div>
        </div>
        <div class="md:col-span-2 py-3 space-y-4">
          <div class="text-2xl font-bold text-gray-100">Our Services</div>
          <div class="text-gray-300 w-60 space-y-2 pr-0">
            <div class="">Clothing</div>
            <div class="">Fashion</div>
            <div class="">Branding</div>
            <div class="">Consultation</div>
          </div>
        </div>
        <div class="md:col-span-2 py-3 space-y-4">
          <div class="text-2xl font-bold text-gray-100">Contact Us</div>
          <div class="text-gray-300 w-60 space-y-2 pr-0">
            <div class="">+234 070-000-000</div>
            <div class="">care@best.com</div>
            <div class="">Terms & Privacy</div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
```

The code above is the bottom section component that renders a footer at the bottom of the page. The footer contains information about the Svelte store, its services, and its contact details. The footer will be used later.

## Store Pages

Now, you have to create pages for your Svelte ecommerce storefront. 

Upon creating a new project in Svelte, it comes with some default files, including [+page.svelt](https://kit.svelte.dev/docs/routing#page-page-svelte) and [+page.js](https://kit.svelte.dev/docs/routing#page-page-js)

### +page.svelte

A `+page.svelte` component defines a page of your application. By default, pages are rendered both on the server ([SSR](https://kit.svelte.dev/docs/glossary#ssr)) for the initial request and in the browser ([CSR](https://kit.svelte.dev/docs/glossary#csr-and-spa)) for subsequent navigation.

### +page.js

Often, a page must load some data before it can be rendered. For this, we add a `+page.js` (or `+page.ts,`  if you're TypeScript-inclined) module that exports a load function:

In the `src/routes` directory, replace the content in the files `src/routes/+page.svelte` with the content below.

### Homepage

In the `src/routes/+page.svelte` file, replace its content with this:

```javaScript
<script>
  // @ts-nocheck

  import Footer from "../components/Footer.svelte";
  import "../app.css";
  import Navbar from "../components/Navbar.svelte";
  import { writable, derived } from "svelte/store";

  // export let data;
  import {getProducts} from '../util/shared';

  let products;
    const productData = async () => {
        const data = await getProducts();
        products = data;
        console.log(products, 'products')
    }

  $: productData()
</script>

<div>
  <Navbar />
   <div class="mt-40">
    <div class="flex">
      <div class="flex-grow text-4xl font-extrabold text-center">
        Best Qualities You Can Trust
      </div>
    </div>
    <div class="flex">
      <div class="flex-grow text-4xl mt-12 font-extrabold text-center">
        <a
          href="/products"
          class="bg-red-400 hover:bg-red-700 text-white font-bold py-2 px-4 rounded "
          >Products</a
        >
      </div>
    </div>
    <div
      class="max-w-12xl mx-auto h-full flex flex-wrap justify-center py-28 gap-10"
    >
    {#if products}
      {#each products?.products as product, i}
        <div class="">
          <div

            class="rounded-lg shadow-lg bg-white max-w-sm"
          >
            <a
              href={`/products/${product.id}`}
              data-mdb-ripple="true"
              data-sveltekit-prefetch
              data-mdb-ripple-color="light"
            >
              <img class="rounded-t-lg" src={product.thumbnail} alt="" />
            </a>
            <div
              class="bg-red-400 py-8 relative font-bold text-gray-100 text-xl w-full flex flex-col justify-center px-6"
            >
              <div class="">{product.title}</div>
              <div class="">
                &euro; {product.variants[0].prices[0].amount / 100}
              </div>
            </div>
          </div>
        </div>
      {/each}
      {/if}
    </div>
  </div>
  <Footer />
</div>
```

The code above is the homepage of the Svelte ecommerce store. A list of products is displayed. A navigation bar appears at the top of the page, followed by a product details section and a footer at the bottom.

### Product Page

First, create a "products" folder within the `"src/routes"` directory, then create two new files, `"+page.svelte"` and `"+page.js"` within the folder.

Add the following code to the `src/routes/products/+page. Svelte` file:

```javaScript
<script>
  // @ts-nocheck

  import Navbar from "../../components/Navbar.svelte";

  // @ts-nocheck

  import "../../app.css";
	import { getProducts } from "../../util/shared";

    let products;
    const productData = async () => {
        const data = await getProducts();
        products = data;
        console.log(products, 'products')
    }

  $: productData()
</script>

<Navbar />

<div class="mt-40">
  <div class="flex">
    <div class="flex-grow text-4xl font-extrabold text-center">
      Best Qualities You Can Trust
    </div>
  </div>
  <div
    class="max-w-12xl mx-auto h-full flex flex-wrap justify-center py-28 gap-10"
  >

 {#each products?.products as product, i}
      <div class="">
        <div

          class="rounded-lg shadow-lg bg-white max-w-sm"
        >
          <a
            href={`/products/${product?.id}`}
            data-mdb-ripple="true"
            data-sveltekit-prefetch
            data-mdb-ripple-color="light"
          >
            <img class="rounded-t-lg" src={product?.thumbnail} alt="" />
          </a>
          <div
            class="bg-red-400 py-8 relative font-bold text-gray-100 text-xl w-full flex flex-col justify-center px-6"
          >
            <div class="">{product?.title}</div>
            <div class="">
              &euro; {product?.variants[0]?.prices[0]?.amount / 100}
            </div>
          </div>
        </div>
      </div>
    {/each}
  </div>
</div>
```

The previous code displays a grid of product cards. It consists of a navigation bar at the top and a grid of product cards below. Each product card includes an image, a title, and a price.

The component also includes logic for handling clicks on the product cards and taking the user to a single product page. 

The component uses the`getProducts` function to get the list of products, which it then displays in the grid using **`each`** block. Each block iterates over the list of products and creates a product card for each. 

### Single Product Page

Create a new `[id]` folder in the `src/routes/products` directory with two files `src/routes/products/[id]/+page.js` and `src/routes/products/[id]/+svelte.svelte`

`src/routes/products/[id]` folder creates a route with a *parameter*, `id`, that can be used to load data dynamically when a user requests a page like `[/products/prod_01GN6666V4R3KWPPTJ0GMD6T](http://localhost:8000/singlepage/prod_01GN6666V4R3KWPPTJ0GMD6TD4)`

In the `src/routes/products/[id]/+page.js` directory, add the following code:

```javaScript
/* eslint-disable no-unused-vars */
// @ts-ignore
export const load = async ({ fetch, params }) => {
    return {
        params
    };
}

```

> This code defines an async function called **`load`** that exports a single object containing the **`params`** object. *The load function receives an object with two properties: fetch and params.*
> 

In the `src/routes/products/[id]/+page.svelte` file, add the following code:

```javaScript

<script>
  // @ts-nocheck

  import "../../../app.css";
  import "../../../components/Navbar.svelte";
  import axios from "axios";
  import Navbar from "../../../components/Navbar.svelte";
  import Swal from 'sweetalert2'

  export let data;
  let responseData = [];
  let currentImg = 0;
  let currentSize = "S";
  let currentPrice = "";
  let variantsId = 0;
  let cartId = "";
  let variantTitle;
  let products = [];
  import { writable, derived } from "svelte/store";
  import {browser} from '$app/environment'

  export const cartDetails = writable({
  cart_id: '',
})

if (!cartId) {
    axios({
        method: 'post',
        url: `${import.meta.env.VITE_API_BASE_URL}/store/carts`,
        withCredentials: true
    })
    .then(response => {
        console.log(response.data.cart.id, 'response.data.cart.id')
        localStorage.setItem("cart_id", response.data.cart.id)
    })
    .catch(error => {
        console.log(error);
    });
}

  const fetchData = async () => {
       cartId = browser && localStorage.getItem('cart_id')
    axios
      .get(`${import.meta.env.VITE_API_BASE_URL}/store/products/${data.params.id}`).then((response) => {
        if (response.data.product) {
            responseData = response?.data
        }
      })
      .catch((err) => {
        console.log("error", err)
      });
  };

$: fetchData();

</script>

<div class="mt-40">
  <main>
  <Navbar productId={JSON.parse( browser && localStorage.getItem('cart'))} />
    <div class="py-20 px-4">
      <div class="text-white max-w-6xl mx-auto py-2">
        <div class="grid md:grid-cols-2 gap-20 grid-cols-1">
          <div>
            <div class="relative">
              <div>
                <div class="relative">

                  <img src={responseData.product?.images[currentImg]?.url} alt="no image_" />
                  <div class="absolute overflow-x-scroll w-full bottom-0 right-0 p-4 flex flex-nowrap gap-4">
                    <div class="flex w-full flex-nowrap gap-4 rounded-lg">

                    {#if responseData?.product?.images}
                    {#each responseData.product.images as img, i}

                        <div
                        key={i}
                        on:click={() => (currentImg = i)}
                        title={responseData.product.images[i].url}
                        class="w-16 h-24 flex-none"
                        on:keydown={() => (currentImg = i)}
                        >
                        <div
                            class="h-full w-full rounded-lg cursor-pointer shadow-lg border overflow-hidden"
                        >
                            <img
                            src={responseData.product.images[i].url}
                            alt=""
                            class="h-full w-full"
                            />
                        </div>
                        </div>
                    {/each}
                    {/if}
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div>
            <div class="flex md:flex-col flex-col space-y-7 justify-center">
              <div class="text-black space-y-3">
                <h2 class="font-bold text-xl text-black">{responseData?.product?.title}</h2>
                <p class="text-sm">{responseData?.product?.description}</p>
              </div>
              <div class="space-y-3">
                <div class="font-bold text-md text-black">Select Size</div>
                <div class="flex flex-row flex-wrap gap-4">
                {#if responseData?.product?.variants}
                    {#each responseData?.product?.variants as variant, i}
                    { variantTitle = variant.title.split("/")[0]}
                      <div>
                      <div
                        on:click={() => {
                           currentSize = variant?.title?.split("/")[0]
                           currentPrice = variant?.prices[0]?.amount[i]
                           variantsId = variant.id
                        }}
                        on:keydown={() => {
                           currentSize = variant?.title?.split("/")[0]
                           currentPrice = variant?.prices[0]?.amount[i]
                           variantsId = variant.id
                        }}

                        class={currentSize === variant?.title?.split("/")[0] ? 'border-purple-300 bg-red-400' : 'border-gray-100'}
                        contenteditable={false}
                      >
                        <span class="text-black text-sm">{variant?.title?.split("/")[0]}</span>
                      </div>
                    </div>
                    {/each}
                {/if}
                </div>
              </div>
              <div class="space-y-3">
                <div class="font-bold text-md text-black">Price</div>

                    {#if responseData?.product?.variants}
                        <div class="text-black">${responseData?.product?.variants.map(x => x.prices[0]?.amount)[0]}</div>
                    {/if}

              </div>

            </div>
          </div>
        </div>
      </div>
    </div>
 </main>
</div>

```

The code above fetches the product information and displays it on the page.

## Add to cart Implementation

The purpose of this section is to explain how the add-to-cart feature works.

In the `src/routes/products/[id]/+page.svelte` file, add the `addProduct` function below the `fetchData` function and the button to add the product below the Price label.

```javaScript
<script>

  // ...
const addProduct = async (data) => {
  let cartId = browser && localStorage.cart_id;

  try {
    const response = await axios.post(
      `${import.meta.env.VITE_API_BASE_URL}/store/carts/${localStorage.cart_id}/line-items`,
      {
        variant_id: data,
        quantity: 1,
        metadata: {
          size: currentSize,
        },
      }
    );

    products = [response.data?.cart];
    browser && localStorage.setItem("cart", JSON.stringify([products]));
    if (response?.data?.cart) {
      if (response?.status === 200) {
        Swal.fire({
          icon: "success",
          title: "Item Added to Cart Successfully",
          showConfirmButton: true,
        }).then((res) => {
          if (res.isConfirmed) {
            window.location.reload();
          }
        });
      }
    }
  } catch (error) {
    console.log(error);
  }
};

// ...
</script>

<div class="mt-40">
  <main>
    <!-- ... -->
    <button
      class="bg-red-400 text-white font-bold py-2 px-4 rounded-full"
      on:click={() => {
        if (variantsId === 0) {
          alert("Please select a size before adding to cart.");
        } else {
          addProduct(variantsId);
        }
      }}
    >
      Add to Cart
    </button>
    <!-- ... -->
  </main>
</div>
```

The `addProduct` function is used to add the product to the cart using the selected `variant ID`. The code then displays the product data using Svelte bindings and event listeners.

## Testing the Svelte Ecommerce

Follow the steps below to test your Svelte ecommerce:

Navigate into your Medusa server and run:

```bash
medusa develop
```

Navigate into your `svelte-eCommerce`  directory and run:

```bash
npm run dev
```

Your Svelte ecommerce storefront is now running at `localhost:8000`
To view your homepage, visit [localhost:8000](http://localhost:8000) in your browser. You should see the homepage.

![https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o4u1ruso7l1s8pghxlx2.png](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o4u1ruso7l1s8pghxlx2.png)

You can view the details of any of the products by clicking on them.

![https://dev-to-uploads.s3.amazonaws.com/uploads/articles/agchb2ddjd2h2xpa8rgx.png](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/agchb2ddjd2h2xpa8rgx.png)

Add the product to your cart by clicking the **Add to Cart** button.


![Add to cart description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tlscjlb99nps4j4c7n81.png)

## Conclusion

This tutorial demonstrates how to connect a Svelte ecommerce application to a Medusa server and implement an "Add to Cart" feature that allows customers to add items to their cart and manage its content. Other features that can be added to the application with the help of the Medusa server include a [checkout flow](https://docs.medusajs.com/advanced/storefront/how-to-implement-checkout-flow/) for placing orders and integration with a payment provider such as [Stripe](https://docs.medusajs.com/add-plugins/stripe).

The possibilities are endless when it comes to running an ecommerce store with Medusa, including but not limited to;

- Integrate a payment provider such as [PayPal](https://docs.medusajs.com/add-plugins/paypal)
- Add a product search engine to your storefront using [Meilisearch](https://docs.medusajs.com/add-plugins/meilisearch)
- Authenticate Customer using the [Authenticate Customer endpoint](https://docs.medusajs.com/api/store/#tag/Auth) that allows the authorization of customers and manages their sessions.
- Additionally, check out how to use the Authenticate Customer endpoint in this [tutorial](https://medusajs.com/blog/next.js-ecommerce-store).

> Should you have any issues or questions related to Medusa, then feel free to reach out to the Medusa team via [Discord](https://discord.com/invite/F87eGuwkTp).
>