Gatsby v4.6.0 深度解读查询性能优化、Markdown 图片变更追踪与插件 Schema 校验升级【免费下载链接】gatsbyReact-based framework with performance, scalability, and security built in.项目地址: https://gitcode.com/gh_mirrors/ga/gatsby本文基于 Gatsby 官方 v4.6.0 发布说明2022 年 1 月第二个版本撰写结合当前仓库源码对三大核心亮点逐一剖析通过缓存rootNode与trackedRootNodes加速后续查询约 10%~15% 性能提升、修复gatsby-remark-images无法感知图片文件变更的问题、以及gatsby-plugin-utils新主版本中插件选项 Schema 校验由报错改为警告的行为变更与迁移方法。读完本文你将掌握这三个功能的底层实现原理、升级到 v4.6 后需要调整的代码以及若干值得关注的 Bugfix 详情。版本概览gatsby4.6.0发布于 2022 年 1 月2022 年 1 月的第二个版本本版本的三个核心亮点为加速后续查询首次gatsby build之后的每次构建查询性能可获得约 10%~15% 的提升缓存未被清除的前提下具体提升幅度取决于节点复杂度追踪 Markdown 文件中的图片变更修复了gatsby-remark-images下修改图片如缩放、直接编辑不生效、需要手动gatsby clean的问题gatsby-plugin-utils新主版本插件选项 Schema 校验对未知键等警告级问题不再抛错默认值可以正确传递。若想抢先体验尚未发布的新特性可以安装gatsbynext并反馈问题。上一版本的说明见 v4.5 Release Notes。加速后续查询缓存rootNode与trackedRootNodes改进思路与收益v4.6 中Gatsby 通过将rootNode与trackedRootNodes缓存在graphqlRunner的多个实例之间共享使后续查询即首次gatsby build之后的每次构建获得约10%~15% 的性能提升。需要说明的是该提升只在缓存未被清除gatsby clean时生效首次构建不受益具体提升百分比因节点复杂度不同而有所差异原发布说明中的表述为 may defer depending on the complexity of nodes。这一优化来自 PR #33695。源码级实现原理优化点直接体现在 graphql-runner.ts 的模块级缓存声明中// Preserve these caches across graphql instances. const _rootNodeMap new WeakMap() const _trackedRootNodes new WeakSet()这两行注释揭示了核心思路将缓存提升为模块级模块作用域变量从而跨GraphQLRunner实例存活。在构造函数中它们被注入LocalNodeModelthis.nodeModel new LocalNodeModel({ schema, schemaComposer: schemaCustomization.composer, createPageDependency, _rootNodeMap, _trackedRootNodes, })为什么要这样做LocalNodeModel内部维护内联对象/数组 → 根节点的反向映射用于在查询解析时快速定位某个内联对象所属的根节点。此前每个GraphQLRunner实例都会重新构建这份映射重复构建的成本在大型站点上不可忽视。在 node-model.js 中可以看到两者的使用方式trackInlineObjectsInRootNode(node)通过_trackedRootNodesWeakSet判断节点是否已被追踪避免重复执行addRootNodeToInlineObject造成的冗余工作trackInlineObjectsInRootNode(node) { if (!this._trackedRootNodes.has(node)) { addRootNodeToInlineObject( this._rootNodeMap, node, node.id, true, new Set() ) this._trackedRootNodes.add(node) } }findRootNodeAncestor(obj, predicate)通过_rootNodeMapWeakMap直接取得内联对象对应的根节点 id 集合再沿parent链向上查找符合条件的祖先节点省去全量扫描let ids this._rootNodeMap.get(obj) if (!ids) { ids new Set() } if (obj?.parent typeof obj.parent string) { ids.add(obj.parent) }选用WeakMap/WeakSet而非普通Map/Set也很关键它们不阻止垃圾回收不会因为缓存而引发内存泄漏。当节点对象不再被引用时映射关系可被自动回收这也是该方案能被提升为模块级缓存的安全前提。追踪 Markdown 文件中的图片变更问题背景当在 Markdown 文件中通过gatsby-remark-images使用图片时例如alt text过去存在一个痛点修改图片后站点不会反映变更。无论是调整图片尺寸还是直接编辑图片内容都需要手动执行gatsby clean清空缓存才能生效。该问题现已通过 PR #34433 修复变更后的图片会在gatsby develop和gatsby build中直接生效。底层处理流程gatsby-remark-images在渲染 Markdown 图片节点时会解析图片在文件系统中的绝对路径并据此查找对应的文件节点随后通过fluid生成响应式图片数据。相关处理见 index.jslet imageNode if (getRemarkFileDependency) { imageNode await getRemarkFileDependency({ absolutePath: { eq: imagePath, }, }) } else { // Legacy: no context, slower version of image query imageNode _.find(files, file { if (file file.absolutePath) { return file.absolutePath imagePath } return null }) } if (!imageNode || !imageNode.absolutePath) { return resolve() } const fluidResult await fluid({ file: imageNode, args: options, reporter, cache, })修复的关键在于让 Gatsby 正确识别图片文件本身的内容变化而不是仅识别引用它的 Markdown 文件变化从而触发文件节点及其派生的图片节点的重新处理。修复后图片的变更追踪得以纳入 Gatsby 的增量构建流程无需再依赖gatsby clean的暴力清缓存手段。这也让gatsby develop下的热更新体验更符合直觉——改图即所见。gatsby-plugin-utils新主版本Schema 校验从报错到警告行为变更一览gatsby-plugin-utils迎来了新的主版本。你可以用它为插件配置插件选项并借助辅助函数对选项 Schema 进行单元测试。本次升级带来的核心变化是Schema 校验遇到未知键等警告级问题时不再抛出错误从而修复了当用户传入未知键时插件默认值未被正确传递的隐患相关实现见 PR #34182。升级后需要关注的具体变化pluginOptionsSchema对未知键返回warnings警告而非 errors错误testPluginOptionsSchema在原有返回值基础上新增返回warnings和hasWarnings插件选项 Schema 中设置的默认值现在能正确传递到插件即使使用者设置了未知键。源码级实现校验行为由 validate.ts 实现其核心是validateOptionsSchema函数。它通过给插件 Schema 添加一个任意键匹配、产出警告的 pattern配合 Joi 的warnings选项将未知键从硬错误转为软警告const warnOnUnknownSchema pluginSchema.pattern( /.*/, Joi.any().warning(any.unknown) ) return (await warnOnUnknownSchema.validateAsync(pluginOptions, { ...validationOptions, // abortEarly: false, cache: true externals: validateExternalRules, warnings: returnWarnings, })) as PromiseIValidateAsyncResult注意其中的abortEarly: false意味着一次校验会收集并返回全部问题而不是只报告第一个错误。而 test-plugin-options-schema.ts 中导出的testPluginOptionsSchema封装了上述校验逻辑其返回类型为interface ITestPluginOptionsSchemaReturnType { errors: Arraystring warnings: Arraystring isValid: boolean hasWarnings: boolean }实现逻辑为当validateOptionsSchema返回的warning列表非空时返回isValid: true、hasWarnings: true及具体 warnings仅当校验真正抛错时才返回isValid: false与 errors。在 README.md 中可以看到这两个函数的通用用法validateOptionsSchema由 Gatsby 在站点启动时内部调用用于校验gatsby-config.js中每个插件的选项。仓库中的测试 test-plugin-options-schema.ts 测试用例 也展示了新语义下的断言方式例如无效配置断言isValid为false而存在警告但整体有效的配置断言isValid为true。迁移指南单元测试的 before/after如果你现有的插件单元测试依赖未知键报错的旧行为需要按下述方式迁移。迁移前旧行为未知键产生 errors// The plugin doesnt take any options exports.pluginOptionsSchema ({ Joi }) Joi.object({})import { testPluginOptionsSchema } from gatsby-plugin-utils import { pluginOptionsSchema } from ../gatsby-node it(should not accept any options, async () { const expectedErrors [optionA is not allowed] const { errors } await testPluginOptionsSchema( pluginOptionsSchema, { optionA: This options shouldnt exist, } ) expect(errors).toEqual(expectedErrors) })迁移后新行为未知键产生 warningsimport { testPluginOptionsSchema } from gatsby-plugin-utils import { pluginOptionsSchema } from ../gatsby-node it(should not accept any options, async () { const expectedWarnings [optionA is not allowed] const { warnings, isValid, hasWarnings } await testPluginOptionsSchema( pluginOptionsSchema, { optionA: This options shouldnt exist, } ) expect(isValid).toBe(true) expect(hasWarnings).toBe(true) expect(warnings).toEqual(expectedWarnings) })可见迁移的关键差异在于断言对象从errors换成warnings同时新增对isValid仍为true与hasWarnings为true的断言。这一调整保证了未声明任何选项的插件在遇到未知键时不再校验失败Schema 中定义的默认值能够正常生效。值得关注的 Bugfix 与改进除三大亮点外v4.6.0 还包含以下值得留意的修复与改进gatsby-plugin-manifest图标改为顺序生成此前为并行避免大规模图标生成时的资源竞争问题create-gatsby修复了用户设置的GATSBY_TELEMETRY_DISABLED环境变量未生效、遥测未被禁用的问题gatsby-sharp围绕 sharp 封装了更具弹性的包装层提升图像处理在异常场景下的健壮性gatsby-source-contentful为assets资产/媒体资源启用标签tag支持与 Contentful 的标签能力对齐gatsby优化了仅按id过滤的查询执行路径进一步压缩这类高频查询的开销其他杂项修正了若干文档中的链接与拼写问题例如GatbsyImage→GatsbyImage、修复了 session storage 不可用时的处理、gatsby-plugin-schema-snapshot初始化时正确解除文件链接等。以上修复分别来自社区成员与核心团队的贡献相关 PR 详见发布说明原文社区成员包括 newhouse、AnilSeervi、janaagaard75、varghesejose2020、jazanne、fedek6、jfgilmore、ferdi05、axe312ger、herecydev、homearanya、njbmartin、merceyz、ShaunDychko 等感谢他们对本版本的贡献。总结Gatsby v4.6.0 是一次小而精的发布三项核心改动分别落在构建性能跨实例缓存rootNode/trackedRootNodes详见 graphql-runner.ts 与 node-model.js、开发体验gatsby-remark-images图片变更即时生效详见 index.js与插件生态健壮性gatsby-plugin-utils的 Schema 校验语义调整详见 validate.ts 与 test-plugin-options-schema.ts。对于插件作者而言最重要的动作是按本文迁移指南一节更新单元测试以适配testPluginOptionsSchema返回warnings/hasWarnings的新契约对于站点开发者升级后即可在后续构建中自然获得查询性能收益并摆脱改图必须gatsby clean的困扰。【免费下载链接】gatsbyReact-based framework with performance, scalability, and security built in.项目地址: https://gitcode.com/gh_mirrors/ga/gatsby创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
