Faster Shopify sourcing (#9754)

This commit is contained in:
Eli Kinsey
2024-10-29 14:22:17 -07:00
committed by GitHub
parent f32365852e
commit 521e7c3412
5 changed files with 178 additions and 45 deletions

View File

@@ -364,24 +364,6 @@ module.exports = {
{
resolve: 'gatsby-plugin-no-sourcemaps',
},
...(process.env.SHOPIFY_APP_PASSWORD &&
process.env.GATSBY_MYSHOPIFY_URL &&
process.env.GATBSY_SHOPIFY_SALES_CHANNEL
? [
{
resolve: 'gatsby-source-shopify',
options: {
password: process.env.SHOPIFY_APP_PASSWORD,
storeUrl: process.env.GATSBY_MYSHOPIFY_URL,
shopifyConnections: ['collections'],
salesChannel: process.env.GATBSY_SHOPIFY_SALES_CHANNEL,
downloadImages: false,
// salesChannel: process.env.SHOPIFY_APP_ID, // Optional but recommended
},
},
]
: []),
...(!process.env.GATSBY_ALGOLIA_APP_ID || !process.env.ALGOLIA_API_KEY || !process.env.GATSBY_ALGOLIA_INDEX_NAME
? []
: [algoliaConfig]),

View File

@@ -37,16 +37,12 @@ export const createResolvers: GatsbyNode['createResolvers'] = ({ createResolvers
imageProducts: {
type: ['ShopifyProduct'],
resolve(source, args, context, info) {
const metafieldNodesIds = source.metafields___NODE
const metafields = source.metafields
let productIds = []
for (const metafieldNodeId of metafieldNodesIds) {
const metafieldNode = context.nodeModel.getNodeById({
id: metafieldNodeId,
})
if (metafieldNode.key === 'image_products') {
productIds = productIds.concat(JSON.parse(metafieldNode.value))
for (const metafield of metafields) {
if (metafield.key === 'image_products') {
productIds = productIds.concat(JSON.parse(metafield.value))
}
}

View File

@@ -3,9 +3,6 @@ import { GatsbyNode } from 'gatsby'
export const createSchemaCustomization: GatsbyNode['createSchemaCustomization'] = async ({ actions, schema }) => {
const { createTypes } = actions
createTypes(`
type ShopifyProduct implements Node {
imageProducts: [ShopifyProduct]
}
type Mdx implements Node {
frontmatter: Frontmatter
avatar: String
@@ -273,16 +270,12 @@ export const createSchemaCustomization: GatsbyNode['createSchemaCustomization']
},
}),
])
if (
!process.env.SHOPIFY_APP_PASSWORD ||
!process.env.GATSBY_MYSHOPIFY_URL ||
!process.env.GATBSY_SHOPIFY_SALES_CHANNEL
) {
createTypes(
`
createTypes(
`
type ShopifyCollection implements Node {
handle: String!
products: [ShopifyProduct!]!
products: [ShopifyProduct!] @link(by: "shopifyId", from: "products.shopifyId")
}
type ShopifySelectedOption {
name: String!
@@ -309,7 +302,6 @@ export const createSchemaCustomization: GatsbyNode['createSchemaCustomization']
selectedOptions: [ShopifySelectedOption!]!
}
type ShopifyImage {
localFile: File
width: Int
height: Int
originalSrc: String
@@ -350,9 +342,9 @@ export const createSchemaCustomization: GatsbyNode['createSchemaCustomization']
options: [ShopifyProductOption!]!
tags: [String!]!
totalInventory: Int!
featuredImage: ShopifyFeaturedImage
featuredImage: ShopifyImage @proxy(from: "featuredMedia.preview.image")
imageProducts: [ShopifyProduct]
}
`
)
}
)
}

View File

@@ -364,6 +364,165 @@ export const sourceNodes: GatsbyNode['sourceNodes'] = async ({ actions, createCo
createNode(node)
})
const collection = await fetch(`https://${shopifyURL}/admin/api/${shopifyAdminAPIVersion}/graphql.json`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Shopify-Access-Token': shopifyAdminAPIAPIPassword!,
},
body: JSON.stringify({
query: ` {
collectionByHandle(handle: "all-products") {
handle
products(first: 250) {
nodes {
description
featuredMedia {
preview {
image {
width
height
originalSrc
}
}
}
handle
id
media(first: 250) {
nodes {
mediaContentType
preview {
image {
width
height
originalSrc
}
}
}
}
metafields(first: 250) {
nodes {
value
key
}
}
options {
shopifyId: id
name
values
}
priceRangeV2 {
maxVariantPrice {
amount
}
minVariantPrice {
amount
}
}
shopifyId: id
status
title
tags
totalInventory
}
}
}
}
`,
}),
}).then((res) => res.json())
const variants = await fetch(`https://${shopifyURL}/admin/api/${shopifyAdminAPIVersion}/graphql.json`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Shopify-Access-Token': shopifyAdminAPIAPIPassword!,
},
body: JSON.stringify({
query: ` {
productVariants(first: 250) {
nodes {
availableForSale
media(first: 250) {
nodes {
preview {
image {
width
height
originalSrc
}
}
}
}
price
product {
shopifyId: id
title
featuredMedia {
preview {
image {
width
height
originalSrc
}
}
}
}
selectedOptions {
name
value
}
shopifyId: id
sku
title
}
}
}
`,
}),
}).then((res) => res.json())
const moveNodesToParent = (obj) => {
if (Array.isArray(obj)) {
return obj.map(moveNodesToParent)
} else if (obj && typeof obj === 'object') {
if (obj.nodes) {
return moveNodesToParent(obj.nodes)
}
return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, moveNodesToParent(value)]))
}
return obj
}
const products = moveNodesToParent(collection.data.collectionByHandle.products.nodes).filter(
(product) => product.status === 'ACTIVE'
)
products.forEach((product) => {
product.variants = moveNodesToParent(
variants.data.productVariants.nodes.filter((variant) => variant.product.shopifyId === product.shopifyId)
)
const node = {
id: createNodeId(`shopify-product-${product.shopifyId}`),
internal: {
type: 'ShopifyProduct',
contentDigest: createContentDigest(product),
},
...product,
}
createNode(node)
})
const data = {
handle: collection.data.collectionByHandle.handle,
products: products.map((product) => ({ shopifyId: product.shopifyId })),
}
const node = {
id: createNodeId(`shopify-collection`),
internal: {
type: 'ShopifyCollection',
contentDigest: createContentDigest(data),
},
...data,
}
createNode(node)
}
const fetchSlackEmojis = async () => {

View File

@@ -94,10 +94,14 @@ export const query = graphql`
status
imageProducts {
handle
featuredImage {
width
height
originalSrc
featuredMedia {
preview {
image {
width
height
originalSrc
}
}
}
}
featuredMedia {