-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgatsby-node.ts
167 lines (154 loc) · 6.73 KB
/
gatsby-node.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import type {GatsbyNode} from "gatsby"
import fs from "fs";
import {IGatsbyResolverContext} from "gatsby/dist/schema/type-definitions";
import path from "path"
import readingTime from "reading-time"
export const createPages: GatsbyNode["createPages"] = async ({actions, graphql}) => {
const {createPage, createRedirect} = actions
// /src/posts/*.mdx 파일만 포스트 페이지를 생성한다.
// /src/pages/blog/{mdx.frontmatter__slug}.mdx 파일시스템 API 사용시
// /src/pages/design-guide.mdx 등 다른 경로의 파일도 모두 포스트 페이지로 생성하는 문제가 있음.
// 참고: https://www.gatsbyjs.com/docs/how-to/routing/mdx/#create-pages-from-sourced-mdx-files
const {data} = await graphql<Queries.CreatePostPagesQuery>(`
query CreatePostPages {
allMdx(
filter: {fields: {sourceInstanceName: {eq: "posts"}}}
sort: {frontmatter: {order: ASC}}
) {
group(field: {frontmatter: {subject: {slug: SELECT}}}) {
edges {
node {
id
# 그룹 경계를 넘은 포스트 내부 네비게이션을 위해 next/previous용 정보도 필요
frontmatter {
subject {
slug
title
}
slug
title
}
internal {
contentFilePath
}
}
}
}
}
}
`)
const edges = data?.allMdx.group.flatMap(group => group.edges) || []
edges.forEach((edge, i) => {
const node = edge.node
createPage({
path: `/blog/${node.frontmatter.slug}`,
// __contentFilePath로 지정한 mdx 본문이 템플릿 페이지 안의 children으로 전달됨.
component: `${path.resolve(`src/templates/post.tsx`)}?__contentFilePath=${node.internal.contentFilePath}`,
context: {
id: node.id,
previous: i > 0 ? edges[i - 1].node : undefined,
next: i < edges.length - 1 ? edges[i + 1].node : undefined,
},
// https://www.gatsbyjs.com/docs/creating-and-modifying-pages/#optimizing-pages-for-content-sync
ownerNodeId: node.id,
})
})
// Redirects 설정
createRedirect({
fromPath: `/`,
toPath: `/blog`,
// isPermanent: false,
})
}
export const onCreateNode: GatsbyNode["onCreateNode"] = ({node, actions, createNodeId, getNode}) => {
const {createNodeField, createNode, createParentChildLink} = actions
if (node.internal.type === `Mdx`) {
// MDX Subset 만들기
// 참고: https://github.com/gatsbyjs/gatsby/discussions/34881
// const fileNode = getNode(node.parent!);
// if (fileNode && fileNode.sourceInstanceName === "posts") {
// const nodeType = 'PostMdx'
// createNode({
// ...node,
// id: createNodeId(`${nodeType}${node.id}`),
// internal: {
// type: nodeType,
// // todo need createContentDigest ?
// contentDigest: node.internal.contentDigest,
// },
// })
// createParentChildLink({
// parent: fileNode,
// child: node,
// });
// }
createNodeField({
node,
name: `timeToRead`,
value: readingTime(node.body)
})
// File 노드의 sourceInstanceName 정보를 Mdx 노드에 추가한다.
// posts, pages 등 목적에 따른 Mdx를 구분하기 위해.
// @ts-ignore
const {sourceInstanceName} = getNode(node.parent!)
createNodeField({
node,
name: `sourceInstanceName`,
value: sourceInstanceName
})
}
}
// 스키마 명확히 정의하기
// 참고: https://www.gatsbyjs.com/docs/reference/graphql-data-layer/schema-customization/#fixing-field-types
// createSchemaCustomization+createResolvers 예시 https://github.com/gatsbyjs/gatsby/blob/master/examples/using-type-definitions/gatsby-node.js
export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] = ({ actions, schema }) => {
const {createTypes} = actions
// 노트: 문법 도움 및 작성 편의를 위해 SDL 이 아닌 .gql 파일에 작성함.
const typeDefs = fs.readFileSync(`type-defs.gql`, {
encoding: `utf-8`,
})
createTypes(typeDefs)
}
// 참고: https://www.gatsbyjs.com/docs/reference/config-files/gatsby-node/#createResolvers
export const createResolvers: GatsbyNode["createResolvers"] = ({ createResolvers }) => {
const resolvers = {
MdxFrontmatter: {
order: {
type: "Int",
resolve: async (source: Queries.MdxFrontmatter, args: object, context: IGatsbyResolverContext<Queries.MdxFrontmatter, undefined>) => {
// 주제별 포스트 순서값 지정 - SubjectJson 데이터를 기반으로 order 값을 반환한다.
if (!source.subject) {
return null
}
const subject = await context.nodeModel.findOne({
type: 'SubjectJson',
query: {filter: {slug: {eq: source.subject}}}
})
return subject.sort.indexOf(source.slug) + 1 || null
},
},
},
SubjectJson: {
// type @link 지정만으로는 sort, limit 같은 쿼리를 사용할 수 없어서 추가함.
// todo posts 에 sort 기능 넣을수 없나?
posts: {
type: "[Mdx!]!",
resolve: async (source: Queries.SubjectJson, args: object, context: IGatsbyResolverContext<Queries.MdxFrontmatter, undefined>) => {
const {entries} = await context.nodeModel.findAll({
type: 'Mdx',
query: {
filter: {frontmatter: {subject: {slug: {eq: source.slug}}}},
// sort: {frontmatter: {order: ASC}},
sort: {
fields: ["frontmatter.order"],
order: ["ASC"]
},
}
})
return entries
},
}
}
}
createResolvers(resolvers)
}