mirror of
https://github.com/vercel/commerce.git
synced 2025-07-04 04:01:21 +00:00
Implement getAllProductPaths to prerender some products during build time
This commit is contained in:
parent
ed49ac8833
commit
a191e28df7
@ -1,18 +1,90 @@
|
|||||||
// import data from '../../data.json'
|
import type {
|
||||||
|
OperationContext,
|
||||||
|
OperationOptions,
|
||||||
|
} from '@commerce/api/operations'
|
||||||
|
import type { Product } from '@commerce/types/product'
|
||||||
|
import type { GetAllProductPathsOperation } from '@commerce/types/product'
|
||||||
|
import { requireConfigValue } from '@framework/isomorphic-config'
|
||||||
|
import type { IProductsSlugs, SpreeSdkVariables } from '@framework/types'
|
||||||
|
import getProductPath from '@framework/utils/get-product-path'
|
||||||
|
import type { SpreeApiConfig, SpreeApiProvider } from '..'
|
||||||
|
|
||||||
export type GetAllProductPathsResult = {
|
export default function getAllProductPathsOperation({
|
||||||
products: Array<{ path: string }>
|
commerce,
|
||||||
}
|
}: OperationContext<SpreeApiProvider>) {
|
||||||
|
async function getAllProductPaths<
|
||||||
|
T extends GetAllProductPathsOperation
|
||||||
|
>(opts?: {
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: Partial<SpreeApiConfig>
|
||||||
|
}): Promise<T['data']>
|
||||||
|
|
||||||
export default function getAllProductPathsOperation() {
|
async function getAllProductPaths<T extends GetAllProductPathsOperation>(
|
||||||
function getAllProductPaths(): Promise<GetAllProductPathsResult> {
|
opts: {
|
||||||
console.log('getAllProductPaths called.')
|
variables?: T['variables']
|
||||||
|
config?: Partial<SpreeApiConfig>
|
||||||
|
} & OperationOptions
|
||||||
|
): Promise<T['data']>
|
||||||
|
|
||||||
return Promise.resolve({
|
async function getAllProductPaths<T extends GetAllProductPathsOperation>({
|
||||||
// products: data.products.map(({ path }) => ({ path })),
|
query,
|
||||||
// TODO: Return Storefront [{ path: '/long-sleeve-shirt' }, ...] from Spree products. Paths using product IDs are fine too.
|
variables: getAllProductPathsVariables = {},
|
||||||
products: [],
|
config: userConfig,
|
||||||
})
|
}: {
|
||||||
|
query?: string
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: Partial<SpreeApiConfig>
|
||||||
|
} = {}): Promise<T['data']> {
|
||||||
|
console.info(
|
||||||
|
'getAllProductPaths called. Configuration: ',
|
||||||
|
'query: ',
|
||||||
|
query,
|
||||||
|
'getAllProductPathsVariables: ',
|
||||||
|
getAllProductPathsVariables,
|
||||||
|
'config: ',
|
||||||
|
userConfig
|
||||||
|
)
|
||||||
|
|
||||||
|
const productsCount = requireConfigValue(
|
||||||
|
'lastUpdatedProductsPrerenderCount'
|
||||||
|
)
|
||||||
|
|
||||||
|
if (productsCount === 0) {
|
||||||
|
return {
|
||||||
|
products: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const variables: SpreeSdkVariables = {
|
||||||
|
methodPath: 'products.list',
|
||||||
|
arguments: [
|
||||||
|
{
|
||||||
|
fields: {
|
||||||
|
product: 'slug',
|
||||||
|
},
|
||||||
|
per_page: productsCount,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = commerce.getConfig(userConfig)
|
||||||
|
const { fetch: apiFetch } = config // TODO: Send config.locale to Spree.
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: { data: spreeSuccessResponse },
|
||||||
|
} = await apiFetch<{ data: IProductsSlugs }, SpreeSdkVariables>(
|
||||||
|
'__UNUSED__',
|
||||||
|
{
|
||||||
|
variables,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const normalizedProductsPaths: Pick<Product, 'path'>[] =
|
||||||
|
spreeSuccessResponse.data.map((spreeProduct) => ({
|
||||||
|
path: getProductPath(spreeProduct),
|
||||||
|
}))
|
||||||
|
|
||||||
|
return { products: normalizedProductsPaths }
|
||||||
}
|
}
|
||||||
|
|
||||||
return getAllProductPaths
|
return getAllProductPaths
|
||||||
|
@ -88,3 +88,12 @@ export interface VariantAttr extends JsonApiDocument {
|
|||||||
backorderable: boolean
|
backorderable: boolean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ProductSlugAttr extends JsonApiDocument {
|
||||||
|
attributes: {
|
||||||
|
slug: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export interface IProductsSlugs extends JsonApiListResponse {
|
||||||
|
data: ProductSlugAttr[]
|
||||||
|
}
|
||||||
|
7
framework/spree/utils/get-product-path.ts
Normal file
7
framework/spree/utils/get-product-path.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import type { ProductSlugAttr } from '@framework/types'
|
||||||
|
|
||||||
|
const getProductPath = (partialSpreeProduct: ProductSlugAttr): string => {
|
||||||
|
return `/${partialSpreeProduct.attributes.slug}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getProductPath
|
@ -15,6 +15,7 @@ import createGetAbsoluteImageUrl from './create-get-absolute-image-url'
|
|||||||
import expandOptions from './expand-options'
|
import expandOptions from './expand-options'
|
||||||
import getMediaGallery from './get-media-gallery'
|
import getMediaGallery from './get-media-gallery'
|
||||||
import { findIncludedOfType } from './find-json-api-documents'
|
import { findIncludedOfType } from './find-json-api-documents'
|
||||||
|
import getProductPath from './get-product-path'
|
||||||
|
|
||||||
const normalizeProduct = (
|
const normalizeProduct = (
|
||||||
spreeSuccessResponse: JsonApiSingleResponse | JsonApiListResponse,
|
spreeSuccessResponse: JsonApiSingleResponse | JsonApiListResponse,
|
||||||
@ -82,7 +83,7 @@ const normalizeProduct = (
|
|||||||
})
|
})
|
||||||
|
|
||||||
const slug = spreeProduct.attributes.slug
|
const slug = spreeProduct.attributes.slug
|
||||||
const path = `/${spreeProduct.attributes.slug}`
|
const path = getProductPath(spreeProduct)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: spreeProduct.id,
|
id: spreeProduct.id,
|
||||||
|
21
framework/spree/utils/validate-products-prerender-count.ts
Normal file
21
framework/spree/utils/validate-products-prerender-count.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
const validateProductsPrerenderCount = (prerenderCount: unknown): number => {
|
||||||
|
let prerenderCountInteger: number
|
||||||
|
|
||||||
|
if (typeof prerenderCount === 'string') {
|
||||||
|
prerenderCountInteger = parseInt(prerenderCount)
|
||||||
|
} else if (typeof prerenderCount === 'number') {
|
||||||
|
prerenderCountInteger = prerenderCount
|
||||||
|
} else {
|
||||||
|
throw new TypeError(
|
||||||
|
'prerenderCount count must be a string containing a number or an integer.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prerenderCountInteger < 0) {
|
||||||
|
throw new RangeError('prerenderCount must be non-negative.')
|
||||||
|
}
|
||||||
|
|
||||||
|
return prerenderCountInteger
|
||||||
|
}
|
||||||
|
|
||||||
|
export default validateProductsPrerenderCount
|
Loading…
x
Reference in New Issue
Block a user