Gatsby中如何通过gatsby-node.js删除index.js并动态生成首页
问题根因
你当前代码存在两个核心错误导致运行报错:
- 重复创建同一路径页面:当
node.slug === '/'时,你在判断分支内已经调用了一次createPage创建首页,分支外的全局createPage逻辑会再次为同一个/路径创建页面,触发路由冲突。 deletePage参数不符合Gatsby API要求:deletePage不需要传入component参数,仅需传入path即可,如果你传入的path.resolve('src/pages/index.js')路径和Gatsby内部生成的首页组件路径不一致,会导致删除失败。
修复方案
- 推荐直接在
onCreatePage钩子中拦截默认的src/pages/index.js页面生成,避免后续删除操作 - 删除重复的首页创建逻辑
- 简化
deletePage调用参数
修正后的完整代码如下:
const path = require('path') // 原有常量定义 STATIC_DEFINED_PAGES、LAYOUT_LOOKUP 保持不变即可 const fetchAllComposePages = async ({ graphql, locales }) => /* eslint implicit-arrow-linebreak: ["error", "below"] */ graphql(` { allContentfulComposePage(filter: { node_locale: { in: ${locales} } }) { nodes { contentful_id title node_locale slug seo { no_follow no_index description name keywords title } content { __typename } } } } `); exports.createPages = async ({ graphql, actions }) => { const { createPage } = actions; let locales = ''; if (process.env.GATSBY_LOCALE === 'qc') { locales = '["en", "fr"]'; } else { locales = '["en-CA", "fr-CA"]'; } const result = await fetchAllComposePages({ graphql, locales }); result.data.allContentfulComposePage.nodes.map((node) => { const { contentful_id: id, slug, seo } = node; const content = node.content || [{}]; const { __typename: template } = content; if (STATIC_DEFINED_PAGES.includes(slug)) { console.info(`Skipping Page :: ID: ${id} - Slug: ${slug}`); return; } if (!template) { console.info(`No Layout Found :: ID: ${id} - Slug: ${slug}`); return; } let layout = ''; if (LAYOUT_LOOKUP[template]) { layout = LAYOUT_LOOKUP[template]; } else { console.info(`No Layout Found :: ID: ${id} - Slug: ${slug}`); layout = 'base/BaseTemplate.js'; } if (!seo) { console.info(`No SEO Found for: ${slug}`); } // 全局仅保留一次createPage调用,避免重复创建 createPage({ path: node.slug, component: path.resolve(`src/layouts/${layout}`), context: { pathSlug: slug, pageId: id, seo: { name: seo?.name ?? '', description: seo?.description ?? '', keywords: seo?.keywords ?? '', title: seo?.title ?? '', no_follow: seo?.no_follow ?? false, no_index: seo?.no_index ?? false, }, }, }); }); }; // 拦截默认的index.js页面生成,从源头避免路由冲突 exports.onCreatePage = ({ page, actions }) => { const { deletePage } = actions // 匹配默认生成的首页直接删除 if (page.path === '/' && page.component.includes('src/pages/index.js')) { deletePage(page) } // 原有国际化逻辑保持不变,增加intl判空避免异常 const lang = page.context.intl?.language if (lang) { const locale = `${lang}-CA`; page.context.locale = locale; } return page; };
额外优化点
- 用可选链
?.和空值合并运算符??简化了SEO字段的判空逻辑,代码更简洁 - 在
onCreatePage中提前拦截默认首页,即使createPages逻辑执行异常也不会出现默认首页和自定义首页冲突的问题 - 去掉了重复的createPage调用,彻底避免路由重复报错
内容的提问来源于stack exchange,提问作者SDK
相关产品推荐
相关产品推荐

