Implement getAllProductPaths to prerender some products during build time

This commit is contained in:
tniezg 2021-08-19 14:02:13 +02:00
parent ed49ac8833
commit a191e28df7
5 changed files with 123 additions and 13 deletions

View File

@ -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 = {
products: Array<{ path: string }>
export default function getAllProductPathsOperation({
commerce,
}: OperationContext<SpreeApiProvider>) {
async function getAllProductPaths<
T extends GetAllProductPathsOperation
>(opts?: {
variables?: T['variables']
config?: Partial<SpreeApiConfig>
}): Promise<T['data']>
async function getAllProductPaths<T extends GetAllProductPathsOperation>(
opts: {
variables?: T['variables']
config?: Partial<SpreeApiConfig>
} & OperationOptions
): Promise<T['data']>
async function getAllProductPaths<T extends GetAllProductPathsOperation>({
query,
variables: getAllProductPathsVariables = {},
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: [],
}
}
export default function getAllProductPathsOperation() {
function getAllProductPaths(): Promise<GetAllProductPathsResult> {
console.log('getAllProductPaths called.')
const variables: SpreeSdkVariables = {
methodPath: 'products.list',
arguments: [
{
fields: {
product: 'slug',
},
per_page: productsCount,
},
],
}
return Promise.resolve({
// products: data.products.map(({ path }) => ({ path })),
// TODO: Return Storefront [{ path: '/long-sleeve-shirt' }, ...] from Spree products. Paths using product IDs are fine too.
products: [],
})
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

View File

@ -88,3 +88,12 @@ export interface VariantAttr extends JsonApiDocument {
backorderable: boolean
}
}
export interface ProductSlugAttr extends JsonApiDocument {
attributes: {
slug: string
}
}
export interface IProductsSlugs extends JsonApiListResponse {
data: ProductSlugAttr[]
}

View File

@ -0,0 +1,7 @@
import type { ProductSlugAttr } from '@framework/types'
const getProductPath = (partialSpreeProduct: ProductSlugAttr): string => {
return `/${partialSpreeProduct.attributes.slug}`
}
export default getProductPath

View File

@ -15,6 +15,7 @@ import createGetAbsoluteImageUrl from './create-get-absolute-image-url'
import expandOptions from './expand-options'
import getMediaGallery from './get-media-gallery'
import { findIncludedOfType } from './find-json-api-documents'
import getProductPath from './get-product-path'
const normalizeProduct = (
spreeSuccessResponse: JsonApiSingleResponse | JsonApiListResponse,
@ -82,7 +83,7 @@ const normalizeProduct = (
})
const slug = spreeProduct.attributes.slug
const path = `/${spreeProduct.attributes.slug}`
const path = getProductPath(spreeProduct)
return {
id: spreeProduct.id,

View 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