首页 > 解决方案 > 获取远程图像并将其转换为 gatsby 图像

问题描述

我正在尝试从 WP 获取一些图像,因为 Gatsby 还不能与 woocommerece 一起使用。我下面的插件能够在构建时转换图像并将它们添加到 .cache 中,但它不会在 Gatsby graphQl 中添加 localFile___NODE 字段。我似乎根本没有添加任何节点来使用 ImageSharp 插件进行查询。Graphql 显示它们正在 ALLFiles 下处理,但不在我在 Graphql 中创建的 wcProduct 节点内处理……这个插件不再创建节点是怎么回事……

const utils = require("./utils")
const fetch = require("node-fetch")
const queryString = require("query-string")
const fs = require("fs-extra")
const { createRemoteFileNode } = require(`gatsby-source-filesystem`)

exports.sourceNodes = async (
  {
    actions, createNodeId, createContentDigest, store, cache
  },
  configOptions
) => {
  const { createNode } = actions

  await fs.removeSync("/.cache")

  // Gatsby adds a configOption that's not needed for this plugin, delete it
  delete configOptions.plugins

  // Helper function that processes a product to match Gatsby's node structure
  const processProduct = async (product, args) => {
    // console.log("product", product)

    //  https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-source-filesystem#createremotefilenode
    // download and add image to local file
    await product.images.map(async image => {

      const fileNode = await createRemoteFileNode({
        ...args,
        url: image.fullSize.url
      })
      image.localFile___NODE = fileNode.id

    })

    const nodeId = createNodeId(`wc-product-${product.id}`)
    const nodeContent = JSON.stringify(product)

    // Node info
    return Object.assign({}, product, {
      id: nodeId,
      parent: null,
      children: [],
      internal: {
        type: `wcProduct`,
        content: nodeContent,
        contentDigest: createContentDigest(product)
      }
    })
  }

  const apiUrl = `${process.env.GATSBY_DB}/wp-json/et-shop/graphql/products`
  const apiResponse = await fetch(apiUrl)
  const results = await apiResponse.json()
  const jsonResults = JSON.stringify(utils.transformNormalizedData(results.data))
  fs.writeFileSync("src/state/products.json", jsonResults)

  results.data.forEach(async (product) => {
    // Process the product data to match the structure of a Gatsby node
    const productNode = await processProduct(product, { store, cache, createNode, createNodeId })

    // Use Gatsby's createNode helper to create a node from the node data
    createNode(productNode)
  })
}

标签: reactjsgraphqlgatsby

解决方案


我意识到我没有正确编写异步循环。此代码允许您从远程源中提取数据,然后在即将转换为 GraphQL 的数据中添加一个节点。对我来说,我想要一个图像 url,将其转换为我在 Gatsby 和 ImageSharp 插件中使用的图像。这会从我的 CMS 中获取该图像,并将其转换为“Gatsby 图像”,并且可以在 wcProduct.images.localFile 下的 graphQL 查询中找到

const utils = require("./utils")
const fetch = require("node-fetch")
const fs = require("fs-extra")
const { createRemoteFileNode } = require(`gatsby-source-filesystem`)

exports.sourceNodes = async (
  {
    actions, createNodeId, createContentDigest, store, cache
  },
  configOptions
) => {
  const { createNode } = actions

  await fs.removeSync("/.cache")

  // Gatsby adds a configOption that's not needed for this plugin, delete it
  delete configOptions.plugins

  // Helper function that processes a product to match Gatsby's node structure
  const processProduct = async (product, args) => {

    // https://flaviocopes.com/javascript-async-await-array-map/
    product.images = await Promise.all(product.images.map(async image => {
      let fileNode

      try {
        fileNode = await createRemoteFileNode({
          url: image.fullSize.url,
          ...args
        })

      } catch (e) {
        console.log("e", e)

      }
      if (fileNode) {
        console.log("createdFile node")
        image.localFile___NODE = fileNode.id
        return image
      }
    }))

    const nodeId = createNodeId(`wc-product-${product.id}`)
    const nodeContent = JSON.stringify(product)

    // Node info
    return Object.assign({}, product, {
      id: nodeId,
      parent: null,
      children: [],
      internal: {
        type: `wcProduct`,
        content: nodeContent,
        contentDigest: createContentDigest(product)
      }
    })
  }

  const apiUrl = `${process.env.GATSBY_DB}/wp-json/et-shop/graphql/products`
  const apiResponse = await fetch(apiUrl)
  const results = await apiResponse.json()

  const jsonResults = JSON.stringify(utils.transformNormalizedData(results.data))
  fs.writeFileSync("src/state/products.json", jsonResults)

  await asyncForEach(results.data, async (product) => {
    const productNode = await processProduct(product, { store, cache, createNode, createNodeId })

    createNode(productNode)
  })
}

// https://codeburst.io/javascript-async-await-with-foreach-b6ba62bbf404
async function asyncForEach (array, callback) {
  for (let index = 0; index < array.length; index++) {
    await callback(array[index], index, array)
  }
}

推荐阅读