1162 字
6 分钟
Gatsby迁移指南:v2 To v3
NOTE

官方迁移指南

TIP

对于拥有一定影响力的开源项目而言,可在 npm 官网查找它在某个大版本下的最新版本(带 lts/latest 标记)。

例如,查询 Node v16Gatsby v3 下的最新版:

version-node

version-gatsby

提升 Node 版本上限#

:::danger 镜像 由于 CI 配置中调用了 rsync 包的相关命令,因此需要自行构建一个包含 rsync 模块的新镜像。 :::

- image: node:10.18.1-rsync
+ image: 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依赖与配置,解决本地代理错误问题:

proxy-error

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-packages
module.exports = {
  plugins: [
    {
      resolve: "gatsby-plugin-compile-es6-packages",
      options: {
        modules: ["gatsby-plugin-image"],
      },
    },
  ],
};

❗️❗️❗️ 由于 Webpack v5 版本不再提供自动引入 Node 模块对应的 polyfills 功能,因此需自行添加依赖与配置

webpack-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 文件。 :::

baidu-sitemap-failure

由于百度不支持 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

baidu-sitemap-success

Gatsby迁移指南:v2 To v3
https://www.hzhi.top/posts/gatsby-v2-to-v3/
作者
Jim的独立博客
发布于
2023-07-26
许可协议
CC BY-NC-SA 4.0