커머스 넥스트 커머스 / 디버거/ 디버깅 / nextjs
next.js commerce에서 provider 분석
여기서는 이미구현된 vendure commerce provider 를 가지고 파악해 본다.
- provider 의 구조 예시: https://github.com/vercel/commerce/tree/main/packages/vendure
src/provider.ts
와 src/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.json
의 paths
추가하게 된다. @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
댓글 없음:
댓글 쓰기