tag:crieit.net,2005:https://crieit.net/tags/JAMStack/feed 「JAMStack」の記事 - Crieit Crieitでタグ「JAMStack」に投稿された最近の記事 2021-08-29T00:49:34+09:00 https://crieit.net/tags/JAMStack/feed 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