使用Svelte和Medusa Backend建立高性能的电子商务
#javascript #svelte #ecommerce #medusa

介绍

在线购物,称为电子商务或电子商务,涉及购买和销售商品和服务。在线交易的易用性和安全性使他们在个人和企业中越来越受欢迎。但是,设置电子商务网站并不是一个简单的任务。此过程需要提供出色的客户服务,有效处理订单并存储客户数据。

在本教程中,您将学习如何使用MedusaSvelte构建表演者电子商务网站。

Svelte电子商务教程源代码可在GitHub上获得。

这是该应用程序的简要预览。

https://dev-to-uploads.s3.amazonaws.com/uploads/articles/it63nlrgsbver6w05lux.gif

什么是苗条?

Svelte是一种工具,可帮助您创建快速的Web应用程序。它与其他JavaScript框架(例如React和Vue)类似,这使得易于构建交互式用户界面。

但是,Svelte在开发期间将应用程序转换为理想的JavaScript具有优势,而不是在运行时解释代码。

当您的应用程序首次加载时,您不会经历实施成本或延迟的延迟。您可以使用Svelte构建整个应用程序或将其添加到现有代码库中。您还可以创建独立的组件,可以在任何地方工作,而无需使用传统框架的额外负担。

什么是美杜莎?

Medusa是一个开源node.js的composable commerce引擎,为电子商务业务提供了灵活而模块化的解决方案。它的架构由三个基本组件组成:Medusa服务器,管理仪表板和店面。

它包含许多强大的功能,例如货币支持,产品配置,多货币支持以及处理手动订单的能力。

美杜莎还提供基本的电子商务组件,例如Headless Server,Admin和店面作为电子商务堆栈的构建块。借助美杜莎(Medusa)店面,您可以为Android,iOS和Web的任何平台建造电子商务商店。

先决条件

要跟随,请确保您有以下内容:

设置

美杜莎服务器安装

要在计算机上安装美杜莎,请执行以下步骤:

通过在终端中运行以下命令来安装Medusa CLI:


npm install @medusajs/medusa-cli -g

现在通过运行以下命令来创建新的Medusa服务器:

medusa new my-medusa-store --seed

使用--seed标志,数据库填充了演示数据,该数据是电子商务商店的起点。

通过在电子商务服务器服务器目录中运行以下命令来启动MEDUSA服务器:

cd my-medusa-store
medusa develop

您现在可以使用邮递员或浏览器等工具进行测试。

打开浏览器,然后转到URL localhost:9000/store/products

如果您在浏览器中找到了类似的内容,则您与Medusa服务器的连接正在正常工作。否则,请查看所有步骤并确保任何内容都没有丢失。

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管理员。 Medusa管理员提供了许多电子商务功能,包括管理互动仪表板的Reporter Merchandise授权(RMA)流,商店设置,订单管理和产品管理。您可以在此User Guide中了解更多有关美杜莎管理员及其功能的信息。

这是您需要遵循的步骤来设置Medusa Admin仪表板。

  • 通过运行:
git clone https://github.com/medusajs/admin medusa-admin
  • 通过运行:更改为新创建的目录:
cd medusa-admin
  • 通过运行安装必要的依赖性:
npm install
  • 通过导航到持有Medusa管理员并运行的目录来测试它:
npm run start

管理员默认运行在port 7000上。您可以在localhost:7000上访问管理页面。您应该看到这样的登录页面:

https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7nsr3vitrb24elw95p36.png

设置美杜莎时使用â--seed选项将为您创建一个假管理帐户。电子邮件为admin@medusa-test.com,密码为supersecret。使用Medusa Admin帐户,您可以管理商店的产品和收藏,查看订单,管理产品并配置您的商店和地区。

您可以通过Medusa管理员编辑或创建产品。

https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wr8bob9yl6x71mjv0aos.png

创建并设置一个苗条的项目

下一步是为电子商务项目创建并设置一个新的Svelte项目。由于它是推荐的设置方法,因此这种苗条的商业将使用SvelteKit

要创建一个新的Sveltekit项目,请在下面运行命令:

npm create svelte@latest svelte-eCommerce

上面的命令创建了一个新的Svelte项目。

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

在安装过程中,将有一些可选功能的提示,例如for Code Linting的ESLint和用于代码格式的Prettier。确保选择与图像中所示的相同选项。

下一步是运行以下命令:

cd svelte-eCommerce
npm install
npm run dev

此代码设置并运行Svelte项目的开发服务器。这是每行的作用:

  1. cd svelte-eCommerce将当前目录更改为项目目录。
  2. 您通过运行npm install安装依赖项。
  3. 通过npm run dev运行开发服务器启动项目的开发环境。这将编译项目并启动本地服务器,使您可以在浏览器中查看和测试项目。

尾风CSS的设置

您可以使用Tailwind CSS为这个Svelte电子商务网站设计样式。在您的svelte-eCommerce目录中关注此guide on Setting up Tailwind CSS in a SvelteKit project

安装依赖项

导航到您的svelte-eCommerce目录并安装以下依赖项

npm i axios svelte-icons-pack sweetalert2

此命令安装三个NPM软件包:Axios,Svelte-Icons-Pack和SweetAlert2。

  • axios 是一个流行的JavaScript库,提供了一个简单的API,用于向服务器提出HTTP请求。它在浏览器和node.js环境中工作,通常用于从Web API发送和接收数据。
  • svelte-icons-pack 是一个与Svelte框架一起使用的图标。该软件包提供了可以轻松在Svelte应用程序中使用的图标的集合。
  • sweetalert2 是一个JavaScript库,用于创建美丽,响应和可自定义的警报对话框。它通常用于向用户提供反馈或提示他们在Web应用程序中输入。

Medusa与Svelte Storefront

您在这里开始构建Svelte电子商务应用程序。

更改Svelte端口

svelte-eCommerce/vite.config.js文件中,将现有代码替换为以下代码

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

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

export default config;

配置对象指定以下选项:

  1. server 选项指定开发服务器应在(8000)上侦听的端口,以及服务器是否只能在该确切端口上收听或允许任何可用端口( strictPort: false )。

默认情况下,Medusa服务器允许在端口8000上的店面连接。

创建基本URL环境变量

创建一个环境文件来存储您的基本URL可以使开发环境和生产环境之间的切换变得轻而易举。它保留敏感信息,例如API键,与您的代码库分开。

svelte-eCommerce目录中创建一个带有以下内容的.env文件:

VITE_API_BASE_URL="http://localhost:9000"

BASE_URL环境变量是您的Medusa服务器的URL。

创建实用程序功能

src目录中,创建一个名称util的文件夹。该文件夹将包含产品的sharedload功能。位于此目录中的sharedload函数负责从API检索数据,并在必要时设计在整个项目中可重复使用。

src/util/shared.js文件中,粘贴以下代码:

// @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);
  }
};

前面的代码导出了从API获取数据的getProducts函数。使用Fetch API请求产品列表。这导致API响应提供产品列表。最后,该函数返回带有产品列表作为属性的对象。注意如何使用.env文件中定义的BASE_URL

存储组件

现在是时候创建一个可重复使用的组件来显示产品了。

HeaderFooter,Products都属于本节。这些组件中的每一个都会出现在您的店面的不同页面上。

组件目录

src目录中,创建一个名称components的文件夹。目录将包含产品的所有可重复使用组件。

Navbar Compont

src目录中,创建文件src/components/Navbar.svelte并添加以下代码:

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

上面的代码是呈现页面顶部的导航栏的头部部分组件。主页,产品和购物车图标都显示在导航栏中。如果购物车已订购物品,则在图标上显示徽章,显示购物车中的物品数量。

导航栏隐藏在小屏幕上,并在较大屏幕上显示为下拉菜单。该组件还包括用于处理钥匙按下的逻辑和链接和购物车图标的单击。

页脚组件

src目录中,创建文件src/components/Footer.svelte并添加以下代码:

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

上面的代码是在页面底部呈现页脚的底部组件。页脚包含有关Svelte商店,其服务及其联系方式的信息。页脚将在以后使用。

存储页面

现在,您必须为Svelte电子商务店面创建页面。

在Svelte创建一个新项目后,它带有一些默认文件,包括+page.svelt+page.js

+page.svelte

a +page.svelte组件定义了您的应用程序页面。默认情况下,在服务器(SSR)的初始请求和浏览器(CSR)中呈现页面上的页面。

+page.js

通常,一个页面必须加载一些数据才能渲染。为此,我们添加一个导出负载函数的模块:

src/routes目录中,将文件中的内容替换为src/routes/+page.svelte中的内容。

主页

src/routes/+page.svelte文件中,用以下内容替换其内容:

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

上面的代码是Svelte电子商务商店的主页。显示产品列表。页面顶部出现了一个导航栏,然后是产品详细信息部分和底部的页脚。

产品页面

首先,在"src/routes"目录中创建一个“产品”文件夹,然后在文件夹中创建两个新文件,"+page.svelte""+page.js"

将以下代码添加到src/routes/products/+page. Svelte文件:

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

以前的代码显示了产品卡的网格。它由顶部的导航栏和下面的产品卡片组成。每张产品卡都包含图像,标题和价格。

该组件还包括用于处理产品卡上点击的逻辑,并将用户带到单个产品页面。

组件使用thegetProducts函数获取产品列表,然后使用 each 块在网格中显示。每个块均在产品列表上迭代,并为每个产品创建产品卡。

单产品页面

src/routes/products目录中创建一个新的[id]文件夹,其中两个文件src/routes/products/[id]/+page.jssrc/routes/products/[id]/+svelte.svelte

src/routes/products/[id]文件夹使用a parameter id)创建一条路由,当用户请求像[/products/prod_01GN6666V4R3KWPPTJ0GMD6T](http://localhost:8000/singlepage/prod_01GN6666V4R3KWPPTJ0GMD6TD4)

的页面时,可以动态加载数据。

src/routes/products/[id]/+page.js目录中,添加以下代码:

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

此代码定义一个称为 load 的异步函数,该函数导出包含 params 对象的单个对象。 加载函数接收一个具有两个属性的对象:获取和参数。

src/routes/products/[id]/+page.svelte文件中,添加以下代码:


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

上面的代码获取产品信息并将其显示在页面上。

添加到购物车实施

本节的目的是解释添加到车的功能如何工作。

src/routes/products/[id]/+page.svelte文件中,在fetchData功能下方添加addProduct函数,并在价格标签下方添加产品的按钮。

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

使用选定的variant ID使用addProduct功能将产品添加到购物车中。然后,代码使用Svelte绑定和事件听众显示产品数据。

测试Svelte电子商务

按照以下步骤测试您的苗条电子商务:

导航到您的Medusa服务器并运行:

medusa develop

导航到您的svelte-eCommerce目录并运行:

npm run dev

您的Svelte电子商务店面现在正在localhost:8000
要查看主页,请在浏览器中访问localhost:8000。您应该看到主页。

https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o4u1ruso7l1s8pghxlx2.png

您可以通过单击它们来查看任何产品的详细信息。

https://dev-to-uploads.s3.amazonaws.com/uploads/articles/agchb2ddjd2h2xpa8rgx.png

单击添加到购物车按钮。

Add to cart description

结论

本教程演示了如何将Svelte电子商务应用程序连接到MEDUSA服务器并实现“添加到购物车”功能,该功能使客户可以将项目添加到购物车并管理其内容。可以在Medusa服务器的帮助下添加到应用程序中的其他功能包括checkout flow,用于与Stripe这样的付款提供商放置订单和集成。

在使用美杜莎(Medusa)经营电子商务商店时,可能性是无穷无尽的,包括但不限于;

  • 整合了诸如PayPal之类的付款提供商
  • 使用Meilisearch将产品搜索引擎添加到您的店面
  • 使用允许客户授权并管理其会议的Authenticate Customer endpoint对客户进行身份验证。
  • 此外,请查看如何在此tutorial中使用身份验证的客户端点。

如果您有与美杜莎有关的任何问题或问题,然后随时通过Discord与Medusa团队联系。