|
6 | 6 |
|
7 | 7 | 'use strict';
|
8 | 8 |
|
9 |
| -const {resolve} = require('path'); |
10 |
| -const webpack = require('webpack'); |
11 |
| - |
12 |
| -exports.modifyWebpackConfig = ({config, stage}) => { |
13 |
| - // See https://github.com/FormidableLabs/react-live/issues/5 |
14 |
| - config.plugin('ignore', () => new webpack.IgnorePlugin(/^(xor|props)$/)); |
15 |
| - |
16 |
| - config.merge({ |
17 |
| - resolve: { |
18 |
| - root: resolve(__dirname, './src'), |
19 |
| - extensions: ['', '.js', '.jsx', '.json'], |
20 |
| - }, |
21 |
| - }); |
22 |
| - return config; |
23 |
| -}; |
24 |
| - |
25 |
| -exports.createPages = async ({graphql, boundActionCreators}) => { |
26 |
| - const {createPage, createRedirect} = boundActionCreators; |
27 |
| - |
28 |
| - // Used to detect and prevent duplicate redirects |
29 |
| - const redirectToSlugMap = {}; |
30 |
| - |
31 |
| - const blogTemplate = resolve('./src/templates/blog.js'); |
32 |
| - const communityTemplate = resolve('./src/templates/community.js'); |
33 |
| - const docsTemplate = resolve('./src/templates/docs.js'); |
34 |
| - const tutorialTemplate = resolve('./src/templates/tutorial.js'); |
35 |
| - |
36 |
| - // Redirect /index.html to root. |
37 |
| - createRedirect({ |
38 |
| - fromPath: '/index.html', |
39 |
| - redirectInBrowser: true, |
40 |
| - toPath: '/', |
41 |
| - }); |
42 |
| - |
43 |
| - const allMarkdown = await graphql( |
44 |
| - ` |
45 |
| - { |
46 |
| - allMarkdownRemark(limit: 1000) { |
47 |
| - edges { |
48 |
| - node { |
49 |
| - fields { |
50 |
| - redirect |
51 |
| - slug |
52 |
| - } |
53 |
| - } |
54 |
| - } |
55 |
| - } |
56 |
| - } |
57 |
| - `, |
58 |
| - ); |
59 |
| - |
60 |
| - if (allMarkdown.errors) { |
61 |
| - console.error(allMarkdown.errors); |
62 |
| - |
63 |
| - throw Error(allMarkdown.errors); |
64 |
| - } |
65 |
| - |
66 |
| - allMarkdown.data.allMarkdownRemark.edges.forEach(edge => { |
67 |
| - const slug = edge.node.fields.slug; |
68 |
| - |
69 |
| - if (slug === 'docs/error-decoder.html') { |
70 |
| - // No-op so far as markdown templates go. |
71 |
| - // Error codes are managed by a page in src/pages |
72 |
| - // (which gets created by Gatsby during a separate phase). |
73 |
| - } else if ( |
74 |
| - slug.includes('blog/') || |
75 |
| - slug.includes('community/') || |
76 |
| - slug.includes('contributing/') || |
77 |
| - slug.includes('docs/') || |
78 |
| - slug.includes('tutorial/') || |
79 |
| - slug.includes('warnings/') |
80 |
| - ) { |
81 |
| - let template; |
82 |
| - if (slug.includes('blog/')) { |
83 |
| - template = blogTemplate; |
84 |
| - } else if (slug.includes('community/')) { |
85 |
| - template = communityTemplate; |
86 |
| - } else if ( |
87 |
| - slug.includes('contributing/') || |
88 |
| - slug.includes('docs/') || |
89 |
| - slug.includes('warnings/') |
90 |
| - ) { |
91 |
| - template = docsTemplate; |
92 |
| - } else if (slug.includes('tutorial/')) { |
93 |
| - template = tutorialTemplate; |
94 |
| - } |
95 |
| - |
96 |
| - const createArticlePage = path => |
97 |
| - createPage({ |
98 |
| - path: path, |
99 |
| - component: template, |
100 |
| - context: { |
101 |
| - slug, |
102 |
| - }, |
103 |
| - }); |
104 |
| - |
105 |
| - // Register primary URL. |
106 |
| - createArticlePage(slug); |
107 |
| - |
108 |
| - // Register redirects as well if the markdown specifies them. |
109 |
| - if (edge.node.fields.redirect) { |
110 |
| - let redirect = JSON.parse(edge.node.fields.redirect); |
111 |
| - if (!Array.isArray(redirect)) { |
112 |
| - redirect = [redirect]; |
113 |
| - } |
114 |
| - |
115 |
| - redirect.forEach(fromPath => { |
116 |
| - if (redirectToSlugMap[fromPath] != null) { |
117 |
| - console.error( |
118 |
| - `Duplicate redirect detected from "${fromPath}" to:\n` + |
119 |
| - `* ${redirectToSlugMap[fromPath]}\n` + |
120 |
| - `* ${slug}\n`, |
121 |
| - ); |
122 |
| - process.exit(1); |
123 |
| - } |
124 |
| - |
125 |
| - // A leading "/" is required for redirects to work, |
126 |
| - // But multiple leading "/" will break redirects. |
127 |
| - // For more context see github.com/reactjs/reactjs.org/pull/194 |
128 |
| - const toPath = slug.startsWith('/') ? slug : `/${slug}`; |
129 |
| - |
130 |
| - redirectToSlugMap[fromPath] = slug; |
131 |
| - createRedirect({ |
132 |
| - fromPath: `/${fromPath}`, |
133 |
| - redirectInBrowser: true, |
134 |
| - toPath, |
135 |
| - }); |
136 |
| - }); |
137 |
| - } |
138 |
| - } |
139 |
| - }); |
140 |
| - |
141 |
| - const newestBlogEntry = await graphql( |
142 |
| - ` |
143 |
| - { |
144 |
| - allMarkdownRemark( |
145 |
| - limit: 1 |
146 |
| - filter: {id: {regex: "/blog/"}} |
147 |
| - sort: {fields: [fields___date], order: DESC} |
148 |
| - ) { |
149 |
| - edges { |
150 |
| - node { |
151 |
| - fields { |
152 |
| - slug |
153 |
| - } |
154 |
| - } |
155 |
| - } |
156 |
| - } |
157 |
| - } |
158 |
| - `, |
159 |
| - ); |
160 |
| - const newestBlogNode = newestBlogEntry.data.allMarkdownRemark.edges[0].node; |
161 |
| - |
162 |
| - // Blog landing page should always show the most recent blog entry. |
163 |
| - createRedirect({ |
164 |
| - fromPath: '/blog/', |
165 |
| - redirectInBrowser: true, |
166 |
| - toPath: newestBlogNode.fields.slug, |
167 |
| - }); |
168 |
| -}; |
169 |
| - |
170 |
| -// Parse date information out of blog post filename. |
171 |
| -const BLOG_POST_FILENAME_REGEX = /([0-9]+)\-([0-9]+)\-([0-9]+)\-(.+)\.md$/; |
172 |
| - |
173 |
| -// Add custom fields to MarkdownRemark nodes. |
174 |
| -exports.onCreateNode = ({node, boundActionCreators, getNode}) => { |
175 |
| - const {createNodeField} = boundActionCreators; |
176 |
| - |
177 |
| - switch (node.internal.type) { |
178 |
| - case 'MarkdownRemark': |
179 |
| - const {permalink, redirect_from} = node.frontmatter; |
180 |
| - const {relativePath} = getNode(node.parent); |
181 |
| - |
182 |
| - let slug = permalink; |
183 |
| - |
184 |
| - if (!slug) { |
185 |
| - if (relativePath.includes('blog')) { |
186 |
| - // Blog posts don't have embedded permalinks. |
187 |
| - // Their slugs follow a pattern: /blog/<year>/<month>/<day>/<slug>.html |
188 |
| - // The date portion comes from the file name: <date>-<title>.md |
189 |
| - const match = BLOG_POST_FILENAME_REGEX.exec(relativePath); |
190 |
| - const year = match[1]; |
191 |
| - const month = match[2]; |
192 |
| - const day = match[3]; |
193 |
| - const filename = match[4]; |
194 |
| - |
195 |
| - slug = `/blog/${year}/${month}/${day}/${filename}.html`; |
196 |
| - |
197 |
| - const date = new Date(year, month - 1, day); |
198 |
| - |
199 |
| - // Blog posts are sorted by date and display the date in their header. |
200 |
| - createNodeField({ |
201 |
| - node, |
202 |
| - name: 'date', |
203 |
| - value: date.toJSON(), |
204 |
| - }); |
205 |
| - } |
206 |
| - } |
207 |
| - |
208 |
| - if (!slug) { |
209 |
| - slug = `/${relativePath.replace('.md', '.html')}`; |
210 |
| - |
211 |
| - // This should only happen for the partials in /content/home, |
212 |
| - // But let's log it in case it happens for other files also. |
213 |
| - console.warn( |
214 |
| - `Warning: No slug found for "${relativePath}". Falling back to default "${slug}".`, |
215 |
| - ); |
216 |
| - } |
217 |
| - |
218 |
| - // Used to generate URL to view this content. |
219 |
| - createNodeField({ |
220 |
| - node, |
221 |
| - name: 'slug', |
222 |
| - value: slug, |
223 |
| - }); |
224 |
| - |
225 |
| - // Used to generate a GitHub edit link. |
226 |
| - createNodeField({ |
227 |
| - node, |
228 |
| - name: 'path', |
229 |
| - value: relativePath, |
230 |
| - }); |
231 |
| - |
232 |
| - // Used by createPages() above to register redirects. |
233 |
| - createNodeField({ |
234 |
| - node, |
235 |
| - name: 'redirect', |
236 |
| - value: redirect_from ? JSON.stringify(redirect_from) : '', |
237 |
| - }); |
238 |
| - return; |
239 |
| - } |
240 |
| -}; |
241 |
| - |
242 |
| -exports.onCreatePage = async ({page, boundActionCreators}) => { |
243 |
| - const {createPage} = boundActionCreators; |
244 |
| - |
245 |
| - return new Promise(resolvePromise => { |
246 |
| - // page.matchPath is a special key that's used for matching pages only on the client. |
247 |
| - // Explicitly wire up all error code wildcard matches to redirect to the error code page. |
248 |
| - if (page.path.includes('docs/error-decoder.html')) { |
249 |
| - page.matchPath = 'docs/error-decoder:path?'; |
250 |
| - page.context.slug = 'docs/error-decoder.html'; |
251 |
| - |
252 |
| - createPage(page); |
253 |
| - } |
254 |
| - |
255 |
| - resolvePromise(); |
256 |
| - }); |
257 |
| -}; |
| 9 | +exports.modifyWebpackConfig = require('./gatsby/modifyWebpackConfig'); |
| 10 | +exports.createPages = require('./gatsby/createPages'); |
| 11 | +exports.onCreateNode = require('./gatsby/onCreateNode'); |
| 12 | +exports.onCreatePage = require('./gatsby/onCreatePage'); |
0 commit comments