ShopifyのフロントをGatsby+TypeScriptで構築
ShopifyのストアフロントをGatsbyで構築するのは案外良さそう。
NextとGatsbyのどちらを選択すべきかについては、またいずれ書く。
ひとまず、Udemyやブログに構築方法が紹介されているので参考にしながら構築してみる。
また、TypeScriptも導入しているようなものはあまりないので今回はそれも導入してみて、その知見をためていく。
ReactももGatsbyもTypeScriptも初めてなので、無駄なフローもあるかもしれない。
参考サイト
まずは特に参考になったサイトを貼っておく
公式系は当然みると思うので省略
- How To Set Up a Gatsby Project with TypeScript | DigitalOcean
- Gatsby.jsのTypeScript化 2020
- React Prop Types with TypeScript | Ben Ilegbodu
単に初めてのReact, TypeScriptで勉強になったサイト
- コンポーネントの作り方(marginの持たせ方とか)
- React+Typescriptのテンプレート群、割と参考にできそう。
- 無駄にスターの多いgatsbyベースのブログ
- TypeScript + Reactのチートシート
- 有志による?TypeScriptのチュートリアルサイト
- stateの型定義について
備考
SSGで商品ページ作ればリクエスト制限を超過するようなことはないよねというお気持ち。
参考になりそうなGatsbyのスターター
UdemyでちょうどShopify+Gatsbyのサイト構築があったのでこちらをベースに参考にできそう
一方で、上記のプロジェクトはTypeScriptに対応していないため、まずは素のGatsbyをインストールしてTypeScriptに対応=>その後にこのスターターに寄せていくような作りにしようと思う。
インストールまわり
Gatsbyのインストール
$ gatsby new gatsby-typescript
$ rm -rf node_modules package.lock.json
$ yarn # パッケージマネージャーをnpmからyarnに変更
- ここでは何もオプションを加えずにそのままのGatsbyをインストール。
- yarnでパッケージ管理したいので、一度node_modulesとpackage.lock.jsonは削除
- yarnでインストール
Typescriptのインストール
# typescriptをプロジェクトへ導入
yarn add typescript -D
# typescriptの設定ファイルを生成
npx tsc --init
# message TS6071: Successfully created a tsconfig.json file.
上記コマンドの解説
yarn add typescript -D
これで、typescript
のnpmパッケージをインストールできる。
typescript
はTypeScriptを使うためのパッケージで、tsc
というTypescriptのコンパイラなどが内包されている。多分 TypeScirpit Compiler
の略?
npx tsc -v
# Version 4.3.5
npx tsc --init
このtsc
を使って、初期化を実行すると、Typescriptの設定ファイルtsconfig.json
が生成されて、TypeScriptのコンパイル環境がとりあえず完成する。
tsconfig.jsonの編集
tsconfig.json
の設定については以下を参考するといいかも
デフォルトでは以下が有効になっている(コメントアウトは削除している)。
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Basic Options */
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
"skipLibCheck": true, /* Skip type checking of declaration files. */
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
}
}
まだ正しい設定はわからないけど必要そうな設定を記述していく
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', 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. */,
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
"jsx": "react" /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */,
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
// "outDir": "./", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"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. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "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. */
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"skipLibCheck": true /* Skip type checking of declaration files. */,
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
}
}
各パッケージの型定義インストール
「@types/」から始まる名前のパッケージとは - Qiita
一応、Gatsbyのサポートにより、依存関係として@types/react, @types/react-dom, @types/nodeなどはインストールされている模様であるけど、明示的に開発環境にaddしていてもいいのかな?と思ったりした
$ yarn add -D @types/node @types/react @types/react-dom @types/react-helmet @types/shopify-buy @types/styled-components
あとプラスして、デフォルトのスターターには gatsby-plugin-react-helmet
が入っていて定義ファイルがないようなので、インストールする
$ yarn add -D @types/react-helmet
ちなみに、runtimeって必要なのか?ts-node, ts-node-devとか
GraphQL Schema, リクエストの型生成を出力するためのパッケージをインストール
GraphQLのレスポンスを型定義するためのプラグインは主に2つあるっぽい
- gatsby-plugin-graphql-codegen
- gatsby-plugin-typegen
gatsby-plugin-graphql-codegen
はよく記事などで利用されているのを見かけるが、メンテナンスがされなくなっているので、gatsby-plugin-typegen
を使うのを推奨している
gatsby-plugin-typegen | Gatsby
yarn add gatsby-plugin-typegen
GatsbyのTypescript対応
GatsbyはデフォルトでTypeScriptに対応するためのプラグイン[gatsby-plugin-typescript]をインクルードしている。
以下のリファレンスに沿って必要な設定があれば記述する。
gatsby-plugin-typescript | Gatsby
各コンポーネントのTypeScript化
Gatsbyはデフォルトでインストールした際に素のJavascriptで書かれている。
そのため拡張子.js, .jsx
を .ts, .tsx
に書き換える。
pages
以下のファイルについては、単純に.tsx
に変換すれば良さそう。
components
以下のファイルについては、少しprops
周りを修正する必要あり
この辺のpurops周りが全然わからなかったので苦労した
ちなみに、typescriptに対応するテンプレートとして、gatsbyjs/gatsby-starter-default(デフォルトの)テンプレートには pages/using-typescript.tsx
というのがある。
以下の変更が済んだら、ターミナルでyarn build
やyarn develop
を実行して、ちゃんとビルドできることを確認する。
src/components
36行目から42行目までの Header.propTypes
やHeader.defaultProps
のオブジェクトはJSのReactでpropsに正常な値が渡っているか型・値のチェックをする機能らしい。
TypeScriptでは、引数や変数定義で型定義する必要があるため、propTypesがあると二重でチェックすることになり実質不要なはず。
一方で、typescriptでもあえてpropTypesを書くことはできる。その場合は、パッケージをインストールして利用する。
yarn add @types/prop-types
/**
* Layout component that queries for data
* with Gatsby's useStaticQuery component
*
* See: https://www.gatsbyjs.com/docs/use-static-query/
*/
import { graphql, useStaticQuery } from "gatsby"
-import PropTypes from "prop-types"
-import * as React from "react"
+import React, { ReactNode } from "react"
import Header from "./header"
import "./layout.css"
-const Layout = ({ children }) => {
+interface LayoutProps {
+ children: ReactNode
+}
+
+const Layout = ({ children }: LayoutProps) => {
const data = useStaticQuery(graphql`
query SiteTitleQuery {
site {
siteMetadata {
title
}
}
}
`)
return (
<>
<Header siteTitle={data.site.siteMetadata?.title || `Title`} />
<div
style={{
margin: `0 auto`,
maxWidth: 960,
padding: `0 1.0875rem 1.45rem`,
}}
>
<main>{children}</main>
<footer
style={{
marginTop: `2rem`,
}}
>
© {new Date().getFullYear()}, Built with
{` `}
<a href="https://www.gatsbyjs.com">Gatsby</a>
</footer>
</div>
</>
)
}
-Layout.propTypes = {
- children: PropTypes.node.isRequired,
-}
-
export default Layout
import { Link } from "gatsby"
-import PropTypes from "prop-types"
import * as React from "react"
-const Header = ({ siteTitle }) => (
+interface HeaderProps {
+ siteTitle: string
+}
+
+const Header: React.FC<HeaderProps> = ({ siteTitle }) => (
<header
style={{
background: `rebeccapurple`,
marginBottom: `1.45rem`,
}}
>
<div
style={{
margin: `0 auto`,
maxWidth: 960,
padding: `1.45rem 1.0875rem`,
}}
>
<h1 style={{ margin: 0 }}>
<Link
to="/"
style={{
color: `white`,
textDecoration: `none`,
}}
>
{siteTitle}
</Link>
</h1>
</div>
</header>
)
-Header.propTypes = {
- siteTitle: PropTypes.string,
-}
-
-Header.defaultProps = {
- siteTitle: ``,
-}
-
export default Header
/**
* SEO component that queries for data with
* Gatsby's useStaticQuery React hook
*
* See: https://www.gatsbyjs.com/docs/use-static-query/
*/
-import * as React from "react"
+import { graphql, useStaticQuery } from "gatsby"
import PropTypes from "prop-types"
+import * as React from "react"
import { Helmet } from "react-helmet"
-import { useStaticQuery, graphql } from "gatsby"
-function Seo({ description, lang, meta, title }) {
+interface SeoProps {
+ description: string
+ language: string
+ meta: []
+}
+
+Seo.propTypes = {
+ description: PropTypes.string,
+ lang: PropTypes.string,
+ meta: PropTypes.arrayOf(PropTypes.object),
+ title: PropTypes.string.isRequired,
+}
+
+function Seo({ description = "", lang = "ja", meta = [], title = "" }) {
const { site } = useStaticQuery(
graphql`
query {
site {
siteMetadata {
title
description
author
}
}
}
`
)
const metaDescription = description || site.siteMetadata.description
const defaultTitle = site.siteMetadata?.title
return (
<Helmet
htmlAttributes={{
lang,
}}
title={title}
- titleTemplate={defaultTitle ? `%s | ${defaultTitle}` : null}
+ titleTemplate={defaultTitle ? `%s | ${defaultTitle}` : undefined}
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 = {
title
description
author
}
}
}
`
)
}
}
`
)
const metaDescription = description || site.siteMetadata.description
const defaultTitle = site.siteMetadata?.title
return (
<Helmet
htmlAttributes={{
lang,
}}
title={title}
- titleTemplate={defaultTitle ? `%s | ${defaultTitle}` : null}
+ titleTemplate={defaultTitle ? `%s | ${defaultTitle}` : undefined}
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
ESLintやPritterの対応
package.jsonを見たらESLintが入っていなかったので、インストールする
$ yarn add -D eslint eslint-config-prettier
$ touch eslintrc.js
module.exports = {
parser: `@typescript-eslint/parser`,
extends: [
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
"prettier/@typescript-eslint",
],
plugins: ["@typescript-eslint", "prettier"],
parserOptions: {
ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
sourceType: "module", // Allows for the use of imports
},
env: {
browser: true,
node: true,
es6: true,
},
rules: {
quotes: "off",
"@typescript-eslint/quotes": [
2,
"backtick",
{
avoidEscape: true,
},
],
indent: ["error", 2, { SwitchCase: 1 }],
"prettier/prettier": [
"error",
{
trailingComma: "es5",
semi: false,
singleQuote: false,
printWidth: 120,
},
],
},
}
gatsby-shopify-starterの内容を移植してく
最初に紹介したShopify用のテンプレートgatsby-shopify-starter
を参考に、Shopify用の雛形を作っていく。ここまで大変長かった。。。。
他にもShopify向けのスターターはあるので、もう少し探して検討してみてもいいかもしれない。
gatsby-shopify-starterのpackage.jsonから入っていない必要そうなパッケージをインストール
$ yarn add shopify-buy styled-components styled-reset react-icons gatsby-source-shopify gatsby-plugin-google-fonts gatsby-optional-chaining babel-plugin-styled-components
- shopify-buy
- styled-components
- styled-reset
- react-icons
- gatsby-source-shopify
- gatsby-plugin-google-fonts
- gatsby-optional-chaining
- babel-plugin-styled-components
gatsby-image
なども含まれていたが、非推奨のパッケージとなっているので、gatsby-plugin-image
に変更しておく
gatsby-shopify-starterの内容を移植してく
最初に紹介したShopify用のテンプレートgatsby-shopify-starter
を参考に、Shopify用の雛形を作っていく。ここまで大変長かった。。。。
他にもShopify向けのスターターはあるので、もう少し探して検討してみてもいいかもしれない。
gatsby-shopify-starterのpackage.jsonから入っていない必要そうなパッケージをインストール
$ yarn add shopify-buy styled-components styled-reset react-icons gatsby-source-shopify gatsby-plugin-google-fonts gatsby-optional-chaining gatsby-plugin-styled-components
- shopify-buy
- styled-components
- styled-reset
- react-icons
- gatsby-source-shopify
- gatsby-plugin-google-fonts
- gatsby-optional-chaining
gatsby-image
なども含まれていたが、非推奨のパッケージとなっているので、gatsby-plugin-image
に変更しておく
gatsby-*.js 系を変更していく
これって ts
に変更する方がいいのかな?
gatsby-config.js
+require("dotenv").config({ //shopify の StorefrontAPIを .env ファイルで管理する
+ path: ".env",
+})
+
module.exports = {
siteMetadata: {
- title: `Gatsby Default Starter`,
- description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`,
- author: `@gatsbyjs`,
+ // サイトのメタデータを記述していい
+ title: `gatsby + typescript + shopify`,
+ description: `Shopify Storefront build by gatsby and typescript`,
siteUrl: `https://gatsbystarterdefaultsource.gatsbyjs.io/`,
},
plugins: [
`gatsby-plugin-react-helmet`,
`gatsby-plugin-image`,
`gatsby-plugin-typegen`,
+ "gatsby-plugin-styled-components",
+ "gatsby-optional-chaining",
+ {
+ resolve: "gatsby-source-shopify",
+ options: {
+ shopName: process.env.GATSBY_SHOP_NAME,
+ accessToken: process.env.GATSBY_ACCESS_TOKEN,
+ apiVersion: "2021-07",
+ },
+ },
+ {
+ resolve: "gatsby-plugin-google-fonts",
+ options: {
+ fonts: [
+ /* eslint-disable no-useless-escape */ // eslintのエラーが解消できなかったため
+ "open sans:400",
+ "open sans:400i",
+ "open sans:700",
+ "open sans:700i",
+ "open sans:800",
+ "open sans:800i",
+ /* eslint-enable no-useless-escape */
+ ],
+ },
+ },
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `gatsby-starter-default`,
short_name: `starter`,
start_url: `/`,
background_color: `#663399`,
theme_color: `#663399`,
display: `minimal-ui`,
icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site.
},
},
`gatsby-plugin-gatsby-cloud`,
// this (optional) plugin enables Progressive Web App + Offline functionality
// To learn more, visit: https://gatsby.dev/offline
// `gatsby-plugin-offline`,
],
}
tsconfig.jsonの修正
gatsbyのインポートで以下のようなエラーが生じていた
モジュール 'gatsby' が見つかりません。'moduleResolution' オプションを 'node' に....
これは tsconfig.json
で "module": "esnext"
とした時に生じる。
解決方法としては tsconfig.json
で "moduleResolution": "node"
とすればいい。
そういえば Typescriptの型チェック用のnpmスクリプトを編集する。
これで yarn typecheck
で型チェック, yarn build
で型チェックしてからビルドが通るようになる
"scripts" {
"build": "npm run type-check && gatsby build",
"typecheck": "tsc --noEmit",
}
gatsby-source-shopify の変更
今回参考にしたスターター(https://github.com/tomphill/gatsby-shopify-starter)は、使用しているパッケージ類がちょいちょい古かったり、非推奨の物があるので注意が必要。
スターターは v3.8.0
だが、2021/08現在では 5.5.0
となっており、結構破壊的な変更も行われている。
READMEを見ると プラグインの設定が変わっていることがわかる。
{
resolve: "gatsby-source-shopify",
options: {
- shopName: process.env.GATSBY_SHOP_NAME,
- accessToken: process.env.GATSBY_ACCESS_TOKEN,
+ password: process.env.SHOPIFY_ADMIN_PASSWORD,
+ storeUrl: process.env.SHOPIFY_STORE_URL,
apiVersion: "2021-07",
},
},
さらに、gatsby build
, gatsby develop
を実行するとqueryエラーで落ちる。
以前までは、Shopify Storefront API を使ってビルドできるようだったが、最近追加されたShopify Admin APIの bulk operationsを使ってビルドを通しているよう。
なのでプライベートアプリにShopify Admin APIのパーミッションを与えないといけない。
For the Private app name enter Gatsby (the name does not really matter). Add the following under the Active Permissions for this App section:
Read access for
Products
Read access forProduct listings
if you want to use Shopify's Product Collections in your Gatsby site
Read access forOrders
if you want to use order information in your Gatsby site
Read access forInventory
andLocations
if you want to use location information in your Gatsby site
gatsby-source-shopify
のREADME通りに 商品管理と商品リストだけ追加すればとりあえず動きそう。
ところが、以下のようなエラーが生じる
ここで、 在庫(Inventory)
のパーミッションを与えると無事ビルドに成功した。
原因はわからない。githubで聞いてもいいのかもしれない?
Wappalyzer対策
html.js
を編集すればいけそう
gatsby-source-shopify
の破壊的な変更について、ProductのIDについても変更があり、
これまでは shopifyId
だったフィールドが storefrontId
となっている
Gasbyの画像の扱いについて
Gatsbyの画像最適化について
コンポーネントでの扱い
=> StaticImage
と GatsbyImage
がありそれぞれ使い分ける必要がある
使い分けについては以下のドキュメントを参考にすればよし。
また、gatsby-source-shopify
では画像の取り扱いについても変更が起きている
以下に従って、gatsby-conifg.js
のプラグインにdownloadImages:true
を設定することで、Graphqlで shop.localFile.childImageSharp....
が利用できるようになる
gatsby-plugin-image
についても破壊的な変更があるのでマイグレーションが必要
ビルド時に同様のエラーがでた。
node --trace-deprecation node_modules/gatsby/dist/bin/gatsby develop
上記の記事と同様に npmパッケージのgotが原因のようであるが、正直最新版をインストールしてわざわざpackage.jsonに追加するのも微妙。依存関係のパッケージ側で解決されるのをまっても良さそう。
info Creating nodes from bulk operation PRODUCTS
ERROR
(node:76144) [DEP0066] DeprecationWarning: OutgoingMessage.prototype._headers is deprecated
at module.exports (/Users/abekeishi/ghq/github.com/TanisukeGoro/chefrepi-storefront/node_modules/timed-out/index.js:9:17)
at EventEmitter.<anonymous> (/Users/abekeishi/ghq/github.com/TanisukeGoro/chefrepi-storefront/node_modules/got/index.js:244:5)
at Object.onceWrapper (node:events:514:26)
at EventEmitter.emit (node:events:394:28)
at makeRequest (/Users/abekeishi/ghq/github.com/TanisukeGoro/chefrepi-storefront/node_modules/cacheable-request/src/index.js:94:9)
at /Users/abekeishi/ghq/github.com/TanisukeGoro/chefrepi-storefront/node_modules/cacheable-request/src/index.js:104:14
at runNextTicks (node:internal/process/task_queues:61:5)
at processImmediate (node:internal/timers:437:9)
Gatsbyの公式ドキュメントを見ると、ページの生成に利用するGraphQLに変数を渡したい場合、contextを付与すればいいらしい。
実際に書くとこうなる。
data.allShopifyProduct.edges.forEach(({ node }) => {
createPage({
path: `products/${node.handle}`,
context: {
hodehoge: 'testo',
storefrontId: node.storefrontId,
},
component: path.resolve('./src/template/ProductTemplate/index.tsx'),
})
})
// 中略
export const query = graphql`
query ProductQuery($shopifyId: String) {
shopifyProduct(shopifyId: { eq: $shopifyId }) {
...ShopifyProductFields
}
}
// 中略
この時、contextのkeyがGraphQLの変数に自動的に読み替えられて実行できるため変数として渡すことができるようなのであるが、特にGraphQL側の変数に関係のないパラメータのみを付与したとしてもなぜがビルドできてしまう問題にぶち当たった。まさに上記のように。
原因も解決方法もまだわかっていない。
ちなみにビルドはできるが、データは1件しか取得できていないみたいで、どのページを見ても同じデータがpropsで与えられている。
contextとGraphQLのパラメータを揃えるとちゃんとビルドされて適切なpropsが渡るようになる。