NOTE
TIP对于拥有一定影响力的开源项目而言,可在 npm 官网查找它在某个大版本下的最新版本(带 lts/latest 标记)。
例如,查询 Node v16 和 Gatsby v3 下的最新版:


提升 Node 版本上限
:::danger 镜像 由于 CI 配置中调用了 rsync 包的相关命令,因此需要自行构建一个包含 rsync 模块的新镜像。 :::
image: node:10.18.1-rsyncimage: node:16.19.1-rsync{ "name": "root", "version": "0.1.0", "engines": { "node": "10.18.1" "node": ">= 16" } // ...}升级 Gatsby 及其相关插件
由于这些依赖为整个 monorepo 项目共用,因此安装时加上-W参数将其提升至项目根部的 package.json 中。
yarn add -W \gatsby@^3.15.0 \gatsby-plugin-image@^1.15.0 \gatsby-plugin-sharp@^3.15.0 \gatsby-plugin-sitemap@^4.11.0 \gatsby-plugin-react-helmet@^4.15.0 \gatsby-plugin-styled-components@^4.15.0 \gatsby-source-filesystem@^3.15.0 \gatsby-source-contentful@^5.15.0 \gatsby-transformer-sharp@^3.15.0:::info 依赖安装策略 实际上在使用 npm/Yarn 等包管理器为 monorepo 项目安装依赖时,默认会将除可执行文件(.bin)之外的所有依赖包都安装到项目<根>目录下的 node_modules 中,此处仅提升公共依赖的「声明位置」以减少多个 package.json 文件维护同一份依赖版本数据的心智负担。 :::
问题处置
路由导航错误
import { navigate } from "gatsby";
navigate(path);在旧版中,Gatsby 默认会对传给navigate方法的path参数中多余的/进行去重处理:
//path//xxx -> /path/xxx而在新版中,移除了这一默认行为,若path存在多余的/则会导致路由导航错误,因此需自行对path做规范化处理:
import { navigate } from "gatsby";
/** * @param {string} path navigate path */function normalizePath(path) { return path.replace(/\/+/g, `/`);}
navigate(normalizePath(path));依赖相关问题
❗️❗️❗️ 添补http-proxy-middleware依赖与配置,解决本地代理错误问题:

yarn add -W -D http-proxy-middleware const { createProxyMiddleware } = require('http-proxy-middleware')
const middleware = createProxyMiddleware({ secure: false, target: 'https://xxx.xxx.xxx' })
/** @type {import("gatsby").GatsbyConfig} */module.exports = { proxy: [ { url: 'https://xxx.xxx.xxx', prefix: '/api-xxx-1' }, { url: 'https://xxx.xxx.xxx', prefix: '/api-xxx-2' }, ], developMiddleware: (app) => app.use('/api-xxx-1', middleware).use('/app-xxx-2', middleware),}❗️❗️❗️ 移除@hot-loader/react-dom依赖与配置,目前已无用:
exports.onCreateWebpackConfig = ({ getConfig, stage }) => { const config = getConfig()
if (stage.startsWith('develop') && config.resolve) { config.resolve.alias = { ...config.resolve.alias, 'react-dom': '@hot-loader/react-dom', } }}❗️❗️❗️ 添补gatsby-plugin-compile-es6-packages依赖与配置,以解决在 Gatsby v3 版本下,插件gatsby-plugin-image在 monorepo 项目里不能正常运作的问题:
yarn add -W gatsby-plugin-compile-es6-packagesmodule.exports = { plugins: [ { resolve: "gatsby-plugin-compile-es6-packages", options: { modules: ["gatsby-plugin-image"], }, }, ],};❗️❗️❗️ 由于 Webpack v5 版本不再提供自动引入 Node 模块对应的 polyfills 功能,因此需自行添加依赖与配置:

yarn add -W -D process path-browserify/** * @typedef {import("webpack").Configuration} WebpackConfiguration */
/** @type {(config: WebpackConfiguration) => WebpackConfiguration} */const defineWebpackConfig = (config) => config;
/** @type {(args: import("gatsby").CreateWebpackConfigArgs) => void} */exports.onCreateWebpackConfig = ({ stage, actions, plugins }) => { const config = defineWebpackConfig({ plugins: [], resolve: { fallback: { path: require.resolve("path-browserify"), }, }, });
if (stage === "develop" || stage === "build-javascript") { config.plugins?.push(plugins.provide({ process: "process/browser" })); }
actions.setWebpackConfig(config);};迁移 gatsby-plugin-image
TIP官方迁移指南:https://www.gatsbyjs.com/docs/reference/release-notes/image-migration-guide/
官方插件文档:https://www.gatsbyjs.com/docs/reference/built-in-components/gatsby-plugin-image/
Step 1 - 配置添补
module.exports = { plugins: [ // ... "gatsby-plugin-image", ],};Step 2 - 导入变更
import Img from 'gatsby-image'import { GatsbyImage } from 'gatsby-plugin-image'Step 3 - 查询变更
query { banner: file(relativePath: { eq: "xxx/xxx.png" }) { childImageSharp { fluid(maxWidth: 1920, quality: 100) { ...GatsbyImageSharpFluid }
gatsbyImageData(quality: 100) } }}Step 4 - 使用变更
import { getImageData } from 'gatsby-plugin-image'
function Comp() { return ( <Fragment> <GatsbyImage fluid={banner.childImageSharp.fluid} />
{/* 需要必传 alt 属性 */} <GatsbyImage alt="xxx-xxx" image={getImageData(banner)} />
{/* or */} <GatsbyImage alt="xxx-xxx" image={banner.childImageSharp.gatsbyImageData} /> </Fragment> )}<GatsbyImage fluid={[ data.bannerMb.childImageSharp.fluid, { ...data.banner.childImageSharp.fluid, media: `(min-width: 813px)`, }, ]}/>
<GatsbyImage alt='xxx-banner' image={isSmall ? getImageData(data.bannerMb) : getImageData(data.banner)}/>迁移 gatsby-plugin-sitemap
Step 1 - 配置变更
module.exports = { plugins: [ { resolve: 'gatsby-plugin-sitemap', options: { exclude: ['*/404/', '*/404.html'], excludes: ['*/404/', '*/404.html'], }, }, ],}Step 2 - 规则变更
:::danger 站点地图抓取规则
插件gatsby-plugin-sitemap在新版本中遵循了索引文件的定义规范,改变了创建 sitemap.xml 的规则:
旧规则:直接创建一个 xxx-sitemap.xml 文件。
新规则:先对 URL 条目进行拆分,每 45000 条拆分为一个 xxx-sitemap-0.xml 文件,以此类推 1-2-3-…,最后再创建一个 sitemap-index.xml 索引文件,重定向到拆分后的 xml 文件。 :::

由于百度不支持 sitemap-index.xml 这类索引文件的重定向(据说是为了打击非法产业与泛目录类网站),并且gatsby-plugin-sitemap也无选项可配置回退旧规则,因此需与营销同事协调改动。
Step 2.1 - 配置变更
由于规则从直接创建文件调整为了文件拆分,因此输出的是一个目录,对输出地址做语义化处理:
module.exports = { plugins: [ { resolve: 'gatsby-plugin-sitemap', options: { output: `/xxx-sitemap.xml`, output: `/xxx-sitemap`, }, }, ],}Step 2.2 - 上传地址
打包后输出的目录结构如下所示:
public└─ xxx-sitemap ├─ sitemap-0.xml └─ sitemap-index.xml需要营销同事重新上传此地址,例如:https://domain/package-name/xxx-sitemap/sitemap-0.xml。
