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

官方迁移指南

TIP

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

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

version-node

version-gatsby

提升 Node 版本上限#

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

.gitlab-ci.yml
image: node:10.18.1-rsync
image: node:16.19.1-rsync
package.json
{
"name": "root",
"version": "0.1.0",
"engines": {
"node": "10.18.1"
"node": ">= 16"
}
// ...
}

升级 Gatsby 及其相关插件#

由于这些依赖为整个 monorepo 项目共用,因此安装时加上-W参数将其提升至项目根部的 package.json 中。

Bash
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 文件维护同一份依赖版本数据的心智负担。 :::

问题处置#

路由导航错误#

Code
import { navigate } from "gatsby";
navigate(path);

在旧版中,Gatsby 默认会对传给navigate方法的path参数中多余的/进行去重处理:

//path//xxx -> /path/xxx

而在新版中,移除了这一默认行为,若path存在多余的/则会导致路由导航错误,因此需自行对path做规范化处理:

Code
import { navigate } from "gatsby";
/**
* @param {string} path navigate path
*/
function normalizePath(path) {
return path.replace(/\/+/g, `/`);
}
navigate(normalizePath(path));

依赖相关问题#

❗️❗️❗️ 添补http-proxy-middleware依赖与配置,解决本地代理错误问题:

proxy-error

Bash
yarn add -W -D http-proxy-middleware
gatsby-config.js
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依赖与配置,目前已无用:

gatsby-node.js
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 项目里不能正常运作的问题:

Bash
yarn add -W gatsby-plugin-compile-es6-packages
gatsby-config.js
module.exports = {
plugins: [
{
resolve: "gatsby-plugin-compile-es6-packages",
options: {
modules: ["gatsby-plugin-image"],
},
},
],
};

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

webpack-polyfills

Bash
yarn add -W -D process path-browserify
gatsby-node.js
/**
* @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 - 配置添补

gatsby-config.js
module.exports = {
plugins: [
// ...
"gatsby-plugin-image",
],
};

Step 2 - 导入变更

Code
import Img from 'gatsby-image'
import { GatsbyImage } from 'gatsby-plugin-image'

Step 3 - 查询变更

GraphQL
query {
banner: file(relativePath: { eq: "xxx/xxx.png" }) {
childImageSharp {
fluid(maxWidth: 1920, quality: 100) {
...GatsbyImageSharpFluid
}
gatsbyImageData(quality: 100)
}
}
}

Step 4 - 使用变更

React JSX
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>
)
}
React JSX - 不再支持数组形式,请使用条件判断代替
<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 - 配置变更

gatsby-config.js
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 - 配置变更

由于规则从直接创建文件调整为了文件拆分,因此输出的是一个目录,对输出地址做语义化处理:

gatsby-config.js
module.exports = {
plugins: [
{
resolve: 'gatsby-plugin-sitemap',
options: {
output: `/xxx-sitemap.xml`,
output: `/xxx-sitemap`,
},
},
],
}

Step 2.2 - 上传地址

打包后输出的目录结构如下所示:

Dir Tree
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