Gatsby 无法构建静态页面
Gatsby Failing to build static pages
我一直在使用 Gatsby 构建自定义 Shopify 和 Netlify CMS 页面。开发构建一直很好。但是当我尝试部署到 Netlify 时,它无法加载 /about 页面。我不知道为什么。它一直指向我的 useCart() 函数,这很奇怪,因为关于页面与我的 useCart 函数无关。
我会尽量在下面包含我能想到的所有相关代码。
Netlify 构建错误:
1:00:24 PM: failed Building static HTML for pages - 0.474s
1:00:24 PM: error Building static HTML failed for path "/about"
1:00:25 PM:
1:00:25 PM: 36 |
1:00:25 PM: 37 | export const useCart = () => {
1:00:25 PM: > 38 | const [checkout, dispatch] = useContext(CartContext);
1:00:25 PM: | ^
1:00:25 PM: 39 |
1:00:25 PM: 40 | const setCheckout = useCallback(
1:00:25 PM: 41 | (checkout) => dispatch({ type: 'SET_CHECKOUT', checkout }),
1:00:25 PM:
1:00:25 PM: WebpackError: TypeError: Cannot destructure '(0 , react__WEBPACK_IMPORTED_MODU LE_0__.useContext)(...)' as it is undefined.
购物车-context.js (useCart())
export const useCart = () => {
const [checkout, dispatch] = useContext(CartContext);
const setCheckout = useCallback(
(checkout) => dispatch({ type: 'SET_CHECKOUT', checkout }),
[dispatch],
);
useEffect(() => {
async function getCheckout() {
if (checkout) return;
if (!IS_BROWSER) {
setCheckout({});
}
// check if we already have a cart stored for this browser
const existingCheckoutID = localStorage.getItem('shopify_checkout_id');
if (existingCheckoutID && existingCheckoutID !== 'null') {
try {
const existingCheckout = await client.checkout.fetch(
existingCheckoutID,
);
// if this cart was already purchased, clear it and start fresh
if (!existingCheckout.completedAt) {
setCheckout(existingCheckout);
return;
}
} catch (error) {
localStorage.removeItem('shopify_checkout_id');
}
}
// if we get here, we need to create a new checkout session
const newCheckout = await client.checkout.create();
localStorage.setItem('shopify_checkout_id', newCheckout.id);
setCheckout(newCheckout);
}
getCheckout();
}, [checkout, setCheckout]);
const prepItem = ({ variantId, quantity }) => [
{
variantId,
quantity: parseInt(quantity, 10),
},
];
const addItemToCart = async (item) => {
dispatch({ type: 'PENDING' });
try {
const updatedCheckout = await client.checkout.addLineItems(
checkout.id,
prepItem(item),
);
setCheckout(updatedCheckout);
} catch (error) {
console.error(error);
}
};
const removeItemFromCart = async (variantId) => {
dispatch({ type: 'PENDING' });
try {
const updatedCheckout = await client.checkout.removeLineItems(
checkout.id,
[variantId],
);
setCheckout(updatedCheckout);
} catch (error) {
console.error(error);
}
};
return { checkout, addItemToCart, removeItemFromCart };
};
盖茨比-node.js
const path = require("path")
const { createFilePath } = require(`gatsby-source-filesystem`)
exports.createPages = async ({ actions, graphql, reporter }) => {
const { createPage } = actions
const blogList = path.resolve(`./src/templates/blog-list.js`)
const result = await graphql(`
{
allMarkdownRemark(sort: { order: DESC, fields: [frontmatter___date] }) {
edges {
node {
id
frontmatter {
slug
template
title
}
}
}
}
}
`)
// Handle errors
if (result.errors) {
reporter.panicOnBuild(`Error while running Blog GraphQL query.`)
return
}
// Create markdown pages
const posts = result.data.allMarkdownRemark.edges
let blogPostsCount = 0
posts.forEach((post, index) => {
const id = post.node.id
const previous = index === posts.length - 1 ? null : posts[index + 1].node
const next = index === 0 ? null : posts[index - 1].node
createPage({
path: post.node.frontmatter.slug,
component: path.resolve(
`src/templates/${String(post.node.frontmatter.template)}.js`
),
// additional data can be passed via context
context: {
id,
previous,
next,
},
})
// Count blog posts.
if (post.node.frontmatter.template === "blog-post") {
blogPostsCount++
}
})
// Create blog-list pages
const postsPerPage = 9
const numPages = Math.ceil(blogPostsCount / postsPerPage)
Array.from({ length: numPages }).forEach((_, i) => {
createPage({
path: i === 0 ? `/events` : `/events/${i + 1}`,
component: blogList,
context: {
limit: postsPerPage,
skip: i * postsPerPage,
numPages,
currentPage: i + 1,
},
})
})
return graphql (`
{
allShopifyProduct {
nodes {
id
handle
images {
gatsbyImageData
originalSrc
}
}
}
}
`).then(result => {
const products = result.data.allShopifyProduct.nodes;
products.forEach((product) => {
if (
!product ||
!product.images ||
!product.images[0] ||
!product.images[0].gatsbyImageData
) {
return;
}
actions.createPage({
path: `/product/${product.handle}`,
component: require.resolve('./src/templates/product-page.js'),
context: {
productID: product.id,
},
});
});
})
}
exports.onCreateNode = ({ node, getNode, actions }) => {
const { createNodeField } = actions
if (node.internal.type === `MarkdownRemark`) {
const slug = createFilePath({ node, getNode, basePath: `pages` })
createNodeField({
node,
name: `slug`,
value: slug,
})
}
}
盖茨比浏览器:
import React from 'react';
import { CartProvider } from './src/context/cart-context';
export const wrapRootElement = ({ element }) => (
<CartProvider>{element}</CartProvider>
);
export const onServiceWorkerUpdateReady = () => {
const answer = window.confirm(
`This application has been updated. ` +
`Reload to display the latest version?`
)
if (answer === true) {
window.location.reload()
}
}
我最终需要一个 gatsby-ssr.js 文件。谢谢 Ferran Buireu 的想法。
盖茨比-ssr.js
export { wrapRootElement } from './gatsby-browser';
我一直在使用 Gatsby 构建自定义 Shopify 和 Netlify CMS 页面。开发构建一直很好。但是当我尝试部署到 Netlify 时,它无法加载 /about 页面。我不知道为什么。它一直指向我的 useCart() 函数,这很奇怪,因为关于页面与我的 useCart 函数无关。
我会尽量在下面包含我能想到的所有相关代码。
Netlify 构建错误:
1:00:24 PM: failed Building static HTML for pages - 0.474s
1:00:24 PM: error Building static HTML failed for path "/about"
1:00:25 PM:
1:00:25 PM: 36 |
1:00:25 PM: 37 | export const useCart = () => {
1:00:25 PM: > 38 | const [checkout, dispatch] = useContext(CartContext);
1:00:25 PM: | ^
1:00:25 PM: 39 |
1:00:25 PM: 40 | const setCheckout = useCallback(
1:00:25 PM: 41 | (checkout) => dispatch({ type: 'SET_CHECKOUT', checkout }),
1:00:25 PM:
1:00:25 PM: WebpackError: TypeError: Cannot destructure '(0 , react__WEBPACK_IMPORTED_MODU LE_0__.useContext)(...)' as it is undefined.
购物车-context.js (useCart())
export const useCart = () => {
const [checkout, dispatch] = useContext(CartContext);
const setCheckout = useCallback(
(checkout) => dispatch({ type: 'SET_CHECKOUT', checkout }),
[dispatch],
);
useEffect(() => {
async function getCheckout() {
if (checkout) return;
if (!IS_BROWSER) {
setCheckout({});
}
// check if we already have a cart stored for this browser
const existingCheckoutID = localStorage.getItem('shopify_checkout_id');
if (existingCheckoutID && existingCheckoutID !== 'null') {
try {
const existingCheckout = await client.checkout.fetch(
existingCheckoutID,
);
// if this cart was already purchased, clear it and start fresh
if (!existingCheckout.completedAt) {
setCheckout(existingCheckout);
return;
}
} catch (error) {
localStorage.removeItem('shopify_checkout_id');
}
}
// if we get here, we need to create a new checkout session
const newCheckout = await client.checkout.create();
localStorage.setItem('shopify_checkout_id', newCheckout.id);
setCheckout(newCheckout);
}
getCheckout();
}, [checkout, setCheckout]);
const prepItem = ({ variantId, quantity }) => [
{
variantId,
quantity: parseInt(quantity, 10),
},
];
const addItemToCart = async (item) => {
dispatch({ type: 'PENDING' });
try {
const updatedCheckout = await client.checkout.addLineItems(
checkout.id,
prepItem(item),
);
setCheckout(updatedCheckout);
} catch (error) {
console.error(error);
}
};
const removeItemFromCart = async (variantId) => {
dispatch({ type: 'PENDING' });
try {
const updatedCheckout = await client.checkout.removeLineItems(
checkout.id,
[variantId],
);
setCheckout(updatedCheckout);
} catch (error) {
console.error(error);
}
};
return { checkout, addItemToCart, removeItemFromCart };
};
盖茨比-node.js
const path = require("path")
const { createFilePath } = require(`gatsby-source-filesystem`)
exports.createPages = async ({ actions, graphql, reporter }) => {
const { createPage } = actions
const blogList = path.resolve(`./src/templates/blog-list.js`)
const result = await graphql(`
{
allMarkdownRemark(sort: { order: DESC, fields: [frontmatter___date] }) {
edges {
node {
id
frontmatter {
slug
template
title
}
}
}
}
}
`)
// Handle errors
if (result.errors) {
reporter.panicOnBuild(`Error while running Blog GraphQL query.`)
return
}
// Create markdown pages
const posts = result.data.allMarkdownRemark.edges
let blogPostsCount = 0
posts.forEach((post, index) => {
const id = post.node.id
const previous = index === posts.length - 1 ? null : posts[index + 1].node
const next = index === 0 ? null : posts[index - 1].node
createPage({
path: post.node.frontmatter.slug,
component: path.resolve(
`src/templates/${String(post.node.frontmatter.template)}.js`
),
// additional data can be passed via context
context: {
id,
previous,
next,
},
})
// Count blog posts.
if (post.node.frontmatter.template === "blog-post") {
blogPostsCount++
}
})
// Create blog-list pages
const postsPerPage = 9
const numPages = Math.ceil(blogPostsCount / postsPerPage)
Array.from({ length: numPages }).forEach((_, i) => {
createPage({
path: i === 0 ? `/events` : `/events/${i + 1}`,
component: blogList,
context: {
limit: postsPerPage,
skip: i * postsPerPage,
numPages,
currentPage: i + 1,
},
})
})
return graphql (`
{
allShopifyProduct {
nodes {
id
handle
images {
gatsbyImageData
originalSrc
}
}
}
}
`).then(result => {
const products = result.data.allShopifyProduct.nodes;
products.forEach((product) => {
if (
!product ||
!product.images ||
!product.images[0] ||
!product.images[0].gatsbyImageData
) {
return;
}
actions.createPage({
path: `/product/${product.handle}`,
component: require.resolve('./src/templates/product-page.js'),
context: {
productID: product.id,
},
});
});
})
}
exports.onCreateNode = ({ node, getNode, actions }) => {
const { createNodeField } = actions
if (node.internal.type === `MarkdownRemark`) {
const slug = createFilePath({ node, getNode, basePath: `pages` })
createNodeField({
node,
name: `slug`,
value: slug,
})
}
}
盖茨比浏览器:
import React from 'react';
import { CartProvider } from './src/context/cart-context';
export const wrapRootElement = ({ element }) => (
<CartProvider>{element}</CartProvider>
);
export const onServiceWorkerUpdateReady = () => {
const answer = window.confirm(
`This application has been updated. ` +
`Reload to display the latest version?`
)
if (answer === true) {
window.location.reload()
}
}
我最终需要一个 gatsby-ssr.js 文件。谢谢 Ferran Buireu 的想法。
盖茨比-ssr.js
export { wrapRootElement } from './gatsby-browser';