[컴][웹] next.js commerce에서 provider 분석

커머스 넥스트 커머스 / 디버거/ 디버깅 / nextjs

next.js commerce에서 provider 분석

여기서는 이미구현된 vendure commerce provider 를 가지고 파악해 본다.

src/provider.tssrc/api/index.ts

provider.ts 와 api/index.ts 의 내용을 구현하면 되는 듯 하다.

  • <nextjs_commerce_root>\packages\vendure\src\provider.ts: Commerce Hooks에 대한 handler들을 export 한다.
  • <nextjs_commerce_root>\packages\vendure\src\api\index.ts: Commerce API 를 위한 provider 들을 export 한다.

provider 이름 추가

  • commerce-config.js에 있는 PROVIDERS 에 provider 이름 추가
  • .env.template에 provider 이름이 추가되어 있다. 여기에 넣어놓고, 나중에 .env.local등을 만들때 COMMERCE_PROVIDER에 이름을 적는다.

src/provider.ts

src/provider.ts에서 vendureProvider 를 볼 수 있는데, 이 object는 Provider type 에 match 돼야만 한다.

// <nextjs_commerce_root>\packages\vendure\src\provider.ts
//
import { handler as useCart } from './cart/use-cart'
import { handler as useAddItem } from './cart/use-add-item'
import { handler as useUpdateItem } from './cart/use-update-item'
import { handler as useRemoveItem } from './cart/use-remove-item'
import { handler as useCustomer } from './customer/use-customer'
import { handler as useSearch } from './product/use-search'
import { handler as useLogin } from './auth/use-login'
import { handler as useLogout } from './auth/use-logout'
import { handler as useSignup } from './auth/use-signup'
import { fetcher } from './fetcher'

export const vendureProvider = {
  locale: 'en-us',
  cartCookie: 'session',
  fetcher,
  cart: { useCart, useAddItem, useUpdateItem, useRemoveItem },
  customer: { useCustomer },
  products: { useSearch },
  auth: { useLogin, useLogout, useSignup },
}

export type VendureProvider = typeof vendureProvider

위에 보면 useCart 같은 handler 들이 보인다.

  • SWRHook : 이 useCart handler 들 처럼 data fetching 을 하는 handler 라면, SWRHook 을 implement해야 한다. 이 SWRHook 은 commerce/packages/commerce/src/utils/types.ts에 정의되어 있다.
  • MutationHook : useAddItem 같은 handler 처럼 mutation 을 사용하는 것이라면, MutationHook을 사용해야 한다.

어떻게 지정된 provider 이 사용되어지는가?

provider 를 정의해 놓으면, 이것과 관련해서 tsconfig.jsonpaths 추가하게 된다. @framework 라는 이름으로 지정한 provider 의 source 를 넣어주게 된다. 그래서 만들어진 provider 들을 사용하게 된다.

// /site/commerce-config.js
/**
 * This file is expected to be used in next.config.js only
 */
...

const PROVIDERS = [
  ...
  '@vercel/commerce-vendure',
  ...
]
function getProviderName() {
  return (
    process.env.COMMERCE_PROVIDER ||
    (process.env.BIGCOMMERCE_STOREFRONT_API_URL
      ? '@vercel/commerce-bigcommerce'
      : process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN
      ? '@vercel/commerce-shopify'
      : process.env.NEXT_PUBLIC_SWELL_STORE_ID
      ? '@vercel/commerce-swell'
      : '@vercel/commerce-local')
  )
}
...
function withCommerceConfig(nextConfig = {}) {
  const config = merge(
    { commerce: { provider: getProviderName() } },
    nextConfig
  )
  const { commerce } = config
  const { provider } = commerce

  ...
  // Update paths in `tsconfig.json` to point to the selected provider
  if (commerce.updateTSConfig !== false) {
    const tsconfigPath = path.join(
      process.cwd(),
      commerce.tsconfigPath || 'tsconfig.json'
    )
    const tsconfig = require(tsconfigPath)
    // The module path is a symlink in node_modules
    // -> /node_modules/[name]/dist/index.js
    const absolutePath = require.resolve(provider)
    // but we want references to go to the real path in /packages instead
    // -> packages/[name]/dist
    const distPath = path.join(path.relative(process.cwd(), absolutePath), '..')
    // -> /packages/[name]/src
    const modulePath = path.join(distPath, '../src')

    tsconfig.compilerOptions.paths['@framework'] = [`${modulePath}`]
    tsconfig.compilerOptions.paths['@framework/*'] = [`${modulePath}/*`]

    fs.writeFileSync(
      tsconfigPath,
      prettier.format(JSON.stringify(tsconfig), { parser: 'json' })
    )

    ...
  }

  return core.withCommerceConfig(config)
}

module.exports = { withCommerceConfig, getProviderName }
// tsconfig.json
{
  "compilerOptions": {
    ...
    "paths": {
      ...
      "@framework": ["..\\packages\\vendure\\src"],
      "@framework/*": ["..\\packages\\vendure\\src/*"]
    }
  },
  ...
}
// /site/pages/cart.tsx

import type { GetStaticPropsContext } from 'next'
import useCart from '@framework/cart/use-cart'
import usePrice from '@framework/product/use-price'
...

export async function getStaticProps({
  preview,
  locale,
  locales,
}: GetStaticPropsContext) {
  ...
  return {
    props: { pages, categories },
  }
}

export default function Cart() {
  const error = null
  const success = null
  const { data, isLoading, isEmpty } = useCart()
  const { openSidebar, setSidebarView } = useUI()

  const { price: subTotal } = usePrice(
    data && {
      amount: Number(data.subtotalPrice),
      currencyCode: data.currency.code,
    }
  )
  const { price: total } = usePrice(
    data && {
      amount: Number(data.totalPrice),
      currencyCode: data.currency.code,
    }
  )

  const goToCheckout = () => {
    openSidebar()
    setSidebarView('CHECKOUT_VIEW')
  }

  return (
    <Container className="grid lg:grid-cols-12 pt-4 gap-20">
      ...
    </Container>
  )
}

Cart.Layout = Layout

debugger

See Also

  1. 쿠…sal: [컴][웹] next.js commerce + vendure 서버 실행

Reference

  1. commerce/new-provider.md at main · vercel/commerce · GitHub
  2. Debugging with VS Code · Discussion #788 · vercel/commerce · GitHub

댓글 없음:

댓글 쓰기