Gatsby Build卡在静态HTML构建阶段 JSX嵌套map问题排查
问题根因
构建卡在"Building static HTML for pages" 0%进度,和JSX嵌套map遍历语法本身无关,是代码存在3个React SSR渲染逻辑问题,触发Gatsby构建时的渲染死锁:
- 第一层
items.map返回的简写Fragment<>...</>未绑定key属性:React要求列表渲染的所有同级顶层节点必须有唯一key,简写Fragment语法不支持传入key属性,SSR阶段做虚拟DOM比对时会反复触发无效重渲染 - 内层
items2.map生成的节点key重复:当前key规则为${navKey}-${index2},该逻辑写在外层items.map循环内部,外层每一轮循环生成的内层节点key都会和上一轮完全重复,React DOM diff无法识别节点差异,会陷入无限节点重排 - 未做
items2的存在性校验:如果items2是异步加载数据、或特定页面场景下值为undefined,直接调用.map()会抛出渲染异常,Gatsby v4的SSR构建遇到未捕获的渲染错误时,部分场景不会直接打印错误日志,只会表现为进度卡死 - 额外依赖隐患:当前项目同时安装了大版本不兼容的
@emotion/core@10.x和@emotion/react@11.x,你使用的theme-ui@0.3.4原生依赖emotion 10.x版本,双版本共存会导致SSR阶段样式注入逻辑死循环,注释内层map后可以构建成功,说明核心问题为前三点,依赖冲突为次要隐患。
修复方案
- 替换简写Fragment为支持传入key的
React.Fragment,给外层循环的每个顶层节点绑定唯一key - 调整内层
items2.map的key生成规则,拼接外层循环的index值,保证所有渲染节点key全局唯一 - 给
items2设置空数组默认值,避免值为undefined时调用map报错 - (建议操作)移除冗余的
@emotion/react依赖,保持emotion版本和theme-ui的依赖要求一致,排除双版本冲突问题
修复后的完整代码如下:
import { Fragment } from 'react' const NaviList = ({ navKey, wrapperProps, items, items2 = [], ...props }) => items ? ( <Flex {...wrapperProps}> {items.map((menuItem, index) => ( <Fragment key={`${navKey}-outer-${index}`}> <NaviItem {...menuItem} {...props} /> <Box sx={styles.secondUl}> {items2.map((menuItem2, index2) => ( <NaviItem key={`${navKey}-${index}-inner-${index2}`} {...menuItem2} {...props} /> ))} </Box> </Fragment> ))} </Flex> ) : null
验证步骤
修改完成后先执行gatsby clean清理所有构建缓存,再执行gatsby build即可正常走完构建流程。如果仍然出现卡死问题,删除node_modules目录和依赖锁文件后重新安装依赖,彻底解决emotion双版本冲突即可。
内容的提问来源于stack exchange,提问作者Mar1o
相关产品推荐
相关产品推荐

