tag:crieit.net,2005:https://crieit.net/tags/GatsbyJS/feed 「GatsbyJS」の記事 - Crieit Crieitでタグ「GatsbyJS」に投稿された最近の記事 2021-11-05T21:44:25+09:00 https://crieit.net/tags/GatsbyJS/feed tag:crieit.net,2005:PublicArticle/17741 2021-11-05T21:44:25+09:00 2021-11-05T21:44:25+09:00 https://crieit.net/posts/microcms-api-update-gatsby-update-20211106 microCMS の X-API-KEY リニューアルに合わせて Vercel の設定と Gatsby のプロジェクトを更新する <p>メール通知で microCMS の X-API-KEY がリニューアルされたという通知を受け取って対応することにしました。</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://blog.microcms.io/renew-x-microcms-api-key/">APIキーをX-MICROCMS-API-KEYへとリニューアルしました。 | microCMSブログ</a></li> </ul> <blockquote> <p>従来のX-API-KEY, X-WRITE-API-KEY, X-DRAFT-KEYは統合され、X-MICROCMS-API-KEYに変更となります。</p> <p><a target="_blank" rel="nofollow noopener" href="https://blog.microcms.io/renew-x-microcms-api-key/">APIキーをX-MICROCMS-API-KEYへとリニューアルしました。 | microCMSブログ</a></p> </blockquote> <p>とのことなので、これに対応することにします。</p> <h2 id="microCMS"><a href="#microCMS">microCMS</a></h2> <p>まずは microCMS 側の作業。新しいAPIキーを発行し直します。</p> <p><a href="https://crieit.now.sh/upload_images/b639bdef8b9834d65ed80dcb79d999e46185263f658dd.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/b639bdef8b9834d65ed80dcb79d999e46185263f658dd.jpg?mw=700" alt="APIキーの一覧" /></a></p> <p>「APIキー管理」のAPIキーの一覧で「旧X-API-KEY」があることを確認。</p> <p><a href="https://crieit.now.sh/upload_images/6adc5584ea41a4d7620ea61147890b1261852649a9f13.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6adc5584ea41a4d7620ea61147890b1261852649a9f13.jpg?mw=700" alt="APIキーの詳細" /></a></p> <p>選択して詳細画面から「削除」を選択。</p> <p>続いて新しいAPIキーを発行し直します。</p> <p><a href="https://crieit.now.sh/upload_images/eef5b0f7a42cda381863a3eae0f6894361852651849ef.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/eef5b0f7a42cda381863a3eae0f6894361852651849ef.jpg?mw=700" alt="新X-MICROCMS-API-KEYの発行" /></a></p> <p>X-MICROCMS-API-KEY を発行します。今回はAPI経由では参照しかしないので GET のみの権限とします。</p> <p><a href="https://crieit.now.sh/upload_images/8febcc76cb4c74b656c4720ed16f44a06185265a7d678.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/8febcc76cb4c74b656c4720ed16f44a06185265a7d678.jpg?mw=700" alt="APIキーをコピー" /></a></p> <p>発行されたAPIキーをコピーして控えます。</p> <p>これで microCMS 側の作業は完了です。</p> <h2 id="Vercel"><a href="#Vercel">Vercel</a></h2> <p>続いて Vercel にログインします。</p> <p><a href="https://crieit.now.sh/upload_images/1ae9a58b4f0e8ee01d8a591c1629ff9b618526623540c.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/1ae9a58b4f0e8ee01d8a591c1629ff9b618526623540c.jpg?mw=700" alt="Vercel の環境変数の一覧" /></a></p> <p>プロジェクトの「Settings」から「Enviroment Variables」に進みます。</p> <p><a href="https://crieit.now.sh/upload_images/3a0751306ac22bdcc1333827ce44d7f16185266ada888.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/3a0751306ac22bdcc1333827ce44d7f16185266ada888.jpg?mw=700" alt="API_KEYの変更" /></a></p> <p><code>API_KEY</code>の値を先ほど控えた値に変更します。</p> <p>これでOKかと思ったのですが……。</p> <pre><code class="bash">00:03:22.489 error microCMS API ERROR: 00:03:22.489 statusCode: 401 00:03:22.489 message: X-MICROCMS-API-KEY header is invalid. 00:03:22.492 not finished source and transform nodes - 1.046s 00:03:23.631 Error: Command "npm run build" exited with 1 </code></pre> <p>ビルドログを見ると 401エラー でコケていますね。認証に失敗しているようです。</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://vanilla-note.com/posts/gatsby4-1-microcms-3/">microCMSの新しいX-MICROCMS-API-KEYに対応する | Vanilla note</a></li> </ul> <p>検索すると、 Gatsby の microCMS 連携のパッケージも更新しないといけないとのこと。</p> <h2 id="Gatsby プロジェクト"><a href="#Gatsby+%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88">Gatsby プロジェクト</a></h2> <p>そこで該当パッケージのバージョンをアップデートします。</p> <pre><code class="json"> "dependencies": { // 略 "gatsby-source-microcms": "^1.2.1", // 略 } </code></pre> <p><code>gatsby-source-microcms</code> を</p> <pre><code class="json"> "dependencies": { // 略 "gatsby-source-microcms": "^2.0.0", // 略 } </code></pre> <p><code>2.0.0</code> にアップデート。</p> <p>これでビルドを走らせ、正常に完了することを確認しました。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://blog.microcms.io/renew-x-microcms-api-key/">APIキーをX-MICROCMS-API-KEYへとリニューアルしました。 | microCMSブログ</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://vanilla-note.com/posts/gatsby4-1-microcms-3/">microCMSの新しいX-MICROCMS-API-KEYに対応する | Vanilla note</a></li> </ul> <p>Vercel に関しては自分の過去の記事も参考にして辿りつつ……。</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://labor.ewigleere.net/2021/08/29/gatsby-vercel-microcms-cooprate-2/">Gatsby.js + Vercel + microCMS の JAMStack 環境を構築する – Ewig Leere(Lab2)</a></li> </ul> arm-band tag:crieit.net,2005:PublicArticle/17623 2021-08-29T00:49:34+09:00 2021-08-29T00:49:34+09:00 https://crieit.net/posts/gatsby-vercel-microcms-cooprate-20210829-2 Gatsby.js + Vercel + microCMS の JAMStack 環境を構築する <p><a href="https://crieit.net/posts/gatsby-vercel-microcms-cooprate-20210829-1">microCMS の設定が完了した</a>ので、次は microCMS からデータを取得するように Gatsby.js の方に手を入れます。また、 microCMS と Vercel に設定を加えて連携させ、 Gatsby.js + Vercel + microCMS の JAMStack 環境を構築します。</p> <h2 id="改修"><a href="#%E6%94%B9%E4%BF%AE">改修</a></h2> <p>今回は<a target="_blank" rel="nofollow noopener" href="https://www.gatsbyjs.com/starters/renyuanz/leonids">leonids: Gatsby Starter | Gatsby</a>を使用しているので、その前提で。</p> <p>テーマが変わったり、 microCMS のスキーマが変われば諸々の調整が必要となります。</p> <h3 id="パッケージの追加"><a href="#%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%81%AE%E8%BF%BD%E5%8A%A0">パッケージの追加</a></h3> <pre><code class="bash">> yarn add yarn add gatsby-source-microcms ## 略 Done in 231.79s. > yarn add marked ## 略 Done in 7.30s. </code></pre> <p>今回は microCMS を利用するので <code>gatsby-source-microcms</code> を追加します。また、本文コンテンツは Markdown で記述しているのですが Gatsby.js の自前の Markdownパーサ まで手が届かなかったので安直に <code>marked</code> を使いました。</p> <p>それから、内部的には <code>dotenv</code> も使用していますが <code>yarn.lock</code> を見たら既に入っていたので追加はしていません。</p> <h3 id="gatsby-config.js"><a href="#gatsby-config.js">gatsby-config.js</a></h3> <p>さて、改修の最初は Gatsby.js の設定から。</p> <pre><code class="javascript">module.exports = { // 略 plugins: [ { resolve: `gatsby-source-filesystem`, options: { path: `${__dirname}/content/blog`, name: `blog`, }, }, // 略 }, `gatsby-plugin-feed`, { // 略 ], // 略 } </code></pre> <p>これを以下のように修正。</p> <pre><code class="js">const activeEnv = process.env.GATSBY_ACTIVE_ENV || process.env.NODE_ENV if(activeEnv === "development") { require("dotenv").config({ path: `.env.${activeEnv}`, }) } module.exports = { // 略 plugins: [ { resolve: 'gatsby-source-microcms', options: { apiKey: process.env.API_KEY, serviceId: process.env.SERVICE_ID, apis: [{ endpoint: process.env.APIS_ENDPOINT, }], }, }, // 略 { resolve: `gatsby-plugin-feed`, options: { query: ` { site { siteMetadata { title description siteUrl } } } `, feeds: [ { serialize: ({ query: { site, allMicrocmsHogeHogeBlog } }) => { return allMicrocmsHogeHogeBlog.edges.map(edge => { return Object.assign({}, edge.node, { description: edge.node.keywords, date: edge.node.date, url: site.siteMetadata.siteUrl + edge.node.slug, guid: site.siteMetadata.siteUrl + edge.node.slug, custom_elements: [{ "content:encoded": edge.node.body }], }) }) }, query: ` { allMicrocmsHogeHogeBlog(sort: {fields: [date], order: DESC}) { totalCount pageInfo { perPage pageCount } edges { node { body createdAt date id keywords publishedAt revisedAt slug title updatedAt } } } } `, output: "/rss.xml", title: "HogeHoge Blog's RSS Feed", }, ], }, }, // 略 ], // 略 } </code></pre> <p>変更点は以下。</p> <ul> <li>ローカルのファイルをコンテンツのリソース参照先としていたのを microCMS をリソースとするように修正</li> <li><code>gatsby develop</code> 時は問題なかったのですが、 <code>gatsby build</code> 時に RSSフィードを生成する <code>gatsby-plugin-feed</code>プラグイン が通常の Markdown の構成をデフォルトにしており、 microCMS に置き換えたことでデータスキーマが異なるとエラーになってしまいました (本番ビルド時に気付いた)。 <ul> <li>そこで、 <code>gatsby-plugin-feed</code>プラグイン の GraphQL も今回定義した microCMS のスキーマに沿って変更しました。併せて <code>serialize</code>メソッド の中身もスキーマに合わせて調整。</li> </ul></li> <li><a target="_blank" rel="nofollow noopener" href="https://www.gatsbyjs.com/plugins/gatsby-source-microcms/">gatsby-source-microcms | Gatsby</a>のサンプルコードでは Git 管理下になる <code>gatsby-config.js</code> に APIキー 等の情報がそのままベタ書きになってしまうので、 <code>dotenv</code> で外部ファイルに取り出すことで隠蔽しました <ul> <li>後述しますが、 Vercel の環境変数も <code>process.env</code> で渡ってくるので、<code>development</code> の場合は <code>dotenv</code> 経由の外部ファイルをパラメータのリソースに、 <code>production</code> の場合は Vercel の環境変数をリソースとするように書き分けました</li> </ul></li> </ul> <h3 id="gatby-node.js"><a href="#gatby-node.js">gatby-node.js</a></h3> <pre><code class="javascript">const path = require(`path`) const { createFilePath } = require(`gatsby-source-filesystem`) exports.createPages = async ({ graphql, actions }) => { const { createPage } = actions const blogPost = path.resolve(`./src/templates/blog-post.js`) const result = await graphql( ` { allMarkdownRemark( sort: { fields: [frontmatter___date], order: DESC } limit: 1000 ) { edges { node { fields { slug } frontmatter { title } } } } } ` ) if (result.errors) { throw result.errors } // Create blog posts pages. const posts = result.data.allMarkdownRemark.edges posts.forEach((post, index) => { const previous = index === posts.length - 1 ? null : posts[index + 1].node const next = index === 0 ? null : posts[index - 1].node createPage({ path: post.node.fields.slug, component: blogPost, context: { slug: post.node.fields.slug, previous, next, }, }) }) // Create blog post list pages const postsPerPage = 5 const numPages = Math.ceil(posts.length / postsPerPage) Array.from({ length: numPages }).forEach((_, i) => { createPage({ path: i === 0 ? `/` : `/${i + 1}`, component: path.resolve("./src/templates/blog-list.tsx"), context: { limit: postsPerPage, skip: i * postsPerPage, numPages, currentPage: i + 1, }, }) }) } exports.onCreateNode = ({ node, actions, getNode }) => { const { createNodeField } = actions if (node.internal.type === `MarkdownRemark`) { const value = createFilePath({ node, getNode }) createNodeField({ name: `slug`, node, value, }) } } </code></pre> <p>これを以下のように修正。</p> <pre><code class="javascript">const path = require(`path`) const { createFilePath } = require(`gatsby-source-filesystem`) exports.createPages = async ({ graphql, actions }) => { const { createPage } = actions const result = await graphql( ` { allMicrocmsHogeHogeBlog(sort: {fields: [date], order: DESC}) { totalCount pageInfo { perPage pageCount } edges { node { body createdAt date id keywords publishedAt revisedAt slug title updatedAt } } } } ` ) if (result.errors) { throw result.errors } // Create blog posts pages. const posts = result.data.allMicrocmsHogeHogeBlog.edges result.data.allMicrocmsHogeHogeBlog.edges.forEach((post, index) => { const previous = index === posts.length - 1 ? null : posts[index + 1].node const next = index === 0 ? null : posts[index - 1].node createPage({ path: post.node.slug, component: path.resolve('./src/templates/blog-post.js'), context: { slug: post.node.slug, previous, next, }, }); }); // Create blog post list pages const postsPerPage = result.data.allMicrocmsHogeHogeBlog.pageInfo.limit || 10 const numPages = Math.ceil(result.data.allMicrocmsHogeHogeBlog.totalCount / postsPerPage) console.log(result.data.allMicrocmsHogeHogeBlog.totalCount, postsPerPage) Array.from({ length: numPages }).forEach((_, i) => { createPage({ path: i === 0 ? `/` : `/${i + 1}`, component: path.resolve("./src/templates/blog-list.tsx"), context: { limit: postsPerPage, skip: i * postsPerPage, numPages, currentPage: i + 1, }, }) }) } exports.onCreateNode = ({ node, actions, getNode }) => { const { createNodeField } = actions if (node.internal.type === `microcmsHogeHogeBlog`) { const value = createFilePath({ node, getNode }) createNodeField({ name: `slug`, node, value, }) } } </code></pre> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://www.gatsbyjs.com/plugins/gatsby-source-microcms/">gatsby-source-microcms | Gatsby</a>のサンプルコードはシンプル過ぎて GraphQL初心者には分かりづらかったので、 <code>gatsby develop</code> で起動した <code>http://localhost:8000/___graphql</code> の GraphQL を試すGUIでひたすらAPIを叩いてパラメータを変えたりしてどういう GraphQL を作れば望んだレスポンスを得られるか確認しながら地道に調整していきました</li> <li>ベースのコードをなるべく変えないように調整して、各種プロパティの階層等を調整しました</li> <li><code>MarkdownRemark</code> や <code>allMarkdownRemark</code> が Markdownファイル をリソースとする場合のキーのような働きをしているのが分かったので、それを <code>http://localhost:8000/___graphql</code> で表示された microCMS のキーに変更したり</li> </ul> <p>GraphQL の構造やレスポンスに慣れるまで時間がかかりましたが、最終的には <code>http://localhost:8000/___graphql</code> であれこれ試したのが一番効果がありました。</p> <h3 id="blog-list.tsx"><a href="#blog-list.tsx">blog-list.tsx</a></h3> <p>記事一覧ページ。トップページもこのテンプレートから生成されています。</p> <pre><code class="javascript">// Gatsby supports TypeScript natively! import React from "react" import { PageProps, Link, graphql } from "gatsby" import Layout from "../components/layout" import SEO from "../components/seo" import { rhythm } from "../utils/typography" type PageContext = { currentPage: number numPages: number } type Data = { site: { siteMetadata: { title: string } } allMarkdownRemark: { edges: { node: { excerpt: string frontmatter: { title: string date: string description: string } fields: { slug: string } } }[] } } const BlogIndex = ({ data, location, pageContext, }: PageProps<Data, PageContext>) => { const siteTitle = data.site.siteMetadata.title const posts = data.allMarkdownRemark.edges const { currentPage, numPages } = pageContext const isFirst = currentPage === 1 const isLast = currentPage === numPages const prevPage = currentPage - 1 === 1 ? "/" : `/${currentPage - 1}` const nextPage = `/${currentPage + 1}` return ( <Layout location={location} title={siteTitle}> <SEO title="All posts" /> {posts.map(({ node }) => { const title = node.frontmatter.title || node.fields.slug return ( <article key={node.fields.slug}> <header> <h3 style=<span>{</span><span>{</span> marginBottom: rhythm(1 / 4), <span>}</span><span>}</span> > <Link style=<span>{</span><span>{</span> boxShadow: `none` <span>}</span><span>}</span> to={node.fields.slug}> {title} </Link> </h3> <small>{node.frontmatter.date}</small> </header> <section> <p dangerouslySetInnerHTML=<span>{</span><span>{</span> __html: node.frontmatter.description || node.excerpt, <span>}</span><span>}</span> /> </section> </article> ) })} <nav> <ul style=<span>{</span><span>{</span> display: `flex`, flexWrap: `wrap`, justifyContent: `space-between`, listStyle: `none`, padding: 0, <span>}</span><span>}</span> > <li> {!isFirst && ( <Link to={prevPage} rel="prev"> ← Previous Page </Link> )} </li> <li> {!isLast && ( <Link to={nextPage} rel="next"> Next Page → </Link> )} </li> </ul> </nav> </Layout> ) } export default BlogIndex export const pageQuery = graphql` query blogPageQuery($skip: Int!, $limit: Int!) { site { siteMetadata { title } } allMarkdownRemark( sort: { fields: [frontmatter___date], order: DESC } limit: $limit skip: $skip ) { edges { node { excerpt fields { slug } frontmatter { date(formatString: "MMMM DD, YYYY") title description } } } } } ` </code></pre> <p>これを以下のように改修。</p> <pre><code class="javascript">// Gatsby supports TypeScript natively! import React from "react" import { PageProps, Link, graphql } from "gatsby" import Layout from "../components/layout" import SEO from "../components/seo" import { rhythm } from "../utils/typography" type PageContext = { currentPage: number numPages: number } type Data = { site: { siteMetadata: { title: string } } allMicrocmsHogeHogeBlog: { edges: { node: { id: string keywords: string title: string updatedAt: string slug: string revisedAt: string publishedAt: string date: string createdAt: string body: string } }[] } } const BlogIndex = ({ data, location, pageContext, }: PageProps<Data, PageContext>) => { const siteTitle = data.site.siteMetadata.title const posts = data.allMicrocmsHogeHogeBlog.edges const { currentPage, numPages } = pageContext const isFirst = currentPage === 1 const isLast = currentPage === numPages const prevPage = currentPage - 1 === 1 ? "/" : `/${currentPage - 1}` const nextPage = `/${currentPage + 1}` return ( <Layout location={location} title={siteTitle}> <SEO title="All posts" /> {posts.map(({ node }) => { const title = node.title || node.slug return ( <article key={node.slug}> <header> <h3 style=<span>{</span><span>{</span> marginBottom: rhythm(1 / 4), <span>}</span><span>}</span> > <Link style=<span>{</span><span>{</span> boxShadow: `none` <span>}</span><span>}</span> to={node.slug}> {title} </Link> </h3> <small>{node.date}</small> </header> <section> <p dangerouslySetInnerHTML=<span>{</span><span>{</span> __html: node.keywords, <span>}</span><span>}</span> /> </section> </article> ) })} <nav> <ul style=<span>{</span><span>{</span> display: `flex`, flexWrap: `wrap`, justifyContent: `space-between`, listStyle: `none`, padding: 0, <span>}</span><span>}</span> > <li> {!isFirst && ( <Link to={prevPage} rel="prev"> ← Previous Page </Link> )} </li> <li> {!isLast && ( <Link to={nextPage} rel="next"> Next Page → </Link> )} </li> </ul> </nav> </Layout> ) } export default BlogIndex export const pageQuery = graphql` query blogPageQuery($skip: Int!, $limit: Int!) { site { siteMetadata { title } } allMicrocmsHogeHogeBlog( sort: {fields: [date], order: DESC} limit: $limit skip: $skip ) { edges { node { body createdAt date(formatString: "YYYY/MM/DD") id keywords publishedAt revisedAt slug title updatedAt } } } } ` </code></pre> <p>ここは大々的な改修というよりは、 GraphQL の変更と、それに併せて変化したデータ構造に合わせてプロパティ名やチェーンを調整した感じです。</p> <h3 id="blog-post.js"><a href="#blog-post.js">blog-post.js</a></h3> <pre><code class="javascript">import React from "react" import { Link, graphql } from "gatsby" import Bio from "../components/bio" import Layout from "../components/layout" import SEO from "../components/seo" import { rhythm, scale } from "../utils/typography" const BlogPostTemplate = ({ data, pageContext, location }) => { const post = data.markdownRemark // const siteTitle = data.site.siteMetadata.title const { previous, next } = pageContext return ( <Layout location={location} title="Home"> <SEO title={post.frontmatter.title} description={post.frontmatter.description || post.excerpt} /> <article> <header> <h1 style=<span>{</span><span>{</span> marginBottom: 0, <span>}</span><span>}</span> > {post.frontmatter.title} </h1> <p style=<span>{</span><span>{</span> ...scale(-1 / 5), display: `block`, marginBottom: rhythm(1), <span>}</span><span>}</span> > {post.frontmatter.date} </p> </header> <section dangerouslySetInnerHTML=<span>{</span><span>{</span> __html: post.html <span>}</span><span>}</span> /> <hr style=<span>{</span><span>{</span> marginBottom: rhythm(1), <span>}</span><span>}</span> /> <footer> <Bio /> </footer> </article> <nav> <ul style=<span>{</span><span>{</span> display: `flex`, flexWrap: `wrap`, justifyContent: `space-between`, listStyle: `none`, padding: 0, <span>}</span><span>}</span> > <li> {previous && ( <Link to={previous.fields.slug} rel="prev"> ← {previous.frontmatter.title} </Link> )} </li> <li> {next && ( <Link to={next.fields.slug} rel="next"> {next.frontmatter.title} → </Link> )} </li> </ul> </nav> </Layout> ) } export default BlogPostTemplate export const pageQuery = graphql` query BlogPostBySlug($slug: String!) { site { siteMetadata { title } } markdownRemark(fields: { slug: { eq: $slug } }) { id excerpt(pruneLength: 160) html frontmatter { title date(formatString: "MMMM DD, YYYY") description } } } ` </code></pre> <p>これを以下のように改修。</p> <pre><code class="javascript">import React from "react" import { Link, graphql } from "gatsby" import Bio from "../components/bio" import Layout from "../components/layout" import SEO from "../components/seo" import { rhythm, scale } from "../utils/typography" import marked from "marked" const BlogPostTemplate = ({ data, pageContext, location }) => { const post = data.microcmsHogeHogeBlog // const siteTitle = data.site.siteMetadata.title const { previous, next } = pageContext return ( <Layout location={location} title="Home"> <SEO title={post.title} description={post.keywords} /> <article> <header> <h1 style=<span>{</span><span>{</span> marginBottom: 0, <span>}</span><span>}</span> > {post.title} </h1> <p style=<span>{</span><span>{</span> ...scale(-1 / 5), display: `block`, marginBottom: rhythm(1), <span>}</span><span>}</span> > {post.date} </p> </header> <section dangerouslySetInnerHTML=<span>{</span><span>{</span> __html: marked(post.body) <span>}</span><span>}</span> /> <hr style=<span>{</span><span>{</span> marginBottom: rhythm(1), <span>}</span><span>}</span> /> <footer> <Bio /> </footer> </article> <nav> <ul style=<span>{</span><span>{</span> display: `flex`, flexWrap: `wrap`, justifyContent: `space-between`, listStyle: `none`, padding: 0, <span>}</span><span>}</span> > <li> {previous && ( <Link to={'../'+previous.slug} rel="prev"> ← {previous.title} </Link> )} </li> <li> {next && ( <Link to={'../'+next.slug} rel="next"> {next.title} → </Link> )} </li> </ul> </nav> </Layout> ) } export default BlogPostTemplate export const pageQuery = graphql` query BlogPostBySlug($slug: String!) { site { siteMetadata { title } } microcmsHogeHogeBlog(slug: { eq: $slug }) { id keywords title updatedAt slug revisedAt publishedAt date(formatString: "YYYY/MM/DD") createdAt body } } ` </code></pre> <p>こちらも <code>blog-list.tsx</code> と同様 GraphQL の変更とそれに伴うプロパティ名やチェーンの調整がメインです。本文の Markdown は冒頭の通り時短のため <code>marked</code> を使いました。</p> <p>こうして見てみると、 GraphQL に慣れるまでかなり紆余曲折した気がするのですが、 <code>blog-list.tsx</code> や <code>blog-post.js</code> は特に出来上がったコードがあまり元から変化していませんね……。</p> <h2 id="microCMS で APIキー を参照"><a href="#microCMS+%E3%81%A7+API%E3%82%AD%E3%83%BC+%E3%82%92%E5%8F%82%E7%85%A7">microCMS で APIキー を参照</a></h2> <p>microCMS で APIキー を控えます。</p> <p><a href="https://crieit.now.sh/upload_images/949bd68fc9e6b312266c6dd7d831ade5612a583ed1bd6.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/949bd68fc9e6b312266c6dd7d831ade5612a583ed1bd6.jpg?mw=700" alt="APIキーの取得" /></a></p> <p>「サービス設定」→「APIキー」と進みます。今回必要なのは「X-API-KEY」。これを控えておきます。</p> <h2 id="Vercel の設定"><a href="#Vercel+%E3%81%AE%E8%A8%AD%E5%AE%9A">Vercel の設定</a></h2> <p>続いて Vercel の設定へ。</p> <h3 id="環境変数の設定"><a href="#%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0%E3%81%AE%E8%A8%AD%E5%AE%9A">環境変数の設定</a></h3> <p>まずは環境変数の設定。</p> <p><a href="https://crieit.now.sh/upload_images/57a8cc2a08598bf78b631bbd9da2a024612a5842798b2.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/57a8cc2a08598bf78b631bbd9da2a024612a5842798b2.jpg?mw=700" alt="環境変数の設定" /></a></p> <p>プロジェクトを選択後、「Settings」から「Enviroment Variables」へ。</p> <p>「NAME」にコードに記載したキーの名前を付けて、実際の値を入力します。画面では APIキー なので上述の microCMS の管理画面で控えた APIキー を入力。</p> <p><a href="https://crieit.now.sh/upload_images/3bbfd322b71fb32df23894afdd5853d5612a584583337.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/3bbfd322b71fb32df23894afdd5853d5612a584583337.jpg?mw=700" alt="環境変数の設定2" /></a></p> <p>他、必要な変数をセットします。</p> <h3 id="Deploy Hooks を登録"><a href="#Deploy+Hooks+%E3%82%92%E7%99%BB%E9%8C%B2">Deploy Hooks を登録</a></h3> <p>次に Deploy Hooks をひっかけます。</p> <p>プロジェクトの「Settings」から今度は「Git」へ。</p> <p><a href="https://crieit.now.sh/upload_images/4f89b78a73ad66c2fab07245a0b599ac612a58482a821.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/4f89b78a73ad66c2fab07245a0b599ac612a58482a821.jpg?mw=700" alt="Deploy hooks" /></a></p> <p>Deploy Hooks に名前を入力、ブランチは通常は <code>main</code> になるかと。</p> <p><a href="https://crieit.now.sh/upload_images/792d34407a2e1061c785101139250868612a584aeed86.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/792d34407a2e1061c785101139250868612a584aeed86.jpg?mw=700" alt="Deploy Hooks を控える" /></a></p> <p>登録されたら Hook の URL を控えます。</p> <h2 id="microCMS の設定"><a href="#microCMS+%E3%81%AE%E8%A8%AD%E5%AE%9A">microCMS の設定</a></h2> <p>お次は microCMS の画面へ。</p> <p><a href="https://crieit.now.sh/upload_images/16478a5b69bd9cb593abea925cd2c925612a584d45b74.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/16478a5b69bd9cb593abea925cd2c925612a584d45b74.jpg?mw=700" alt="Webhook" /></a></p> <p>サービスの管理画面から「API設定」→「Webhook」へ。</p> <p><a href="https://crieit.now.sh/upload_images/192e10d26803bfa0dcf31470a2553f63612a58505802c.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/192e10d26803bfa0dcf31470a2553f63612a58505802c.jpg?mw=700" alt="カスタム通知" /></a></p> <p>Vercel は一覧にはないので「カスタム通知」を選択。</p> <p><a href="https://crieit.now.sh/upload_images/b93547fbc6ca4f11e11986ec1869d7d5612a5853d80e0.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/b93547fbc6ca4f11e11986ec1869d7d5612a5853d80e0.jpg?mw=700" alt="Vercel の Hook を設定" /></a></p> <p>名前は任意の名前を。</p> <p>Hook の URL に先ほど控えた URL を入力します。</p> <p><a href="https://crieit.now.sh/upload_images/39693fd99f7447504a37a4bfd38afea0612a58568376c.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/39693fd99f7447504a37a4bfd38afea0612a58568376c.jpg?mw=700" alt="Hook の権限" /></a></p> <p>権限はこのような感じ。基本的に公開されているデータに変更が加わったら Hook が通知を行うものとします。</p> <h2 id="テスト投稿"><a href="#%E3%83%86%E3%82%B9%E3%83%88%E6%8A%95%E7%A8%BF">テスト投稿</a></h2> <p><a href="https://crieit.now.sh/upload_images/58704ee832c977a18796e1a3e05c2c8f612a5859db3dd.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/58704ee832c977a18796e1a3e05c2c8f612a5859db3dd.jpg?mw=700" alt="記事を試しに追加" /></a></p> <p>ここまで設定できたら、試しに記事を新しく追加してみます。</p> <p><a href="https://crieit.now.sh/upload_images/b79d4f2666aaa6c98f4c010011c12e6f612a585d5f4c4.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/b79d4f2666aaa6c98f4c010011c12e6f612a585d5f4c4.jpg?mw=700" alt="Vercel 側が反応" /></a></p> <p>すると、 Vercel 側でプロジェクトが反応してビルドが走り始めました。</p> <p><a href="https://crieit.now.sh/upload_images/75c7890bf380c4b476fea57535096623612a586141166.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/75c7890bf380c4b476fea57535096623612a586141166.jpg?mw=700" alt="デプロイ完了" /></a></p> <p>microCMS に記事を追加すると、 Github のリポジトリに push することなく勝手にビルドが走ってサイトが更新されることが確認できました。</p> <p>これで Gatsby.js + Vercel + microCMS で JAMStack なブログの仕組みが構築できました。実験成功です。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <h3 id="改修"><a href="#%E6%94%B9%E4%BF%AE">改修</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://zenn.dev/k1_style/scraps/07cce0dd3611e3">Gatsby + microcms + Vercel でブログを作って公開したい</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://www.gatsbyjs.com/plugins/gatsby-source-microcms/">gatsby-source-microcms | Gatsby</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://zenn.dev/rokki188/articles/948d53199508c7">microCMS + Next.js でJamStackブログを作ってみた</a></li> </ul> <h3 id="コード、GraphQL、microCMSの設定、環境変数"><a href="#%E3%82%B3%E3%83%BC%E3%83%89%E3%80%81GraphQL%E3%80%81microCMS%E3%81%AE%E8%A8%AD%E5%AE%9A%E3%80%81%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0">コード、GraphQL、microCMSの設定、環境変数</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://blog.microcms.io/microcms-next-jamstack-blog/">microCMS + Next.jsでJamstackブログを作ってみよう | microCMSブログ</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://blog.microcms.io/gatsby-microcms-media/">GatsbyJS + microCMSでJamstackなオウンドメディアを作ろう | microCMSブログ</a></li> </ul> <h3 id="Vercel の環境変数"><a href="#Vercel+%E3%81%AE%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0">Vercel の環境変数</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://vercel.com/docs/environment-variables">Vercel – Environment Variables - Vercel Documentation</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://www.snorerelax.com/posts/tech-vercel-environment/">Vercelで環境変数を設定する | Next.js Blog Example with すのりら</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/Slowhand0309/items/f954237520d343fa9e4c">Vercelで設定した環境変数をNext.jsで使用する - Qiita</a></li> </ul> <h4 id="環境変数の分かち書き"><a href="#%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0%E3%81%AE%E5%88%86%E3%81%8B%E3%81%A1%E6%9B%B8%E3%81%8D">環境変数の分かち書き</a></h4> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://blog.gaji.jp/2020/06/09/4030/">GatsbyJSで開発環境にのみページを存在させる方法 ++ Gaji-Laboブログ</a></li> </ul> <h3 id="gatsby-plugin-feed"><a href="#gatsby-plugin-feed">gatsby-plugin-feed</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://www.gatsbyjs.com/plugins/gatsby-plugin-feed/">gatsby-plugin-feed | Gatsby</a></li> </ul> <p>基本 Gatsby.js のプラグインのページはシンプルなサンプルなので <code>http://localhost:8000/___graphql</code> で GraphQL を試して感覚をつかむ方が早かった気がします。</p> arm-band tag:crieit.net,2005:PublicArticle/17615 2021-08-25T22:14:35+09:00 2021-08-29T20:33:12+09:00 https://crieit.net/posts/publish-blog-by-gatsvyjs-vercel-20210825 Gatsby.js + Vercel でブログを作ってみる <p>兼ねてより試してみたかった Gatsby.js + Vercel の組み合わせに着手してみました。</p> <h2 id="1. Gatsby.js のインストールと Gitリポジトリ の準備"><a href="#1.+Gatsby.js+%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%A8+Git%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA+%E3%81%AE%E6%BA%96%E5%82%99">1. Gatsby.js のインストールと Gitリポジトリ の準備</a></h2> <p>まずは Gatsby.js のプロジェクトを作って Gitホスティングサービス に push します。</p> <pre><code class="bash">> yarn init ## 略 success Saved package.json Done in 2.33s. </code></pre> <p>適当なディレクトリで <code>package.json</code> を生成。</p> <pre><code class="bash">> yarn add gatsby-cli ## 略 Done in 26.05s. </code></pre> <p>続いて <code>gatsby-cli</code> をインストールします。一応グローバルではなくローカルで。</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://www.gatsbyjs.com/static/203f352fa59959029a106ffe821ad0bb/85e35/93d59e2b139dc14ee2118ff7410333c9.webp">: Gatsby Starter | Gatsby</a></li> </ul> <p>今回のテーマはこれにします。</p> <pre><code class="bash">> gatsby new mptotkb https://github.com/renyuanz/leonids ╔════════════════════════════════════════════════════════════════════════╗ ║ ║ ║ Gatsby collects anonymous usage analytics ║ ║ to help improve Gatsby for all users. ║ ║ ║ ║ If you'd like to opt-out, you can use `gatsby telemetry --disable` ║ ║ To learn more, checkout https://gatsby.dev/telemetry ║ ║ ║ ╚════════════════════════════════════════════════════════════════════════╝ info Creating new site from git: https://github.com/renyuanz/leonids.git Cloning into 'mptotkb'... remote: Enumerating objects: 60, done. remote: Counting objects: 100% (60/60), done. remote: Compressing objects: 100% (44/44), done. Receiving objects: 100% (60/60), 542.69 KiB | 5.32 MiB/s, done.eceiving objects: 100% (60/60) success Created starter directory layout info Installing packages... info Preferred package manager set to "npm" ## 略 Your new Gatsby site has been successfully bootstrapped. Start developing it by running: cd mptotkb gatsby develop </code></pre> <p>プロジェクト作成完了。</p> <pre><code class="bash">> cd mptotkb > gatsby develop ## 略 info Hi from the Gatsby maintainers! Based on what we see in your site, these coming features may help you. All of these can be enabled within gatsby-config.js via flags (samples below) Preserve webpack's Cache (https://github.com/gatsbyjs/gatsby/discussions/28331), which changes Gatsby's cache clearing behavior to not clear webpack's cache unless you run "gatsby clean" or delete the .cache folder manually. Here's how to try it: module.exports = { flags: { PRESERVE_WEBPACK_CACHE: true }, plugins: [...] } ⠀ You can now view gatsby-starter-leonids in the browser. ⠀ http://localhost:8000/ ⠀ View GraphiQL, an in-browser IDE, to explore your site's data and schema ⠀ http://localhost:8000/___graphql ⠀ Note that the development build is not optimized. To create a production build, use gatsby build ⠀ success Building development bundle - 48.261s </code></pre> <p>OK。完了しました。</p> <p>最初は手始めということでこの状態でいったん push しておきたいと思います。 Gitリポジトリ に登録するのは親ディレクトリではなく作成したプロジェクト (今回は <code>mptotkb</code> 下) です。</p> <p><a href="https://crieit.now.sh/upload_images/c767731cd51656a0324d46f4f80e7af261263f776ecdc.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/c767731cd51656a0324d46f4f80e7af261263f776ecdc.jpg?mw=700" alt="GitHub でリポジトリを作成" /></a></p> <p>GitHub でリポジトリを作成して、このリポジトリに先ほどのプロジェクトを push 。ちなみにリポジトリは public である必要があります。</p> <h2 id="2. Vercel と Gitホスティングサービス の連携"><a href="#2.+Vercel+%E3%81%A8+Git%E3%83%9B%E3%82%B9%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9+%E3%81%AE%E9%80%A3%E6%90%BA">2. Vercel と Gitホスティングサービス の連携</a></h2> <p>次に Vercel でアカウントを作ります。</p> <p><a href="https://crieit.now.sh/upload_images/77ce0ff86a6de3b873bb06d7f1de0c8e61263f822ba39.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/77ce0ff86a6de3b873bb06d7f1de0c8e61263f822ba39.jpg?mw=700" alt="Vercel で Sign Up をクリック" /></a></p> <p>Sign Up をクリック。</p> <p><a href="https://crieit.now.sh/upload_images/43666c5f16041fc59fdb8d593a9b955561263f8d448dd.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/43666c5f16041fc59fdb8d593a9b955561263f8d448dd.jpg?mw=700" alt="GitHub と連携" /></a></p> <p>今回は GitHub を使用しているので「Continue with GitHub」を選択。</p> <p><a href="https://crieit.now.sh/upload_images/1f94d557606bdff1448bcb340a9d56b861263f98c6f6f.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/1f94d557606bdff1448bcb340a9d56b861263f98c6f6f.jpg?mw=700" alt="Vercel のアクセスを認証して権限を付与" /></a></p> <p>「Authorize Vercel」で Vercel のアクセスを認証します。</p> <p><a href="https://crieit.now.sh/upload_images/0e40bf8259a51bb7dea9189426fb3f5961263faa0614f.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/0e40bf8259a51bb7dea9189426fb3f5961263faa0614f.jpg?mw=700" alt="Vercel にログイン成功" /></a></p> <p>ログインできました。</p> <h2 id="3. リポジトリのインポート"><a href="#3.+%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%88">3. リポジトリのインポート</a></h2> <p><a href="https://crieit.now.sh/upload_images/9b1b79698c430d0d958f3d770e4c62bf61263fbda9d17.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/9b1b79698c430d0d958f3d770e4c62bf61263fbda9d17.jpg?mw=700" alt="ダッシュボードから「New Project」" /></a></p> <p>一度中断してしまったのでダッシュボードから。ここからであれば「New Project」で次へ進みます。</p> <p><a href="https://crieit.now.sh/upload_images/490785baeef1275ccb89cdb6d4a5db7861263fc869e4e.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/490785baeef1275ccb89cdb6d4a5db7861263fc869e4e.jpg?mw=700" alt="Import Git Repository から「Add GitHub Org or Account」" /></a></p> <p>Import Git Repository から「Add GitHub Org or Account」。</p> <p><a href="https://crieit.now.sh/upload_images/92eb299d6668bdba87d40c089976f9fc61263fd566948.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/92eb299d6668bdba87d40c089976f9fc61263fd566948.jpg?mw=700" alt="インポートするリポジトリを選択" /></a></p> <p>インポートするリポジトリを選択します。今回は1つのリポジトリだけに Vercel に連携させます。</p> <p><a href="https://crieit.now.sh/upload_images/95606ef51dd06912c5fe460301a1d09361263fe080aa9.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/95606ef51dd06912c5fe460301a1d09361263fe080aa9.jpg?mw=700" alt="リポジトリの確認" /></a></p> <p>リポジトリの確認です。使用しているフレームワークが自動判別されるのはありがたいですね。</p> <p><a href="https://crieit.now.sh/upload_images/676cf8e4e4edee1f6c692cd0a445524e61263fea8e98f.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/676cf8e4e4edee1f6c692cd0a445524e61263fea8e98f.jpg?mw=700" alt="チームの作成は「Skip」" /></a></p> <p>次の画面でフローに沿って設定を進めていきます。最初に Vercel のチームを作成する画面が有効になっていますが、今回は個人なので「Skip」。</p> <p><a href="https://crieit.now.sh/upload_images/fa75aa33dba45c6b8029ab0a0a3695bc61263ff3507ed.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/fa75aa33dba45c6b8029ab0a0a3695bc61263ff3507ed.jpg?mw=700" alt="Configure Project" /></a></p> <p>プロジェクトの設定。出力の設定や環境変数を設定できますが、今回はそのままで。</p> <p><a href="https://crieit.now.sh/upload_images/64a16b6c3867805df977e0ac9704d57361263ffb9d76a.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/64a16b6c3867805df977e0ac9704d57361263ffb9d76a.jpg?mw=700" alt="デプロイ中" /></a></p> <p>デプロイ中。</p> <p><a href="https://crieit.now.sh/upload_images/eb14aeca4ce6114b32dd4f90697d064361264004d26ec.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/eb14aeca4ce6114b32dd4f90697d064361264004d26ec.jpg?mw=700" alt="デプロイされた画面を実際に確認" /></a></p> <p>少し待つとデプロイが完了します。そこでURLから実際の画面を表示させると……きちんとデプロイされていました!</p> <p>ここまでで Gatsby.js + Vercel でブログを作成することができました。</p> <p>今後の課題としては以下の通り。</p> <ul> <li>サイト名や著者情報といった基本情報のカスタマイズ</li> <li>どうやらブログ記事の Markdown ファイルを生成する CLI やユーティリティはなさそうで、手作業で記事をちまちま作っていくのは手間なので記事リソースを別の場所 (<a href="https://crieit.net/posts/gatsby-vercel-microcms-cooprate-20210829-1">Headless CMS</a> とか) で管理して <a href="https://crieit.net/posts/gatsby-vercel-microcms-cooprate-20210829-2">JAMStack にする</a></li> </ul> <p>あとは折角なので GraphQL にも少しは触ってみたいところですね。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <h3 id="Gatsby.js + Vercel"><a href="#Gatsby.js+%2B+Vercel">Gatsby.js + Vercel</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://webcraftlog.net/gatsbyjs-site-deploy-to-vercel/">【ZEIT Now】Gatsbyサイトを無料サーバーVercelで公開する方法を徹底解説 | WebCraftLog</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://zenn.dev/k1_style/scraps/07cce0dd3611e3">Gatsby + microcms + Vercel でブログを作って公開したい</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://vercel.com/docs/git">Vercel – Git - Vercel Documentation</a> <ul> <li>参考記事とは画面構成が変わっていたため、最終的には Vercel のドキュメントが頼りでした</li> </ul></li> </ul> <h3 id="Gatsby.js のテーマ"><a href="#Gatsby.js+%E3%81%AE%E3%83%86%E3%83%BC%E3%83%9E">Gatsby.js のテーマ</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://www.gatsbyjs.com/starters/?c=Blog">Gatsby Starters: Library | Gatsby</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://www.gatsbyjs.com/starters/renyuanz/leonids">: Gatsby Starter | Gatsby</a></li> </ul> <h3 id="Vercel"><a href="#Vercel">Vercel</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://dev.classmethod.jp/articles/vercel/">NetlifyキラーのVercelでウェブサイトをホストしたら簡単すぎて笑顔になった | DevelopersIO</a></li> </ul> <h3 id="Gatsby.js"><a href="#Gatsby.js">Gatsby.js</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/k-penguin-sato/items/7554e5e7e90aa10ae225">GatsbyとNetlifyで簡単にブログを作成 - Qiita</a></li> </ul> arm-band tag:crieit.net,2005:PublicArticle/15463 2019-10-08T08:41:01+09:00 2019-10-08T08:41:01+09:00 https://crieit.net/posts/GatsbyJS-5d9bcd0d8d744 GatsbyJSで次の記事、前の記事へのリンクを生成する方法 <p><strong>オリジナルの記事は<a target="_blank" rel="nofollow noopener" href="https://www.mono7555e.com/implement-next-and-previous-links-in-gatsbyjs/">こちら</a></strong></p> <hr /> <p>こんにちは。mono(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/mono7555e" target="_blank" rel="noopener">@mono7555e</a>)です。</p> <p>記事ページで他の記事へ行く術がなく直帰率が高くなっていたので他の記事への遷移を追加することにしました。</p> <p>ちょっとひと手間かかりますがGatsbyJSでも実現できましたのでご紹介したいと思います。</p> <h2 id="ページ生成時に前後の記事情報を渡す"><a href="#%E3%83%9A%E3%83%BC%E3%82%B8%E7%94%9F%E6%88%90%E6%99%82%E3%81%AB%E5%89%8D%E5%BE%8C%E3%81%AE%E8%A8%98%E4%BA%8B%E6%83%85%E5%A0%B1%E3%82%92%E6%B8%A1%E3%81%99">ページ生成時に前後の記事情報を渡す</a></h2> <pre><code class="js">exports.createPages = async ({ actions, graphql }) => { const { createPage } = actions const template = path.resolve(`src/templates/blog.tsx`) await graphql(` { allMarkdownRemark( sort: { order: DESC, fields: [frontmatter___published_at] } limit: 2000 ) { edges { node { fields { slug } frontmatter { title image } } } } } `).then(result => { if (result.errors) { return Promise.reject(result.errors) } const pages = result.data.allMarkdownRemark.edges pages.forEach(({ node }, index) => { const prev = index === 0 ? null : pages[index - 1].node const next = index === pages.length - 1 ? null : pages[index + 1].node createPage({ path: node.fields.slug, component: template, context: { slug: node.fields.slug, prev, next, }, }) }) }) } </code></pre> <p>重要なのは<code>const prev = ~</code>と<code>const next ~</code>の部分と、contextでそれを設定している部分です。<br /> それ以外のところは自由です。</p> <h2 id="設定された前後の記事情報を元にリンクを生成"><a href="#%E8%A8%AD%E5%AE%9A%E3%81%95%E3%82%8C%E3%81%9F%E5%89%8D%E5%BE%8C%E3%81%AE%E8%A8%98%E4%BA%8B%E6%83%85%E5%A0%B1%E3%82%92%E5%85%83%E3%81%AB%E3%83%AA%E3%83%B3%E3%82%AF%E3%82%92%E7%94%9F%E6%88%90">設定された前後の記事情報を元にリンクを生成</a></h2> <p>ちょっとごちゃごちゃしてしまったので前後の記事用のコンポーネントに分割しました。</p> <pre><code class="jsx">import React from "react" import { Box, Card, CardActionArea, CardContent, Typography } from "@material-ui/core" import Image from "../atoms/image" const PrevNext = ({ prev, next }) => { return( <Box mt={5} display="flex" justifyContent="space-between"> { prev == null ? null : _link(prev, `prev`)} { next == null ? null : _link(next, `next`)} </Box> ) } export default PrevNext const _link = ({ fields, frontmatter }, direction) =>{ return( <Box display="flex" flexDirection="column" style=<span>{</span><span>{</span> width: `40%` <span>}</span><span>}</span>> <Typography gutterBottom variant="body2" component="h6"> { direction == 'prev' ? '前の記事' : '次の記事'} </Typography> <Card style=<span>{</span><span>{</span> width: `100%`, height: `100%`<span>}</span><span>}</span>> <CardActionArea href={fields.slug} style=<span>{</span><span>{</span> display: 'flex', alignItems: `stretch`, height: `100%` <span>}</span><span>}</span>> <Box style=<span>{</span><span>{</span> width: `35%` <span>}</span><span>}</span>> <Image filename={frontmatter.image} style=<span>{</span><span>{</span> height: `100%` <span>}</span><span>}</span> /> </Box> <CardContent style=<span>{</span><span>{</span> flex: `1` <span>}</span><span>}</span>> <Typography variant="body2" component="p"> {frontmatter.title} </Typography> </CardContent> </CardActionArea> </Card> </Box> ) } </code></pre> <p>このブログは<a target="_blank" rel="nofollow noopener" href="https://material-ui.com/" target="_blank" rel="noopener">Material-UI</a>を使っているのでちょっとややこしい感じになりますが、単純にリンクをするだけであればもう少し簡単に書けると思います。</p> <p>あとは作った前後の記事用のコンポーネントをテンプレートから呼び出すだけです。</p> <pre><code class="jsx">// importなどなど export default function Template({ data, pageContext }) { // 中略 return ( <Layout> <Container maxWidth="md" component="article"> {/* その他コンポーネント読み込み */} <PrevNext prev={pageContext.prev} next={pageContext.next} /> </Container> </Layout> ) } </code></pre> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>やってみると結構かんたんでした。</p> <p>今はイメージとタイトルだけですが、タグや日付など各記事が持っている情報を利用できるのでよりリッチな前後の記事へのリンクが設置できると思います。</p> mono7555e tag:crieit.net,2005:PublicArticle/15462 2019-10-08T08:32:43+09:00 2019-10-08T08:46:46+09:00 https://crieit.net/posts/gatsby-transformer-remark gatsby-transformer-remarkで出力されるコンポーネントをカスタマイズする方法 <p><strong>オリジナルの記事は<a target="_blank" rel="nofollow noopener" href="https://www.mono7555e.com/customize-gatsby-transfer-remark/">こちら</a></strong></p> <hr /> <p>こんにちは。mono(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/mono7555e" target="_blank" rel="noopener">@mono7555e</a>)です。</p> <p>このブログがGatsbyJSで作られていること、<a target="_blank" rel="nofollow noopener" href="https://www.gatsbyjs.org/packages/gatsby-transformer-remark/" target="_blank" rel="noopener">gatsby-transformer-remark</a>を使ってMakrdownを読み込んでいることは以前にもご紹介しましたが、今回はそこで出力されるHTML(コンポーネント)をカスタマイズする方法をご紹介したいと思います。</p> <p>かなり簡単で、ずばり<a target="_blank" rel="nofollow noopener" href="https://github.com/rehypejs/rehype-react" target="_blank" rel="noopener">rehype-react</a>を使うとやりたいことが出来ます。</p> <h2 id="既存コンポーネントを独自コンポーネントに置き換える"><a href="#%E6%97%A2%E5%AD%98%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%82%92%E7%8B%AC%E8%87%AA%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%AB%E7%BD%AE%E3%81%8D%E6%8F%9B%E3%81%88%E3%82%8B">既存コンポーネントを独自コンポーネントに置き換える</a></h2> <p>まずは<code>h1</code>や<code>p</code>などの既存コンポーネントを置き換える方法についてです。</p> <p>私が実際に使っているものを例にするとこんな感じになります。</p> <pre><code class="tsx">import rehypeReact from "rehype-react" import { Box, Typography } from "@material-ui/core" // 中略 export const renderAst = new rehypeReact({ createElement: React.createElement, components: { 'h2': (props: TypographyProps) => { return ( <Box mt={4} mb={2} py={2} px={3} bgcolor="primary.400" color="common.white"> <Typography variant="h6" component="h2" {...props}></Typography> </Box> ) }, 'h3': (props: TypographyProps) => { return ( <Box mt={4} mb={2} py={1} px={2} borderLeft={4} borderColor="primary.500"> <Typography variant="h6" component="h3" {...props}></Typography> </Box> ) }, 'h4': (props: TypographyProps) => { return ( <Box mt={4} mb={2} py={1} px={1} borderBottom={1} borderColor="primary.500"> <Typography variant="body1" component="h4" {...props}></Typography> </Box> ) }, 'p': (props: TypographyProps) => { return ( <Typography variant="body2" component="p" style=<span>{</span><span>{</span> marginTop: `1rem`, marginBottom: `1rem`, lineHeight: 1.8 <span>}</span><span>}</span> {...props}></Typography> ) }, // などなど }, }).Compiler </code></pre> <p>全体的に<a target="_blank" rel="nofollow noopener" href="https://material-ui.com/" target="_blank" rel="noopener">Material-UI</a>を使っているので、そのコンポーネントに各既存コンポーネントを置き換えています。</p> <p>あとは、GraphQLで取得するデータを<code>html</code>から<code>htmlAst</code>に変更し、定義した<code>renderAst</code>を使うように書き換えます。</p> <p>具体的には</p> <pre><code class="jsx"><div dangerouslySetInnerHTML=<span>{</span><span>{</span> __html: html <span>}</span><span>}</span> /> </code></pre> <p>を↓に置き換える感じです。</p> <pre><code class="jsx"><div>{renderAst(htmlAst)}</div> </code></pre> <p>ここまで来ればあとは自由にカスタマイズ可能です。</p> <h2 id="独自コンポーネントを読み込む"><a href="#%E7%8B%AC%E8%87%AA%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%82%92%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%82%80">独自コンポーネントを読み込む</a></h2> <p>前述の例では、既存コンポーネントを独自コンポーネントに置き換える方法でしたが、独自コンポーネントを追加することも出来ます。</p> <p>まずは読み込みたいコンポーネントを作ります。</p> <p>```jsx:title=src/components/atoms/custom.tsx<br /> import React from 'react'</p> <p>const Custom = () => {<br /> return(<br /> <div><br /> <p>独自コンポーネント</p><br /> </div><br /> )<br /> }<br /> export default Custom</p> <pre><code><br />Markdownファイルのコンポーネントを読み込みたい場所にタグを追加します。 ```md ↓コンポーネント読み込み↓ <custom></custom> ↑コンポーネント読み込み↑ </code></pre> <p>※ちなみに<code><custom /></code>と書きたくなりますがこれだとダメでした</p> <p>それが置き換えられるように<code>rehypeReact</code>を設定します。</p> <pre><code class="jsx">import rehypeReact from "rehype-react" import Custom from "../components/custom" // 中略 export const renderAst = new rehypeReact({ createElement: React.createElement, components: { 'custom': Custom, }, }).Compiler </code></pre> <p>これで<code><custom></custom></code>と書かれたところ<code>Custom</code>コンポーネントになって出力されるようになります。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p><code>gatsby-transformer-remark</code>を使っている際にカスタマイズをしたい場合<code>rehype-react</code>を使えば簡単なことであれば大体のことは出来ると思います。</p> <p>もし、さらにより細かいカスタマイズを行いたい場合は今回のように置き換えるのではなくて、コンポーネント自体を読み込めるようになる<a target="_blank" rel="nofollow noopener" href="https://mdxjs.com/" target="_blank" rel="noopener">MDX</a>を使うと良さそうです。</p> mono7555e tag:crieit.net,2005:PublicArticle/15460 2019-10-08T08:07:21+09:00 2019-10-08T08:11:32+09:00 https://crieit.net/posts/GatsbyJS-Netlify-5d9bc529145a3 いまブログを始めるならGatsbyJS+Netlifyがオススメ! <p><strong>オリジナルの記事は<a target="_blank" rel="nofollow noopener" href="https://www.mono7555e.com/gatsbyjs-and-netlify/">こちら</a></strong></p> <hr /> <p>こんにちは。mono(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/mono7555e" target="_blank" rel="noopener">@mono7555e</a>)です。</p> <p>今回は新しくブログを立ち上げた際に使ったGatsbyJSとNetlifyのご紹介です。<br /> 新しくブログを立ち上げようとしている方やWordPressに疲れた方には参考になるんじゃないかと思います。</p> <h2 id="GatsbyJSとは"><a href="#GatsbyJS%E3%81%A8%E3%81%AF">GatsbyJSとは</a></h2> <p><a target="_blank" rel="nofollow noopener" href="https://www.gatsbyjs.org/">https://www.gatsbyjs.org/</a></p> <p>GatsbyJSは<a target="_blank" rel="nofollow noopener" href="https://reactjs.org/" target="_blank" rel="noopener">React</a>で作られた静的サイトジェネレーターです。<br /> JSONやYAML、XMLなど扱うデータを全て一回GraphQLで取り出せるように変換してくれるので、様々なデータが扱いやすく、コンポーネント化がしやすいという特長があります。</p> <p>また、プラグインも豊富で大抵の場合、既にプラグインがあるのでそれを使うように設定してあげればOKです。</p> <p>今回のブログ立ち上げの際にも<strong>Markdownで記事が書ける</strong>というのを必須事項にあげていたので<code>gatsby-transformer-remark</code>というプラグインを利用してMakrdownファイルをGraphQLで扱えるようにしました。</p> <p>他にもsitemap.xmlを生成してくれる<code>gatsby-plugin-sitemap</code>、Google Tag Managerのタグを入れてくれる<code>gatsby-plugin-google-tagmanager</code>など利用しています。</p> <h2 id="なぜWordPressを使わなかったのか"><a href="#%E3%81%AA%E3%81%9CWordPress%E3%82%92%E4%BD%BF%E3%82%8F%E3%81%AA%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%8B">なぜWordPressを使わなかったのか</a></h2> <p>ブログを立ち上げるとなると真っ先に思い浮かぶのがWordPressだと思います。<br /> ですが、今回は使うのをやめました。<br /> WordPressを使った経験はある方なら分かると思うのですが色々つらみを感じているからです。</p> <h3 id="セキュリティが不安"><a href="#%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E3%81%8C%E4%B8%8D%E5%AE%89">セキュリティが不安</a></h3> <p>WordPressはかなり使われているので様々な方面から狙われやすいです。<br /> セキュリティパッチ等のアップデートを忘れているとすぐに狙われて乗っ取られたり、悪意のあるコードを埋め込められたりする恐れがあります。</p> <h3 id="管理が大変"><a href="#%E7%AE%A1%E7%90%86%E3%81%8C%E5%A4%A7%E5%A4%89">管理が大変</a></h3> <p>前述の通りセキュリティが不安なのでセキュリティパッチが降ってきたらすぐに適用したいのですがカスタマイズをバリバリやっていたりプラグインを使っている場合、それらが邪魔をしてアップデートが出来ないことがままあります。<br /> また、WordPressだけでなくPHPやWebサーバーの管理等も必要なのでその辺りも大変です(レンタルサーバーの場合はその辺り任せられるので楽ですが、カスタマイズがしづらい場合もあります。)</p> <h3 id="PHP書くの辛い"><a href="#PHP%E6%9B%B8%E3%81%8F%E3%81%AE%E8%BE%9B%E3%81%84">PHP書くの辛い</a></h3> <p>最後はかなり個人的な理由です。<br /> WordPressはPHPで作られているので、ある程度カスタマイズをしようと思うとPHPでコードを書く必要があるのですが、PHPは書いててあまり楽しい言語ではないので出来れば避けたいと思っています。</p> <h2 id="なぜブログサービスを使わなかったのか"><a href="#%E3%81%AA%E3%81%9C%E3%83%96%E3%83%AD%E3%82%B0%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%92%E4%BD%BF%E3%82%8F%E3%81%AA%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%8B">なぜブログサービスを使わなかったのか</a></h2> <p>WordPress以外にもブログをはじめるのに使えるサービスがいくつかありますが、Markdown、アフィリエイト、カスタマイズ性の辺りがマッチせず使うのを諦めました。</p> <p>有名なところだとAmebaブログ、ライブドアブログ、fc2ブログなどがありますが、それらのブログサービスはMarkdownで記事が書けないので除外しました。</p> <p>Markdownが使えるのは、調べた限りだとMedium、note、Qiita、はてなブログぐらいですが、それらも他の部分がネックになりました。</p> <h3 id="Medium"><a href="#Medium">Medium</a></h3> <p>使ったことがないので何とも言えないところですが、日本で使っている人が少ない印象で、検索に引っかかることもないのでSEOにも強くなさそうな印象です。<br /> <a target="_blank" rel="nofollow noopener" href="https://medium.com/@MEJapan/from-medium-japan-ad346bee2a9b">2017年に日本から撤退</a>しているのも気になりました。</p> <h3 id="note"><a href="#note">note</a></h3> <p>アフィリエイトが貼れなかったり、カスタマイズも出来ないのがちょっと辛いかなと。<br /> ただ、有料記事が販売できたりするのでブログとは別に利用しようと思っています。</p> <p><a target="_blank" rel="nofollow noopener" href="https://note.mu/mono7555e">https://note.mu/mono7555e</a></p> <h3 id="Qiita"><a href="#Qiita">Qiita</a></h3> <p>noteと同様にアフィリエイト、カスタマイズが出来ないのと、プログラミングに関するものしか投稿できないというのがネックです。<br /> もしかしたらめちゃくちゃコードを見せるような記事はQiitaに書くかもしれません。</p> <p>一応登録だけはしました。</p> <p><a target="_blank" rel="nofollow noopener" href="https://qiita.com/mono7555e">https://qiita.com/mono7555e</a></p> <h3 id="はてなブログ"><a href="#%E3%81%AF%E3%81%A6%E3%81%AA%E3%83%96%E3%83%AD%E3%82%B0">はてなブログ</a></h3> <p>4つの中だと、<a target="_blank" rel="nofollow noopener" href="https://hatenablog.com/" target="_blank" rel="noopener">はてなブログ</a>は結構良くてサクッと立ち上げるならオススメです。<br /> 独自ドメインを設定する場合は有料プランになってしまいますが気にしない方なら無料版で事足りると思います。<br /> 今回はガッツリカスタマイズしたかったのでやめました。</p> <h2 id="GatsbyJSを選んだ理由"><a href="#GatsbyJS%E3%82%92%E9%81%B8%E3%82%93%E3%81%A0%E7%90%86%E7%94%B1">GatsbyJSを選んだ理由</a></h2> <p>ということでGatsbyJSです。</p> <p>GatsbyJSはReactベースでGraphQLでデータを扱うというのが当時、流行っていたというのもあって採用することにしました。</p> <h2 id="GatsbyJSの良いところ、悪いところ"><a href="#GatsbyJS%E3%81%AE%E8%89%AF%E3%81%84%E3%81%A8%E3%81%93%E3%82%8D%E3%80%81%E6%82%AA%E3%81%84%E3%81%A8%E3%81%93%E3%82%8D">GatsbyJSの良いところ、悪いところ</a></h2> <h3 id="高速"><a href="#%E9%AB%98%E9%80%9F">高速</a></h3> <p>WordPressなどと違い事前にHTMLを生成してあるのでレスポンスが高速です。</p> <h3 id="維持費が安い"><a href="#%E7%B6%AD%E6%8C%81%E8%B2%BB%E3%81%8C%E5%AE%89%E3%81%84">維持費が安い</a></h3> <p>基本的には静的HTMLを置いておくだけでOKなので、AppサーバーやDBは不要。<br /> 後述するNetlify等の静的サイトをホスティングするサービスを使うだけでほとんどの場合事足ります。</p> <h3 id="豊富なプラグイン、ライブラリ"><a href="#%E8%B1%8A%E5%AF%8C%E3%81%AA%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E3%80%81%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA">豊富なプラグイン、ライブラリ</a></h3> <p>公式、非公式に関わらずプラグインが多数あるのと、npmも使えます。<br /> それらの組み合わせで作ることが出来ます。</p> <h3 id="専門知識が必要"><a href="#%E5%B0%82%E9%96%80%E7%9F%A5%E8%AD%98%E3%81%8C%E5%BF%85%E8%A6%81">専門知識が必要</a></h3> <p>一方で、ReactやGraphQL、ES6等の知識が必要です。<br /> フロントエンドエンジニアの方であれば問題ないと思いますが、そうでない場合は少しキャッチアップが必要かもしれません。</p> <p>GatsbyJSを採用したのでホスティングを考えなければなりませんが、GatsbyJSを使うならNetlifyを使うというのがデファクトスタンダードになっています。<br /> なので私も例に漏れずNetlifyを使うことにしました。</p> <h2 id="Netlifyとは"><a href="#Netlify%E3%81%A8%E3%81%AF">Netlifyとは</a></h2> <p><a target="_blank" rel="nofollow noopener" href="https://www.netlify.com/">https://www.netlify.com/</a></p> <p>静的サイトをホスティングしてくれるサービスです。<br /> GitHubやBitbucketのリポジトリと連携するだけで、pushを検知して自動でビルド、デプロイしてくれます。</p> <h2 id="Netlifyの良いところ"><a href="#Netlify%E3%81%AE%E8%89%AF%E3%81%84%E3%81%A8%E3%81%93%E3%82%8D">Netlifyの良いところ</a></h2> <h3 id="無料で独自ドメインを設定できる"><a href="#%E7%84%A1%E6%96%99%E3%81%A7%E7%8B%AC%E8%87%AA%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%A7%E3%81%8D%E3%82%8B">無料で独自ドメインを設定できる</a></h3> <p>基本的には<code>.netlify.com</code>のサブドメインが設定されますが、独自ドメインを持っていればそれを無料で設定できます。</p> <h3 id="無料でHTTPSにできる"><a href="#%E7%84%A1%E6%96%99%E3%81%A7HTTPS%E3%81%AB%E3%81%A7%E3%81%8D%E3%82%8B">無料でHTTPSにできる</a></h3> <p><code>.netlify.com</code>のサブドメインであっても、独自ドメインであってもHTTPSにするのは無料で出来ます。</p> <h3 id="デプロイ前にプレビューできる"><a href="#%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E5%89%8D%E3%81%AB%E3%83%97%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BC%E3%81%A7%E3%81%8D%E3%82%8B">デプロイ前にプレビューできる</a></h3> <p>ブランチを切ると自動的にプレビュー用のサイトが自動で作られるので変更内容を公開前に確認できます。</p> <p>悪いところも書こうと思ったんですが思いつかないですね…<br /> 一応、無料だと100GBまでの転送量の制限がありますが、多くても数100MBぐらいしか使わないと思うので全然問題ないかなと思います。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>私はブログを立ち上げるときの条件</p> <ul> <li>WordPress以外</li> <li>独自ドメインが使える</li> <li>Markdownで書ける</li> <li>カスタマイズしやすい</li> </ul> <p>これらを満たすのがGatsbyJSとNetlifyの組み合わせだったので使用しています。</p> <p>同じような条件で検討されている方はGatsbyJSとNetlifyの組み合わせがオススメなので是非試してみてください。</p> mono7555e