尝试将GatsbyJS教程内容转换为TypeScript化

将教程4~8的内容转化为TypeScript格式。使用Gatsby中的数据。

通过使用名为gatsby-plugin-typegen的插件,可以很容易地为GraphQL类型生成代码,因此能够轻松地进行实现。(大部分参考了2020年的Gatsby.js TypeScript化,详见Zenn网站。)

请原谅关于细节的不足,为了使整个系统运行起来,最低限度的TS转化是必要的(当然,如果能提点意见会让我很高兴)。

项目产出

image.png

可以在TS化的情况下,用相同的图片启动http://localhost:9000/。

教程完成后的默认分支是用JavaScript编写的,请点击此处。
教程转换为TypeScript的完成形式分支,请点击此处。

步骤

    1. 搭建TypeScript环境

 

    1. 生成GraphQL类型

 

    将所有页面转化为TypeScript

1. TypeScript 的环境配置

使用”tsc –init”命令创建了初始化的tsconfig.json文件。

npx tsc --init

接下来我会下载两个必要的typescript库。

yarn add -D typescript
yarn add gatsby-plugin-typegen // gatsby-config.jsのplugins[]へ追記

tsconfig.json文件的设置

最开始,将strict模式的选项移除。

{
  "compilerOptions": {
    "target": "esnext",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
    "lib": ["dom", "es2017"],                             /* Specify library files to be included in the compilation. */
    "jsx": "react",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
    "outDir": "./build",                        /* Redirect output structure to the directory. */
    "rootDir": "./",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
    "noUnusedLocals": true,                /* Report errors on unused locals. */
    "noUnusedParameters": true,            /* Report errors on unused parameters. */
    "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. */
    "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. */
    "baseUrl": "src",                       /* Base directory to resolve non-absolute module names. */
    "esModuleInterop": true,                  /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */
    "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */
    "skipLibCheck": true,                     /* Skip type checking of declaration files. */
    "forceConsistentCasingInFileNames": true  /* Disallow inconsistently-cased references to the same file. */
    // "strict": true,                           /* Enable all strict type-checking options. */
    // "noImplicitAny": true,                 /* Raise error on expressions and declarations with an implied 'any' type. */
    // "strictNullChecks": true,              /* Enable strict null checks. */
    // "strictFunctionTypes": true,           /* Enable strict checking of function types. */
    // "strictBindCallApply": true,           /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
    // "strictPropertyInitialization": true,  /* Enable strict checking of property initialization in classes. */
  },
  "include": ["src/**/*", "gatsby-node/index.ts"],
  "exclude": ["node_modules", "public", "build", "src/templates/blog-post.tsx"],
}

将内容添加到gatsby-config.js文件中。

module.exports = {
  siteMetadata: {
    title: `typescriptのテスト gatsbyのチュートリアル参考:https://www.gatsbyjs.com/tutorial/part-four/`,
    description: `これは説明文章ですよ`,
    author: `gatsbyJSマン`,
  },
  plugins: [
    `gatsby-plugin-emotion`,
    {
      resolve: `gatsby-plugin-typography`,
      options: {
        pathToConfigModule: `src/utils/typography`,
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `src`,
        path: `${__dirname}/src/`,
      }
    },
    `gatsby-transformer-remark`,
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `GatsbyJS`,
        short_name: `GatsbyJS`,
        start_url: `/`,
        background_color: `#6b37bf`,
        theme_color: `#6b37bf`,
        display: `standalone`,
        icon: `src/images/icon.png`,
      },
    },
    `gatsby-plugin-offline`,
    `gatsby-plugin-react-helmet`,
    `gatsby-plugin-typegen`, // 型生成のプラグインを追加
  ],
}

2. 生成GraphQL的类型

我可以从任何地方开始,但首先我会在index.js文件中尝试生成GraphQL的类型。

将文件名更改为index.tsx。显然,如果保持不变,会显示类型错误(使用的是VSCode编辑器)。
我将其改写为以下方式。

/** @jsx jsx */ //emotionCSSのTS化のための記述
import React, {FC} from "react"
import { jsx, css } from '@emotion/react' // jsxを追加
import { Link, graphql } from "gatsby"
import { rhythm } from "../utils/typography"
import Layout from "components/layout"

const Home: FC<{ data: any }> = ({data}): any => { //型生成するまで適当にanyを突っ込んでおく
  return (
    <Layout>
      <div>
        <h1
          css={css`
            display: inline-block;
            border-bottom: 1px solid;
          `}
        >
          Amazing Pandas Eating Things
        </h1>
        <h4>{data.allMarkdownRemark.totalCount} Posts</h4>
        {data.allMarkdownRemark.edges.map(({ node }) => (
          <div key={node.id}>
            <Link
              to={node.fields.slug}
              css={css`
                text-decoration: none;
                color: inherit;
              `}
            >
            <h3
              css={css`
                margin-bottom: ${rhythm(1 / 4)};
              `}
            >
              {node.frontmatter.title}{" "}
              <span
                css={css`
                  color: #bbb;
                `}
              >
                 {node.frontmatter.date}
              </span>
            </h3>
            <p>{node.excerpt}</p>
            </Link>
          </div>
        ))}
      </div>
    </Layout>
  )
}

export const query = graphql`
  query MarkdownOfIndex { //便宜上、任意で型の名前をつけておく(ただし、名前がなくても生成されるファイルの type Query オブジェクトの中に型が格納されているので取り出せば良い)
    allMarkdownRemark {
      totalCount
      edges {
        node {
          id
          frontmatter {
            title
            date(formatString: "DD MMMM, YYYY")
          }
          fields {
            slug
          }
          excerpt
        }
      }
    }
  }
`

export default Home

在这种情况下,

gatsby build

当你运行这样的操作后,会在src目录下生成一个”__ generated __”文件夹,其中包含了类型信息文件。
你可以通过文件搜索来找到”MarkdownOfIndex”,以确认生成的类型信息文件并将其提取出来。


type MarkdownOfIndexQueryVariables = Exact<{ [key: string]: never; }>;


type MarkdownOfIndexQuery = { readonly allMarkdownRemark: ( //この型を引っ張ってあげる
    Pick<MarkdownRemarkConnection, 'totalCount'>
    & { readonly edges: ReadonlyArray<{ readonly node: (
        Pick<MarkdownRemark, 'id' | 'excerpt'>
        & { readonly frontmatter: Maybe<Pick<MarkdownRemarkFrontmatter, 'title' | 'date'>>, readonly fields: Maybe<Pick<MarkdownRemarkFields, 'slug'>> }
      ) }> }
  ) };


使用Gatsby的PageProps库

回到 index.tsx 文件并添加 PageProps。

import { Link, graphql, PageProps } from "gatsby"

只要按照以下方式,将类型嵌入,就能够成功。

const Home: FC<PageProps<GatsbyTypes.MarkdownOfIndexQuery>> = ({data}) => {
  return (
    <Layout>
//以下略

3. 对src网页的所有内容进行TS转换。

按照与2相同的方法生成并应用类型。

建设之前的状态

尽量以最少的修改,将每个文件准备好可以进行构建的状态。如果在这个阶段有任何引起指责的地方,请随意添加“any”或其他方法来暂时解决。

/** @jsx jsx */
import React, {FC} from "react"
import { jsx, css } from "@emotion/react"
import { useStaticQuery, Link, graphql } from "gatsby"
import { rhythm } from "../utils/typography"

const Layout = ({ children }) => {
  const data = useStaticQuery<GatsbyTypes.LayoutSiteMetadataQuery>(
    graphql`
    query LayoutSiteMetadata {
      site {
        siteMetadata {
          title
        }
      }
    }
    `
  )
  return (
    <div
      css={css`
        margin: 0 auto;
        max-width: 700px;
        padding: ${rhythm(2)};
        padding-top: ${rhythm(1.5)};
      `}
    >
      <Link to={`/`}>
        <h3
          css={css`
            margin-bottom: ${rhythm(2)};
            display: inline-block;
            font-style: normal;
          `}
        >
          {data.site.siteMetadata.title}
        </h3>
      </Link>
      <Link
        to={`/about/`}
        css={css`
          float: right;
        `}
      >
        About
      </Link>
      {children}
    </div>
  )
}

export default Layout
import React from "react"
import PropTypes from "prop-types"
import { Helmet } from "react-helmet"
import { useStaticQuery, graphql } from "gatsby"

const SEO = ({ description, lang, meta, title }) => {
  const { site } = useStaticQuery<GatsbyTypes.SEOsiteMetadataQuery>(
    graphql`
      query SEOsiteMetadata {
        site {
          siteMetadata {
            title
            description
            author
          }
        }
      }
    `
  )
  const metaDescription = description || site.siteMetadata.description
  return (
    <Helmet
      htmlAttributes={{
        lang,
      }}
      title={title}
      titleTemplate={`%s | ${site.siteMetadata.title}`}
      meta={[
        {
          name: `description`,
          content: metaDescription,
        },
        {
          property: `og:title`,
          content: title,
        },
        {
          property: `og:description`,
          content: metaDescription,
        },
        {
          property: `og:type`,
          content: `website`,
        },
        {
          name: `twitter:card`,
          content: `summary`,
        },
        {
          name: `twitter:creator`,
          content: site.siteMetadata.author,
        },
        {
          name: `twitter:title`,
          content: title,
        },
        {
          name: `twitter:description`,
          content: metaDescription,
        },
      ].concat(meta)}
    />
  )
}
SEO.defaultProps = {
  lang: `en`,
  meta: [],
  description: ``,
}
SEO.propTypes = {
  description: PropTypes.string,
  lang: PropTypes.string,
  meta: PropTypes.arrayOf(PropTypes.object),
  title: PropTypes.string.isRequired,
}
export default SEO

import React from "react"
import { graphql } from "gatsby"
import Layout from "../components/layout"

const About = ({ data }) => {
  return (
    <Layout>
      <h1>About {data.site.siteMetadata.title}</h1>
      <p>
        We are the only site running on your computer dedicated to showing the
        best photos and videos of pandas eating lots of food.
      </p>
    </Layout>
  )
}

export const query = graphql`
  query AboutsiteMetadata {
    site {
      siteMetadata {
        title
      }
    }
  }
`

export default About



import React from "react"
import { graphql } from "gatsby"
import Layout from "../components/layout"

const MyFiles = ({data}) => {
  console.log(data)
  return (
    <Layout>
      <div>
        <h1>My Sites Files</h1>
        <table>
          <thead>
            <tr>
              <th>relativePath</th>
              <th>prettySize</th>
              <th>extension</th>
              <th>birthTime</th>
            </tr>
          </thead>
          <tbody>
            {data.allFile.edges.map(({ node }, index) => (
              <tr key={index}>
                <td>{node.relativePath}</td>
                <td>{node.prettySize}</td>
                <td>{node.extension}</td>
                <td>{node.birthTime}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </Layout>
  )
}

export const query = graphql`
  query {
    allFile {
      edges {
        node {
          relativePath
          prettySize
          extension
          birthTime(fromNow: true)
        }
      }
    }
  }
`

export default MyFiles

import React from "react"
import { graphql } from 'gatsby'
import Layout from "../components/layout"
import SEO from "../components/seo"

const BlogPost = ({data}) => {
  const post = data.markdownRemark
  return (
    <Layout>
      <SEO title={post.frontmatter.title} description={post.excerpt} />
      <div>
        <h1>{post.frontmatter.title}</h1>
        <div dangerouslySetInnerHTML={{ __html: post.html }}/>
      </div>
    </Layout>
  )
}

export const query = graphql`
  query($slug: String!) {
    markdownRemark(fields: { slug: { eq: $slug } }) {
      html
      frontmatter {
        title
      }
      excerpt
    }
  }
`

export default BlogPost

typography.js的文件名仅更改为typography.ts

gatsby build

将gatsby-node.js转化为TypeScript。

下一步是将gatsby-node.js转化为TS,因此需要安装ts-node。

yarn add -D ts-node

在将gatsby-node.js转换为TypeScript时,我们保留了gatsby-node.js文件名,并创建了一个名为gatsby-node/index.ts的用于TypeScript的文件夹和文件,并从这里引用。 参考:Gatsby.js的TypeScript化 2020

首先,将gatsby-node.js中的处理过程转化为TypeScript并添加到index.ts文件中。

import path from 'path'
import { createFilePath } from "gatsby-source-filesystem"
import { GatsbyNode } from 'gatsby'

export const onCreateNode: GatsbyNode["onCreateNode"] = ({ node, getNode, actions }) => {
  const { createNodeField } = actions
  if (node.internal.type === `MarkdownRemark`) {
    const slug = createFilePath({ node, getNode, basePath: `pages` })
    createNodeField({
      node,
      name: `slug`,
      value: slug,
    })
  }
}

export const createPages: GatsbyNode["createPages"] = async ({ graphql, actions }) => {
  const { createPage } = actions
  const result = await graphql<{ allMarkdownRemark: GatsbyTypes.Query["allMarkdownRemark"]}>(`
  {
      allMarkdownRemark {
        edges {
          node {
            fields {
              slug
            }
          }
        }
      }
  }
  `)
  const { data } = result || 'undefined';
  if( data === undefined) throw 'データが見つかりませんでした';

  data.allMarkdownRemark.edges.forEach(({node}) => {
    if(node.fields){
    createPage({
      path: node.fields.slug || '/undefined',
      component: path.resolve(`./src/templates/blog-post.tsx`),
      context: {
        slug: node.fields.slug
      }
    })
  }
  })
}

然而,gatsby-node.js将被重写为拉取gatsby-node/index.ts的代码。

"use strict"

require("ts-node").register({
  compilerOptions: {
    module: "commonjs",
    target: "esnext",
  },
})

require("./src/__generated__/gatsby-types")

const {
  createPages,
  onCreateNode,
} = require("./gatsby-node/index")

exports.createPages = createPages
exports.onCreateNode = onCreateNode

在这个时候,我建议先用 gatsby develop 来确认一下是否正常运行,我觉得转译应该是成功的(如果有错误的话,可以用任何方法来处理,比如使用any等等哈)。

以严格模式逐步修正

{
  "compilerOptions": {
    "target": "esnext",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
    "lib": ["dom", "es2017"],                             /* Specify library files to be included in the compilation. */
    "jsx": "react",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
    "outDir": "./build",                        /* Redirect output structure to the directory. */
    "rootDir": "./",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
    "noUnusedLocals": true,                /* Report errors on unused locals. */
    "noUnusedParameters": true,            /* Report errors on unused parameters. */
    "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. */
    "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. */
    "baseUrl": "src",                       /* Base directory to resolve non-absolute module names. */
    "esModuleInterop": true,                  /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */
    "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */
    "skipLibCheck": true,                     /* Skip type checking of declaration files. */
    "forceConsistentCasingInFileNames": true  /* Disallow inconsistently-cased references to the same file. */
    "strict": true,                           /* Enable all strict type-checking options. */
    "noImplicitAny": true,                 /* Raise error on expressions and declarations with an implied 'any' type. */
    "strictNullChecks": true,              /* Enable strict null checks. */
    "strictFunctionTypes": true,           /* Enable strict checking of function types. */
    "strictBindCallApply": true,           /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
    "strictPropertyInitialization": true,  /* Enable strict checking of property initialization in classes. */
  },
  "include": ["src/**/*", "gatsby-node/index.ts"],
  "exclude": ["node_modules", "public", "build", "src/templates/blog-post.tsx"],
}

那么立刻就会遇到错误,所以我们需要进行修正。

因为在生成的undefined处出现错误,需要进行修正。

image.png

对组件和页面进行了修整看了看。

这里是git – 完整的教程的TS化分支在这里

/** @jsx jsx */
import { FC } from "react"
import { jsx, css } from "@emotion/react"
import { useStaticQuery, Link, graphql } from "gatsby"
import { rhythm } from "../utils/typography"

const Layout: FC = ({ children }) => {
  const data = useStaticQuery<GatsbyTypes.LayoutSiteMetadataQuery>(
    graphql`
    query LayoutSiteMetadata {
      site {
        siteMetadata {
          title
        }
      }
    }
    `
  )
  return (
    <div
      css={css`
        margin: 0 auto;
        max-width: 700px;
        padding: ${rhythm(2)};
        padding-top: ${rhythm(1.5)};
      `}
    >
      <Link to={`/`}>
        <h3
          css={css`
            margin-bottom: ${rhythm(2)};
            display: inline-block;
            font-style: normal;
          `}
        >
          {data.site?.siteMetadata?.title}
        </h3>
      </Link>
      <Link
        to={`/about/`}
        css={css`
          float: right;
        `}
      >
        About
      </Link>
      {children}
    </div>
  )
}

export default Layout
import React from "react"
// import PropTypes from "prop-types"
import { Helmet } from "react-helmet"
import { useStaticQuery, graphql } from "gatsby"

interface SEOTypes {
  description?: string,
  lang?: string,
  meta?: any,
  title: string,
}

const SEO = ({
  description,
  lang,
  meta,
  title
}: SEOTypes) => {
  const { site } = useStaticQuery<GatsbyTypes.SEOsiteMetadataQuery>(
    graphql`
      query SEOsiteMetadata {
        site {
          siteMetadata {
            title
            description
            author
          }
        }
      }
    `
  )

  const metaDescription = description || site?.siteMetadata?.description
  if(!lang) lang = 'ja';
  if(!meta) meta = {};

  return (
    <Helmet
      htmlAttributes={{
        lang,
      }}
      title={title}
      titleTemplate={`%s | ${site?.siteMetadata?.title}`}
      meta={[
        {
          name: `description`,
          content: metaDescription,
        },
        {
          property: `og:title`,
          content: title,
        },
        {
          property: `og:description`,
          content: metaDescription,
        },
        {
          property: `og:type`,
          content: `website`,
        },
        {
          name: `twitter:card`,
          content: `summary`,
        },
        {
          name: `twitter:creator`,
          content: site?.siteMetadata?.author,
        },
        {
          name: `twitter:title`,
          content: title,
        },
        {
          name: `twitter:description`,
          content: metaDescription,
        },
      ].concat(meta)}
    />
  )
}
export default SEO
/** @jsx jsx */
import {FC} from "react"
import { jsx, css } from '@emotion/react'
import { Link, graphql, PageProps } from "gatsby"
import { rhythm } from "../utils/typography"
import Layout from "../components/layout"

const Home: FC<PageProps<GatsbyTypes.MarkdownOfIndexQuery>> = ({data}) => {
  return (
    <Layout>
      <div>
        <h1
          css={css`
            display: inline-block;
            border-bottom: 1px solid;
          `}
        >
          Amazing Pandas Eating Things
        </h1>
        <h4>{data.allMarkdownRemark.totalCount} Posts</h4>
        {data.allMarkdownRemark.edges.map(({ node }) => (
          <div key={node.id}>
            <Link
              to={node.fields?.slug || '/'}
              css={css`
                text-decoration: none;
                color: inherit;
              `}
            >
            <h3
              css={css`
                margin-bottom: ${rhythm(1 / 4)};
              `}
            >
              {node.frontmatter?.title}{" "}
              <span
                css={css`
                  color: #bbb;
                `}
              >
                 {node.frontmatter?.date}
              </span>
            </h3>
            <p>{node.excerpt}</p>
            </Link>
          </div>
        ))}
      </div>
    </Layout>
  )
}

export const query = graphql`
  query MarkdownOfIndex {
    allMarkdownRemark {
      totalCount
      edges {
        node {
          id
          frontmatter {
            title
            date(formatString: "DD MMMM, YYYY")
          }
          fields {
            slug
          }
          excerpt
        }
      }
    }
  }
`

export default Home
import React, {FC} from "react"
import { graphql, PageProps } from "gatsby"
import Layout from "../components/layout"

const About: FC<PageProps<GatsbyTypes.AboutsiteMetadataQuery>> = ({ data }) => {
  return (
    <Layout>
      <h1>About {data.site?.siteMetadata?.title}</h1>
      <p>
        We are the only site running on your computer dedicated to showing the
        best photos and videos of pandas eating lots of food.
      </p>
    </Layout>
  )
}

export const query = graphql`
  query AboutsiteMetadata {
    site {
      siteMetadata {
        title
      }
    }
  }
`

export default About

import React, {FC} from "react"
import { graphql, PageProps } from "gatsby"
import Layout from "../components/layout"

const MyFiles: FC<PageProps<GatsbyTypes.myFilesAllFileQuery>> = ({data}) => {
  return (
    <Layout>
      <div>
        <h1>My Sites Files</h1>
        <table>
          <thead>
            <tr>
              <th>relativePath</th>
              <th>prettySize</th>
              <th>extension</th>
              <th>birthTime</th>
            </tr>
          </thead>
          <tbody>
            {data.allFile.edges.map(({ node }, index) => (
              <tr key={index}>
                <td>{node.relativePath}</td>
                <td>{node.prettySize}</td>
                <td>{node.extension}</td>
                <td>{node.birthTime}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </Layout>
  )
}

export const query = graphql`
  query myFilesAllFile {
    allFile {
      edges {
        node {
          relativePath
          prettySize
          extension
          birthTime(fromNow: true)
        }
      }
    }
  }
`

export default MyFiles
import React, {FC} from "react"
import { graphql, PageProps } from 'gatsby'
import Layout from "../components/layout"
import SEO from "../components/seo"

const BlogPost: FC<PageProps<GatsbyTypes.blogPostRemarkQuery>> = ({data}) => {
  const post = data.markdownRemark
  return (
    <Layout>
      <SEO title={post?.frontmatter?.title || "undefined"} description={post?.excerpt || "undefined"} />
      <div>
        <h1>{post?.frontmatter?.title}</h1>
        <div dangerouslySetInnerHTML={{ __html: post?.html || "undefined"}}/>
      </div>
    </Layout>
  )
}

export const query = graphql`
  query blogPostRemark($slug: String!) {
    markdownRemark(fields: { slug: { eq: $slug } }) {
      html
      frontmatter {
        title
      }
      excerpt
    }
  }
`

export default BlogPost

添加缺少的库。

yarn add -D @types/react-helmet @types/typography

在这里,可悲的是,在GatsbyJS教程中使用的”typography-theme-kirkham”的@types文件找不到,因此无法进行TS编码。

进行开发时出现错误。

我想在这里进行gatsby develop的测试,但不知道为什么,如果保留”gatsby-plugin-typegen”插件,”组件生成的GraphQL类型将不会消失,终端将一直重新加载并无法运行。”

如果有人知道理由,请告诉我,因为我不明白。是因为只有在处理develop时,没有使用useStaticQuery的GraphQL才会重新生成类型吗?

当组件的GraphQL类型消失后,通过进行gatsby构建,就可以恢复其原始状态。
因此,在进行gatsby开发时,需要注释掉在gatsby-config.js中配置的gatsby-plugin-typegen。

我尝试构建并启动了服务。

gatsby build
gatsby serve
image.png

如果可以在 http://localhost:9000/ 上启动,则完成。

bannerAds