Gatsby GraphQL Typegen 完整指南:用自动生成类型告别手写查询类型
【免费下载链接】gatsbyReact-based framework with performance, scalability, and security built in.项目地址: https://gitcode.com/gh_mirrors/ga/gatsby
导读
本指南讲解 Gatsby 的GraphQL Typegen自动类型生成功能:只要在gatsby-config中开启graphqlTypegen,Gatsby 就会在gatsby develop时根据你的 GraphQL 查询与 schema 自动生成 TypeScript 类型(默认输出到src/gatsby-types.d.ts),并为你提供 IDE 内联提示(IntelliSense)、GraphQL 查询自动补全与 ESLint 校验。读完本文,你将掌握如何开启与配置该功能、使用全局Queries命名空间、配合 GraphQL fragments 复用类型、接入 VSCode GraphQL 插件以及用graphql-eslint强制查询命名规范。
适用前提:Gatsby 项目使用
gatsby@4.15.0或更高版本,并已按 Gatsby with TypeScript 配置好 TypeScript。该功能默认只在gatsby develop期间生成文件(构建阶段不生成)。
前置条件
在开始之前,确认你的项目满足以下条件:
Gatsby 版本:
gatsby@4.15.0或更高版本(GraphQL Typegen 在gatsby@4.15.0中引入)。开启配置项:在
gatsby-config中将graphqlTypegen设为true:module.exports = { graphqlTypegen: true, }tsconfig.json包含源码目录:项目中需要有tsconfig.json,且"include"需覆盖生成文件路径,例如:{ "compilerOptions": { /* ... */ }, "include": ["./src/**/*"] }完整示例可参考仓库中的 examples/using-graphql-typegen/tsconfig.json,它额外包含了
./gatsby-node.ts、./gatsby-config.ts与./plugins/**/*。可选:如果你使用 VSCode,可安装 GraphQL 扩展 以获得查询自动补全(详见后文"配置 VSCode GraphQL 插件"一节)。
使用自动生成的Queries类型
为了让示例正常运行,请先在gatsby-config的siteMetadata中准备一个title字段:
module.exports = { siteMetadata: { title: `My Gatsby Site`, }, graphqlTypegen: true, }示例项目的完整配置见 examples/using-graphql-typegen/gatsby-config.ts。
第一步:启动开发服务器
运行gatsby develop。当服务器就绪后,你会在终端底部看到一条日志:
Generating GraphQL and TypeScript types这条日志来自 Gatsby 的 typegen 服务。从源码看,该服务依次执行三步写入:graphQLTypegen 会调用writeGraphQLSchema写入 schema、writeGraphQLFragments写入 fragments,最后调用writeTypeScriptTypes生成 TypeScript 类型,整个过程被包裹在 reporter 的活动计时器中。
第二步:查看生成的类型文件
Gatsby 会生成一个类型声明文件,默认位于src/gatsby-types.d.ts,其中包含你所有查询对应的 TypeScript 类型。你的tsconfig.json需要 include 该文件,这样就能在项目任何地方访问Queries命名空间(全局declare namespace Queries)。
第三步:创建一个使用类型的页面
在src/pages/typegen.tsx创建新页面:
import * as React from "react" import { graphql, PageProps } from "gatsby" const TypegenPage = ({ data }: PageProps) => { return ( <main style={pageStyles}> <p>Site title: TODO</p> <hr /> <p>Query Result:</p> <pre> <code>{JSON.stringify(data, null, 2)}</code> </pre> </main> ) } export default TypegenPage export const query = graphql` query TypegenPage { site { siteMetadata { title } } } `关键点:查询必须有名字(如query TypegenPage {}),否则自动类型生成无法工作。建议查询名与 React 组件同名,并使用 PascalCase 命名。你可以通过graphql-eslint(见下文)强制执行这一约定。
第四步:在组件中使用Queries命名空间
在 React 组件中访问Queries命名空间,并使用TypegenPageQuery类型:
({ data }: PageProps<Queries.TypegenPageQuery>)当你像下面这样写出站点标题时,就能获得 TypeScript IntelliSense 提示:
<p>Site title: {data.site?.siteMetadata?.title}</p>注意这里使用了可选链?.,原因见下文"Non-Nullable 类型"一节。
配置gatsby-config中的选项
除了布尔值,graphqlTypegen还可以设置为一个对象来细化配置:
module.exports = { graphqlTypegen: { typesOutputPath: `src/gatsby-types.d.ts`, documentSearchPaths: [`./gatsby-node.ts`, `./plugins/**/gatsby-node.ts`], }, }| 配置项 | 说明 |
|---|---|
typesOutputPath | 类型文件的输出路径。默认值为src/gatsby-types.d.ts。修改后请同步更新tsconfig.json的"include",把新路径包含进去。 |
documentSearchPaths | 覆盖被扫描以提取 GraphQL 查询的文档搜索路径。默认值为./gatsby-node.ts与./plugins/**/gatsby-node.ts(见 ts-codegen.ts)。 |
从源码看,这两个默认值定义在 ts-codegen.ts:DEFAULT_TYPES_OUTPUT_PATH = 'src/gatsby-types.d.ts',DEFAULT_DOCUMENT_SEARCH_PATHS = ['./gatsby-node.ts', './plugins/**/gatsby-node.ts']。同时,Joi 校验层(joi.ts)允许graphqlTypegen为布尔值或对象,且两个字段均带默认值,说明它们可省略。
另外,documentSearchPaths的机制值得说明:生成gatsby-node.ts中的查询类型时,Gatsby 使用loadDocuments+CodeFileLoader扫描这些路径,并通过pluckConfig仅提取来自gatsby包的graphql标签模板(见 ts-codegen.ts)。
Non-Nullable 类型
由于 Gatsby 推断所有字段(除非用户提供了显式 schema),字段默认都是可空的。这意味着在 GraphQL Typegen 中,字段可能为null——正如上面的示例,你必须写成data.site?.siteMetadata?.title,因为siteMetadata和title都是可空的。
如果你确定siteMetadata.title始终存在,可以使用 Gatsby 的 schema 自定义 API 显式声明字段类型:
import { GatsbyNode } from "gatsby" export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] = ({ actions }) => { actions.createTypes(` type Site { siteMetadata: SiteMetadata! } type SiteMetadata { title: String! } `) }!表示非空。关于如何显式定义类型,可阅读 Customizing the GraphQL schema guide。
生成代码的类型选项也印证了可空设计:ts-codegen.ts中设置avoidOptionals: true且maybeValue: 'T | null',即字段类型被生成为T | null而非可选属性(见 ts-codegen.ts)。
GraphQL fragments
Fragments 允许你在整个站点中复用 GraphQL 查询的片段,并把查询的特定部分与单个文件内聚。可参考 Using GraphQL fragments guide。
在 GraphQL Typegen 的语境下,fragments 让你能为查询的嵌套部分获得独立的 TypeScript 类型——因为每个 fragment 都会成为自己的 TypeScript 类型。你可以用这些类型来标注消费 GraphQL 数据的组件参数。
以下示例(同样来自 using-graphql-typegen 示例)展示了一个接收buildTime参数的Info组件。该组件和它的SiteInformationfragment 随后被用在src/pages/index.tsx中:
import * as React from "react" import { graphql } from "gatsby" const Info = ({ buildTime }: { buildTime?: any }) => { return ( <p> Build time: {buildTime} </p> ) } export default Info export const query = graphql` fragment SiteInformation on Site { buildTime } `# Rest of the page above... query IndexPage { site { ...SiteInformation } }这样就会生成一个SiteInformationFragmentTypeScript 类型,你可以直接在Info组件中使用:
const Info = ({ buildTime }: { buildTime?: Queries.SiteInformationFragment["buildTime"] }) => {}仓库示例 examples/using-graphql-typegen/src/components/info.tsx 正是这样实现的,对应页面查询见 examples/using-graphql-typegen/src/pages/index.tsx。注意buildTime类型是可空的(?),这与前面讲的"推断字段默认可空"一致。此外,源码中为 typescript-operations 插件设置了exportFragmentSpreadSubTypes: true(见 ts-codegen.ts),这保证了 fragment 展开子类型会被导出。
Tips
- 保存文件后类型才更新:当你给 GraphQL 查询新增字段时,需要保存文件,自动生成的文件才会更新——生成的文件只在文件保存时刷新。
- 图片类型开箱即用:使用
gatsby-plugin-image(以及 Image CDN)时,gatsbyImageData与gatsbyImage会自动获得正确的 TypeScript 类型。这是因为生成配置中内置了标量映射:GatsbyImageData: import('gatsby-plugin-image').IGatsbyImageData、Date: string、JSON: Record<string, unknown>(见 ts-codegen.ts)。 - 建议加入
.gitignore:推荐把src/gatsby-types.d.ts加入.gitignore,因为它是机器生成的代码,并且信息与页面查询等内容重复。生成文件头部也明确写有/* THIS FILE IS AUTOGENERATED. CHANGES WILL BE LOST ON SUBSEQUENT RUNS. */以及/* eslint-disable */、/* prettier-ignore */标记(见 ts-codegen.ts),再次印证它不应被手改或提交。
配置 VSCode GraphQL 插件
在 VSCode 中安装 GraphQL 扩展。
在项目根目录创建
graphql.config.js,内容如下:module.exports = require("./.cache/typegen/graphql.config.json")VSCode 扩展会读取
graphql.config.js,并复用 Gatsby.cache目录中的自动生成文件。关于graphql.config.js的更多信息可查看 GraphQL Config 文档。重启 VSCode,让 GraphQL 扩展生效。
启动开发服务器
gatsby develop。打开任意查询(例如
src/pages下的页面查询),使用Ctrl + Space(也可用Shift + Space作为替代快捷键)即可获得类似 GraphiQL 的自动补全。
该文件从哪来?从源码看,Gatsby 会生成三份产物到.cache/typegen/目录:schema.graphql、fragments.graphql与graphql.config.json(见 file-writes.ts)。其中graphql.config.json的documents字段被设置为['src/**/**.{ts,js,tsx,jsx}', fragments 文件],即 IDE 会自动扫描src下的源码文件并合并 fragments,从而支持跨文件的自动补全。
多 GraphQL 项目
如果你的仓库包含多个 GraphQL 项目(包括 Gatsby),可以使用projects键配置:
module.exports = { projects: { site: require("./.cache/typegen/graphql.config.json"), other: { // other config } } }子目录场景
如果 Gatsby 项目位于子目录(例如site),配置应改为:
module.exports = require("./site/.cache/typegen/graphql.config.json")graphql-eslint
你可以选择使用graphql-eslint来 lint 你的 GraphQL 查询。它能无缝对接上一步创建的graphql.config.js。
以下指南假设你还没有任何 ESLint 配置。如果你已经在使用 ESLint,需要自行适配你的配置,并参考
graphql-eslint文档。
安装依赖:
npm install --save-dev eslint @graphql-eslint/eslint-plugin @typescript-eslint/eslint-plugin @typescript-eslint/parser在
package.json中添加两个脚本:{ "scripts": { "lint": "eslint --ignore-path .gitignore .", "lint:fix": "npm run lint -- --fix" }, }创建
.eslintrc.js配置 ESLint:module.exports = { root: true, overrides: [ { files: ['*.ts', '*.tsx'], processor: '@graphql-eslint/graphql', parser: "@typescript-eslint/parser", extends: [ "eslint:recommended", "plugin:@typescript-eslint/recommended" ], env: { es6: true, }, }, { files: ['*.graphql'], parser: '@graphql-eslint/eslint-plugin', plugins: ['@graphql-eslint'], rules: { '@graphql-eslint/no-anonymous-operations': 'error', '@graphql-eslint/naming-convention': [ 'error', { OperationDefinition: { style: 'PascalCase', forbiddenPrefixes: ['Query', 'Mutation', 'Subscription', 'Get'], forbiddenSuffixes: ['Query', 'Mutation', 'Subscription'], }, }, ], }, }, ], }在项目根目录创建
graphql.config.js:module.exports = require("./.cache/typegen/graphql.config.json")启动 Gatsby 开发服务器
gatsby develop,确认.cache/typegen/graphql.config.json已生成。
现在你可以运行npm run lint和npm run lint:fix检查 GraphQL 查询(例如它们是否已命名)。通过@graphql-eslint/no-anonymous-operations规则,任何匿名的 GraphQL 操作都会被标记为错误,这正好呼应了前文"查询必须有名字"的硬性要求。
额外资源
- Gatsby with TypeScript
- VSCode GraphQL Plugin
- IntelliJ GraphQL Plugin
- gatsby-config Option
- 可运行示例:examples/using-graphql-typegen(包含
gatsby-config.ts、gatsby-node.ts、graphql.config.js、tsconfig.json与完整页面/组件源码)
【免费下载链接】gatsbyReact-based framework with performance, scalability, and security built in.项目地址: https://gitcode.com/gh_mirrors/ga/gatsby
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考