作成日:2023-02-01
Gatsby mdを理解してもらうためにgatsby-starter-blogを使いながら解説していきます。
markdownを理解する。
markdownで記事ができる流れと、どこを変更すれば良いのか、その理解を深めて行きます。
Gatsbyでmd記事が作られて行く流れをまず解説していきます。
mdのシンプルなテンプレであるGatsby-starter-blogを使って行きます。
markdownを利用して、記事のページが作成されるまでの流れは、まず、ビルド時にmarkdownからページを生成しているのはgatsby-node.jsということを覚えて置いてください。
これがビルド時に起動し、graphqlからデーターを取得し、ページを作成しています。
具体的な流れは
gatsby-node.jsが実際何をしてしているのか?
//20行
const result = await graphql(`
{
allMarkdownRemark(sort: { frontmatter: { date: ASC } }, limit: 1000) {
nodes {
id
fields {
slug
}
}
}
}
`)
// 41行
const posts = result.data.allMarkdownRemark.nodes
このコードでは、graphqlからデータを取得しpostsに入れています。 ここで取得している物はidとslugになっています。
ブラウザーを開きgraphqlを確認してみます。
gatsby develop
ブラウザーでhttp://localhost:8000/___graphqlにアクセスします。
クエリーは以下の通りです。
query MyQuery {
allMarkdownRemark(sort: { frontmatter: { date: ASC } }, limit: 1000) {
nodes {
id
fields {
slug
}
}
}
}
クエリーの結果はこれが返って来ます。
{
"data": {
"allMarkdownRemark": {
"nodes": [
{
"id": "2074e68e-bdb3-5b8a-a292-44f2f622e6d3",
"fields": {
"slug": "/hello-world/"
}
},
{
"id": "7a3f41a6-12ca-5060-af3d-01e636b95483",
"fields": {
"slug": "/my-second-post/"
}
},
{
"id": "039cb5fe-73d7-5867-8130-bbd79ef7edc0",
"fields": {
"slug": "/new-beginnings/"
}
}
]
}
},
"extensions": {}
}
gatsby-node.jsのpostsに入っている値はブラウザーで確認したものと同じ結果になります。
console.logでも確認してみます。
//41行目
const posts = result.data.allMarkdownRemark.nodes
console.log(posts) //<--追加
以下結果
オブジェクトやら、配列やら違いはありますが、同じ値が返って来ています。
先ほどのpostsのデーターをforEachでループさせ、createPageを実行しています。 つまりここでmarkdownファイルからページの作成を行っています。
//49行目
posts.forEach((post, index) => {
const previousPostId = index === 0 ? null : posts[index - 1].id
const nextPostId = index === posts.length - 1 ? null : posts[index + 1].id
createPage({
path: post.fields.slug,
component: blogPost,
context: {
id: post.id,
previousPostId,
nextPostId,
},
})
})
ページの作成はこのcretePageです。
※注意createPageではmdのデータをまだ取得していません。
createPage({
path: post.fields.slug,
component: blogPost,
context: {
id: post.id,
previousPostId,
nextPostId,
},
})
createPageはページの作成を行っています。色々と書かれていてややこしいです。 createapi公式
これらは何を意味しているのか。
ページのパスを指定している。
実際の値は「/hello-world/」
テンプレートを指定している。
このgatsby-stater-blogではblog-post.jsのことです。
blog-post.jsは記事レイアウト等jsxが書かれています。
idとその他データを渡している。
ここに独自の値も追加できるので必要な物があればここに追加する。
それに伴い、テンプレートも変更が必要になる場合も。
path,componentは理解できるが、idがなぜ必要かというと、
blog-post.jsの方でidでフィルタ―を行い、markdownのデータを取得しているからです。
mdのデータの取得はblog-post.jsがしています。
そのため仮に、contextに記事の内容(HTML)等全部入れるとidが無くてもページの作成ができます。
テンプレファイルであるblog-posts.jsが実際に何をしているのかを解説していきます。 ここでのポイントはblog-post.jsの一番下のpageQueryの部分です。
このテンプレは実際に何をしているのか?順を追って説明します。
markdownを使うにあたってここが最難関だと思っています。
私自身ここの記述が理解できなかったのでgatsbyを諦めようと何度も思いました。
そして、gatsbyの日本語の記事が少なすぎる...
ここでもまたqraphqlが登場します。orz...
上から順に解説していきます。
export const pageQuery = graphql`
query BlogPostBySlug(
$id: String!
$previousPostId: String
$nextPostId: String
)
このexport const pageQuery = graphqlはgraphqlを使う時のテンプレだと理解して頂いても問題ありません。
このpageQuery名は特に指定が無いようなので。
export const ABCD = graphql
としても動きます。変更する必要性もないのでそのままで良いです。
このBlogPostBySlugも名前はなんでも構いません。
一点注意事項としては複数のテンプレを使用する際この名前は被らないようにしてください。被るとエラーが発生します。
BlogPostBySlugの中身に以下の記述があります。
$id: String!
$previousPostId: String
$nextPostId: String
これはgatsby-node.jsの部分でcontextのデータを送った物を受け取るために必要な記述です。
createPage({
path: post.fields.slug,
component: blogPost,
context: {
id: post.id,
previousPostId,
nextPostId,
},
})
graphql内で使うためには$変数名:型
を指定します。
また、この変数名はgatsby-node.jsで指定したものと全く同じ名前で指定してください。
また、大文字小文字の区別もするため変数名はご注意ください。型も大文字小文字に注意してください。
gatsby-node.jsで変数名を指定していますが、その名前を変更する場合はこのようにしてください。
id: post.id,
servalue , //通常こんな感じ
hoge: post.setvalue//hogeにしたい場合
$id: String!
$servalue: String
$hoge:String
次に、ここから下のコードが実際にmdのデータ取得しています。
{
site {
siteMetadata {
title
}
}
markdownRemark(id: { eq: $id }) {
id
excerpt(pruneLength: 160)
html
frontmatter {
title
date(formatString: "MMMM DD, YYYY")
description
}
}
ブラウザーの方で確認してみます。 ブラウザーではこのようなデータを取ることができました。なんの値が取れるのかを確認するためにはブラウザーで確認するのが早いです。
siteMetadataはgatsby-config.jsに記述されています。難しいものはありません。
ようやくmdファイルのデータをここで取ることができます。
markdownRemark(id: { eq: $id }) {
id // id
excerpt(pruneLength: 160)
html //mdの記事の本体
frontmatter {//mdファイルの一番上の部分
title
date(formatString: "MMMM DD, YYYY")
description
}
}
ここでhtmlが出てきました。
このhtmlがmdの中身、HTMLの本体です
forntmatterも結構重要な部分です。
mdファイルの中身一番上に書かれています。
---
title: Hello World
date: "2015-05-01T22:12:03.284Z"
description: "Hello World"
---
このように、この記事独自の情報を入れておくことで可変的に変更が容易になります。
blog-post.jsのpageQueryの部分ラストです。
previous: markdownRemark(id: { eq: $previousPostId }) {
fields {
slug
}
frontmatter {
title
}
}
next: markdownRemark(id: { eq: $nextPostId }) {
fields {
slug
}
frontmatter {
title
}
}
この「previousPostId,nextPostId」値はgatsby-node.jsの変数を確認してみてください。
gatsby-node.jsの変数を確認
posts.forEach((post, index) => {
const previousPostId = index === 0 ? null : posts[index - 1].id
const nextPostId = index === posts.length - 1 ? null : posts[index + 1].id
となっています。つまり現在の記事postsの前後に記事があればその記事のidを渡しています。
変数名の通りですがpreviousPostId=前の記事のIdです。
ここでもpreviousと言う変数名に変換しています。
previous: markdownRemark(id: { eq: $previousPostId }) {//名前をpreviousに変更
fields {
slug//"slug": "/hello-world/"
}
frontmatter {
title//index.mdのtitle: hellow Worldを取得している。
}
}
gatsby-node.jsでcreateNodeFieldというものを使ってgraphqlに値を追加しています。
//70目
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
if (node.internal.type === `MarkdownRemark`) {
const value = createFilePath({ node, getNode })
createNodeField({
name: `slug`,
node,
value,
})
}
}
以上でblog-post.jsのgraphqの部分の説明が終わりました。相当長い...
ここからは実際にデータが取れたのでそのデータを使用してテンプレに流して行きます。
//8行目
const BlogPostTemplate = ({
data: { previous, next, site, markdownRemark: post },
location,
}) => {
return (
graphqlで取得したデータは自動的に第一引数にporpsとして渡されます。
porpsは全てのデータをもっていますが、このテンプレでは不要なのでこのような書き方になっているようです。
このコードを崩すと次のようになります。
const BlogPostTemplate = (props) => {
const previous = props.data.previous
const next = props.data.next
const site = props.data.site
const post = props.data.markdownRemark
const location = props.location
const siteTitle = site.siteMetadata?.title || `Title`
return (
第一引数以外は何もかえって来ないようなので以下のようにしても二つ目以降は何もデータがありません。
引数2は空
const BlogPostTemplate = (props,otherdata) => {
const previous = props.data.previous
const next = props.data.next
//中身がないのでotherdata = {}です。
return (
以下のようにしても何も返って来ません。
const BlogPostTemplate = (props,{data: {site}}) => {
//propsはたくさんデータを持っています。
//siteは二つ目の引数なので= {}です。
return (
あとはただデータを流し込むだけなので難しくありません。
<h1 itemProp="headline">{post.frontmatter.title}</h1>
<p>{post.frontmatter.description}</p>
mdのデータを展開するにはdangerouslySetInnerHTMLを使う必要があります。
<section
dangerouslySetInnerHTML={{ __html: post.html }}
itemProp="articleBody"
/>
post.htmlとはmarkdownRemarkでhtmlと書いたあのhtmlの事です。
markdown記述ではgatsby-node.jsの独自の値をblog-post.jsに渡す事ができます。
//47行目
var customvalue = "kasutamu"//<--追加
if (posts.length > 0) {
posts.forEach((post, index) => {
const previousPostId = index === 0 ? null : posts[index - 1].id
const nextPostId = index === posts.length - 1 ? null : posts[index + 1].id
createPage({
path: post.fields.slug,
component: blogPost,
context: {
id: post.id,
customvalue,//<--追加
previousPostId,
nextPostId,
},
})
})
}
}
const BlogPostTemplate = (props ,others) => {
const previous = props.data.previous
const next = props.data.next
const site = props.data.site
const post = props.data.markdownRemark
const location = props.location
const siteTitle = site.siteMetadata?.title || `Title`
console.log(props.pageContext)
タグ等で複数の値を追加したい場合mdでは以下のように記入します。
---
title: Hello World
date: "2015-05-01T22:12:03.284Z"
description: "Hello World"
tag :
- A
- B
- B
---
ブラウザーでtagが配列で返って来ることを確認できました。
Gatsbyはこの部分が非常に難しい。markdownでただ書きたいだけなのに、それがとんでもなく大変でした。ここをある程度理解できると、プラグイン無しでも実装が可能になる...かもしれない。
markdownが理解できたらmdxを使う事も容易くできます。
graphqlが絡むから難しく感じると思う。これさえ理解できれば後はなんでも応用ができるはずです。
質問があれば、下に記入ください。
質問や、間違いがありましたら、お気軽にどうぞ
※お名前とコメントの内容を入力してください。
※全てこのブログ上に公表されます。
※許可なく管理者によって修正・削除する場合がございます。 詳しくはプライバシーポリシーを参照ください