将Gatsby-starter-blog升级为TypeScript [2022年12月版]
首先。
上个月我个人创建了一个博客,在使用Gatsby.js的gatsby-starter-blog模板时,默认情况下没有使用TypeScript,因此我想介绍一下这个步骤。
在网络上的相关文章中,有一些关于将config文件进行ts化的技巧,但现在config文件的ts化已经得到官方支持,使得TS迁移更加简单。本文将介绍这一点。
代码经过测试后,已上传到作者的代码库。如果出现无法运行的情况,请参考以下链接:
https://github.com/ironkicka/gatsby-starter-blog-typescript
“Gatsby Starter Blog 是什么?”
这是Gatsby.js提供的一种称为Starter的模板之一。
起始项目是官方或社区维护的标准化Gatsby网站。
与新手一起工作 | Gatsby
Starter有很多种类,除了gatsby-starter-blog之外,还可以在以下页面查看示例网站。
入门图书馆 | 盖茨比
gatsby-starter-blog具有以下特点:
gatsby-starter-blog的特点包括:
由于我经常使用Markdown做各种笔记,所以我决定使用这个gatsbyjs/gatsby-starter-blog!如果你也想直接将Markdown内容用作文章,我推荐你使用它!
操作步骤
根据起始代码创建一个模板。
请执行以下命令以创建一个模板。
npx gatsby new myBlog https://github.com/gatsbyjs/gatsby-starter-blog
将Config文件转化为ts文件
gatsby-config.js – gatsby配置文件。
请您进行以下两项更改。
拡張子をtsにする
エクスポートの記述をESモジュール形式にする(これ自体は行わなくてもエラーは出ないです)
変更前
module.exports = {
siteMetadata: {
title: `Gatsby Starter Blog`,
author: {
name: `Kyle Mathews`,
summary: `who lives and works in San Francisco building useful things.`,
},
description: `A starter blog demonstrating what Gatsby can do.`,
siteUrl: `https://gatsbystarterblogsource.gatsbyjs.io/`,
social: {
twitter: `kylemathews`,
},
},
…
}
改变后
import type { GatsbyConfig } from "gatsby"
const config: GatsbyConfig = {
siteMetadata: {
title: `Gatsby Starter Blog`,
author: {
name: `Kyle Mathews`,
summary: `who lives and works in San Francisco building useful things.`,
},
description: `A starter blog demonstrating what Gatsby can do.`,
siteUrl: `https://gatsbystarterblogsource.gatsbyjs.io/`,
social: {
twitter: `kylemathews`,
},
},
...
}
export default config
在这个阶段,由于没有为GraphQL查询结果设置类型,所以会出现错误,但构建本身应该是成功的。GraphQL的类型化将在下面进行说明。
Gatsby-node.js -> 盖茨比节点.js
tsconfig.jsを作成する
CommonJSのモジュールであるpathをimportできるようにtsconfigを作成し、esModuleInteropをtrueにします。ただし、デフォルトでtrueなので以下のコマンドでtsconfig.jsonを作るだけで大丈夫です。
npx tsc -init
拡張子をtsにする
エクスポートの記述をESモジュール形式にする(これ自体は行わなくてもエラーは出ないです)
改动之前
const path = require(`path`)
const { createFilePath } = require(`gatsby-source-filesystem`)
...
exports.createPages = async ({ graphql, actions, reporter }) => {
...
}
exports.onCreateNode = ({ node, actions, getNode }) => {
...
}
exports.createSchemaCustomization = ({ actions }) => {
...
}
改动后
import { Actions, GatsbyNode } from "gatsby"
import path from "path"
import { createFilePath } from "gatsby-source-filesystem"
export const createPages: GatsbyNode["createPages"] = async ({ graphql, actions, reporter }) => {
...
}
export const onCreateNode: GatsbyNode["onCreateNode"] = ({ node, actions, getNode }) => {
...
}
export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] = async ({ actions }: { actions: Actions}) => {
...
}
与gatsby-config.ts类似,由于当前尚未对graphQL查询结果设置类型,因此会出现错误,但构建本身应该是成功的。我们将在后面的解释中对GraphQL进行类型化说明。
盖茨比浏览器.js
将文件扩展名更改为.tsx。
默认情况下,在TS中没有问题,但在这里,我们有时会导出返回JSX.Element的函数,所以为了避免出现错误,我们会将文件扩展名更改为tsx。
这次我们不会用到,但是举个例子,当我们使用Recoil时,可以按以下方式使用。
export const wrapRootElement = ({element,props}:any)=>{
return <RecoilRoot {...props} >{element}</RecoilRoot>
}
gatsby-ssr.js 的原生中文释义:《了不起的盖茨比-服务端渲染.js》。
-
- 拡張子をtsにする
- エクスポートの記述をESモジュール形式にする(これ自体は行わなくてもエラーは出ないです)
变更前
exports.onRenderBody = ({ setHtmlAttributes }) => {
setHtmlAttributes({ lang: `en` })
}
修改后
export const onRenderBody = ({ setHtmlAttributes }:any) => {
setHtmlAttributes({ lang: `en` })
}
为GraphQL的结果添加类型
-
- 安装插件
-
- 由于有一个名为gatsby-plugin-typegen的插件可用,因此请安装它
-
- npm i gatsby-plugin-typegen
gatsby-plugin-typegen | Gatsby
将以下内容添加到gatsby-config.ts中
const config: GatsbyConfig = {
…
{
resolve: “gatsby-plugin-typegen”,
options: {
emitSchema: {
“src/__generated__/gatsby-schema.graphql”: true,
“src/__generated__/gatsby-introspection.json”: true
},
emitPluginDocuments: {
“src/__generated__/gatsby-plugin-documents.graphql”: true
}
}
},
],
}
请重新运行gatsby develop以完成添加
如果出现以下日志并且文件已创建,则表示成功。
success [typegen] emit schema into src/__generated__/gatsby-schema.graphql – 0.462s
success [typegen] emit 3rd-party documents into src/__generated__/gatsby-plugin-documents.graphql – 0.276s
success [typegen] generate type definitions to src/__generated__/gatsby-types.d.ts. (language: TypeScript) – 0.278s
success [typegen] emit schema into src/__generated__/gatsby-introspection.json – 0.366s
输出文件
__generated__
├── gatsby-introspection.json
├── gatsby-plugin-documents.graphql
├── gatsby-schema.graphql
└── gatsby-types.d.ts
应用类型
gatsby-node.ts
更改前
const result = await graphql(`
{
allMarkdownRemark(sort: { frontmatter: { date: ASC } }, limit: 1000) {
nodes {
id
fields {
slug
}
}
}
}
`)
const posts = result.data.allMarkdownRemark.nodes
// 创建博客文章页面
// 但前提是在“content/blog”路径下至少找到一个markdown文件(在gatsby-config.js中定义)
// “context”在模板中作为属性和GraphQL变量可用
if (posts.length > 0) {
posts.forEach((post, index) => {
const previousPostId = index === 0 ? null : posts[index – 1].id
const nextPostId = index === posts.length – 1 ? null : posts[index + 1].id
createPage({
path: post.fields.slug,
component: blogPost,
context: {
id: post.id,
previousPostId,
nextPostId,
},
})
})
}
更改后
const result = await graphql<{ allMarkdownRemark: GatsbyTypes.Query[“allMarkdownRemark”]}>(`
{
allMarkdownRemark(sort: { frontmatter: { date: ASC } }, limit: 1000) {
nodes {
id
fields {
slug
}
}
}
}
`)
const posts = result.data?.allMarkdownRemark.nodes
// 创建博客文章页面
// 但前提是在“content/blog”路径下至少找到一个markdown文件(在gatsby-config.js中定义)
// “context”在模板中作为属性和GraphQL变量可用
if(!posts) return;
if (posts.length > 0) {
posts.forEach((post, index) => {
const previousPostId = index === 0 ? null : posts[index – 1].id
const nextPostId = index === posts.length – 1 ? null : posts[index + 1].id
createPage({
path: post.fields?.slug!,
component: blogPost,
context: {
id: post.id,
previousPostId,
nextPostId,
},
})
})
}
gatsby-config.ts
更改前
{
resolve: `gatsby-plugin-feed`,
options: {
…
feeds: [
{
serialize: ({ query: { site, allMarkdownRemark }}) => {
return allMarkdownRemark.nodes.map(node => {
return Object.assign({}, node.frontmatter, {
description: node.excerpt,
date: node.frontmatter.date,
url: site.siteMetadata.siteUrl + node.fields.slug,
guid: site.siteMetadata.siteUrl + node.fields.slug,
custom_elements: [{ “content:encoded”: node.html }],
})
})
},
…
]
}
}
更改后
{
resolve: `gatsby-plugin-feed`,
options: {
…
feeds: [
{
serialize: ({ query: { site, allMarkdownRemark } }:{query:{site:GatsbyTypes.Query[‘site’],allMarkdownRemark:GatsbyTypes.Query[“allMarkdownRemark”]}}) => {
return allMarkdownRemark.nodes.map(node => {
return Object.assign({}, node.frontmatter, {
description: node.excerpt,
date: node.frontmatter?.date,
url: site?.siteMetadata?.siteUrl! + node.fields?.slug,
guid: site?.siteMetadata?.siteUrl! + node.fields?.slug,
custom_elements: [{ “content:encoded”: node.html }],
})
})
},
…
]
}
}
这样一来,应该已经解决了配置文件中与GraphQL相关的错误!
将组件转换为tsx的格式
接下来,我们将把用于页面显示的各种组件转化为TS格式。
将src/pages文件夹下的组件转换为tsx。
以上意味着暂时结束对src/pages文件夹下的TS转换工作!
将components文件夹下的所有组件转换为tsx格式。
尽管在这一点上页面本身会显示,但我认为在index.tsx和404.tsx中会出现以下错误。
这是因为该组件Seo尚未转换为tsx,并且props没有定义类型。因此,在此部分中,我们将包括components目录下的组件,其中包括Seo组件,并将其转换为tsx文件。
首先,作为准备工作,将以下内容添加到tsconfig.json的compilerOptions中。
"jsx": "react"
如果不这样做,就会出现以下类似的错误并被责备。
Cannot use JSX unless the '--jsx' flag is provided
那么让我们将每个组件转为tsx形式吧。
将位于templates目录下的blog-post.js文件转换成tsx格式。
最后,我们将将用于文章详细页面的组件blog-post.js进行tsx化。 这里有两个步骤。
-
- 将文件扩展名更改为.tsx
-
- 为类型进行标注
-
- 为文件中的两个组件BlogPostTemplate和Head添加以下类型。值得注意的是,在BlogPostTemplate中,由于将string | undefined传递给了期望字符串的位置,所以会出现一些错误。有关详细信息,请参阅存储库中的此处。
-
- const BlogPostTemplate = ({
-
- data: { previous, next, site, markdownRemark: post },
-
- location,
-
- }: PageProps) => {
-
- …
-
- }
export const Head = ({ data: { markdownRemark: post }
}: PageProps) => {
return (
)
}
在gatsby-node.ts中修改引用blog-post.js的部分
最后,请参考gatsby-node.ts。将引用模板的路径从./src/templates/blog-post.js更改为./src/templates/blog-post.tsx,然后完成!
const blogPost = path.resolve(`./src/templates/blog-post.tsx`)
以上就是gatsby-starter-blog的TS化完成了。最终它应该具有以下结构。
.
├── LICENSE
├── README.md
├── content
│ └── blog
│ ├── hello-world
│ │ ├── index.md
│ │ └── salty_egg.jpg
│ ├── my-second-post
│ │ └── index.md
│ └── new-beginnings
│ └── index.md
├── gatsby-browser.tsx
├── gatsby-config.ts
├── gatsby-node.ts
├── gatsby-ssr.ts
├── package-lock.json
├── package.json
├── public
├── node_modules
├── src
│ ├── __generated__
│ │ ├── gatsby-introspection.json
│ │ ├── gatsby-plugin-documents.graphql
│ │ ├── gatsby-schema.graphql
│ │ └── gatsby-types.d.ts
│ ├── components
│ │ ├── bio.tsx
│ │ ├── layout.tsx
│ │ └── seo.tsx
│ ├── global.d.ts
│ ├── images
│ │ ├── gatsby-icon.png
│ │ └── profile-pic.png
│ ├── normalize.css
│ ├── pages
│ │ ├── 404.tsx
│ │ └── index.tsx
│ ├── style.css
│ └── templates
│ └── blog-post.tsx
├── static
│ ├── favicon.ico
│ └── robots.txt
└── tsconfig.json
提示
在将TS文件转化的过程中,如果发生了错误或者变更没有被正确地反映出来,您可以尝试删除.cache文件夹。如果不这么做,即使您在TS/TSX文件中重新创建,gatsby也可能会引用先前的状态。
最后 (zui hou)
你觉得怎么样呢?我认为基本上只需要进行一些工作,没有特别困难的事情,能帮助大家个人博客的创建就好了。顺便说一下,对于我自己来说,设计和功能都还没达到理想的状态,所以还无法发布出来。。哈哈。
请看一下
-
- Gatsby の Config ファイルがいつの間にか TypeScript 対応していた
-
- Gatsby.jsのTypeScript化 2020
- Gatsby.js を完全TypeScript化する