Skip to content

Commit d408672

Browse files
committed
chore: ts-ify gatsby pages configs, remove pathPrefix
1 parent 7a360a7 commit d408672

File tree

7 files changed

+250
-192
lines changed

7 files changed

+250
-192
lines changed

data/createPages/index.js

-167
This file was deleted.

data/createPages/index.ts

+228
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
import path from 'path';
2+
import textile from 'textile-js';
3+
import { identity } from 'lodash';
4+
import { safeFileExists } from './safeFileExists';
5+
import { flattenContentOrderedList, maybeRetrievePartial } from '../transform';
6+
import { postParser } from '../transform/post-parser';
7+
import { htmlParser } from '../html-parser';
8+
import { createLanguagePageVariants } from './createPageVariants';
9+
import { LATEST_ABLY_API_VERSION_STRING } from '../transform/constants';
10+
import { createContentMenuDataFromPage } from './createContentMenuDataFromPage';
11+
import { DEFAULT_LANGUAGE } from './constants';
12+
import { writeRedirectToConfigFile } from './writeRedirectToConfigFile';
13+
import { siteMetadata } from '../../gatsby-config';
14+
import { GatsbyNode } from 'gatsby';
15+
16+
const writeRedirect = writeRedirectToConfigFile('config/nginx-redirects.conf');
17+
const documentTemplate = path.resolve(`src/templates/document.tsx`);
18+
const apiReferenceTemplate = path.resolve(`src/templates/apiReference.tsx`);
19+
20+
interface Edge {
21+
node: {
22+
slug: string;
23+
version?: string;
24+
contentOrderedList: Array<{
25+
data: string;
26+
type: string;
27+
}>;
28+
meta?: {
29+
redirect_from?: string[];
30+
};
31+
};
32+
}
33+
34+
interface DocumentQueryResult {
35+
allError: {
36+
nodes: {
37+
message: string;
38+
}[];
39+
};
40+
allFileHtml: {
41+
edges: {
42+
node: {
43+
slug: string;
44+
contentOrderedList: {
45+
data: string;
46+
type: string;
47+
}[];
48+
meta: {
49+
redirect_from?: string[];
50+
};
51+
};
52+
}[];
53+
};
54+
}
55+
56+
interface ApiReferenceQueryResult {
57+
allFileHtml: {
58+
edges: {
59+
node: {
60+
slug: string;
61+
contentOrderedList: {
62+
data: string;
63+
type: string;
64+
}[];
65+
meta: {
66+
redirect_from?: string[];
67+
};
68+
};
69+
}[];
70+
};
71+
}
72+
73+
export const createPages: GatsbyNode['createPages'] = async ({ graphql, actions: { createPage, createRedirect } }) => {
74+
/**
75+
* It's not ideal to have:
76+
* * the reusable function `documentCreator` defined inline like this
77+
* * so much of `documentCreator` being imperative processing of data
78+
* - but Gatsby throws horrible unrelated errors (from onCreateNode) if
79+
* you try to extract any of this functionality into an independent composable
80+
* and testable function.
81+
*/
82+
83+
// DOCUMENT TEMPLATE
84+
const documentResult = await graphql<DocumentQueryResult>(`
85+
query {
86+
allError {
87+
nodes {
88+
message
89+
}
90+
}
91+
allFileHtml(filter: { articleType: { eq: "document" } }) {
92+
edges {
93+
node {
94+
slug
95+
contentOrderedList {
96+
data
97+
type
98+
}
99+
meta {
100+
redirect_from
101+
}
102+
}
103+
}
104+
}
105+
}
106+
`);
107+
/**
108+
* We could log here, the reason we don't right now is that the error should already have been caught and logged.
109+
* Because Gatsby spawns a bunch of async processes during the onCreateNode step, though, and errors don't prevent
110+
* the onCreateNode processes from continuing, the workaround is to create Error nodes and then quit when we get
111+
* to the next synchronous stage in the Gatsby pipeline if any Error nodes exist.
112+
* It's an awkward solution and an alternative would be welcome, I'm not sure what we would do instead though.
113+
* We could log only during createPages and never during onCreateNode, but then if there's an error that does manage
114+
* to crash Gatsby somehow or the Error Node is broken, we wouldn't see the output.
115+
*
116+
* For context:
117+
* The original ticket here was EDX-21. When I originally detected missing meta descriptions, I wanted to
118+
* console.warn and continue just so editors could see the error. However it was decided that it should be a
119+
* requirement to always have a meta description, so the app had to avoid building while still throwing & logging
120+
* an error when a page didn't have a meta description.
121+
*/
122+
if (documentResult.data?.allError.nodes && documentResult.data.allError.nodes.length > 0) {
123+
process.exit(1);
124+
}
125+
// API REFERENCES TEMPLATE
126+
const apiReferenceResult = await graphql<ApiReferenceQueryResult>(`
127+
query {
128+
allFileHtml(filter: { articleType: { eq: "apiReference" } }) {
129+
edges {
130+
node {
131+
slug
132+
contentOrderedList {
133+
data
134+
type
135+
}
136+
meta {
137+
redirect_from
138+
}
139+
}
140+
}
141+
}
142+
}
143+
`);
144+
145+
const retrievePartialFromGraphQL = maybeRetrievePartial(graphql);
146+
147+
const documentCreator =
148+
(documentTemplate: string) =>
149+
async (edge: Edge): Promise<string> => {
150+
const content = flattenContentOrderedList(
151+
await Promise.all(edge.node.contentOrderedList.map(retrievePartialFromGraphQL)),
152+
)
153+
.map((content: { data: unknown }) => (content.data ? content.data : ''))
154+
.join('\n');
155+
156+
const postParsedContent = postParser(textile(content));
157+
const contentOrderedList = htmlParser(postParsedContent);
158+
const contentMenu = contentOrderedList.map((item) => createContentMenuDataFromPage(item));
159+
const [languages, contentMenuObject] = createLanguagePageVariants(identity, documentTemplate)(
160+
contentOrderedList,
161+
edge.node.slug,
162+
);
163+
164+
contentMenuObject[DEFAULT_LANGUAGE] = contentMenu;
165+
166+
const script = safeFileExists(`static/scripts/${edge.node.slug}.js`);
167+
168+
const pagePath = `/docs/${edge.node.slug}`;
169+
170+
const redirectFromList = edge.node.meta?.redirect_from;
171+
172+
if (redirectFromList) {
173+
redirectFromList.forEach((redirectFrom) => {
174+
const redirectFromUrl = new URL(redirectFrom, siteMetadata.siteUrl);
175+
176+
if (!redirectFromUrl.hash) {
177+
// We need to be prefix aware just like Gatsby's internals so it works
178+
// with nginx redirects
179+
writeRedirect(redirectFrom, pagePath);
180+
}
181+
182+
createRedirect({
183+
fromPath: redirectFrom,
184+
toPath: pagePath,
185+
isPermanent: true,
186+
force: true,
187+
redirectInBrowser: true,
188+
});
189+
});
190+
}
191+
192+
const slug = edge.node.slug;
193+
createPage({
194+
path: pagePath,
195+
component: documentTemplate,
196+
context: {
197+
slug,
198+
version: edge.node.version ?? LATEST_ABLY_API_VERSION_STRING,
199+
language: DEFAULT_LANGUAGE,
200+
languages,
201+
contentOrderedList,
202+
contentMenu: contentMenuObject,
203+
script,
204+
},
205+
});
206+
return slug;
207+
};
208+
209+
createRedirect({
210+
fromPath: '/',
211+
toPath: '/docs',
212+
isPermanent: true,
213+
redirectInBrowser: true,
214+
});
215+
216+
if (!documentResult.data) {
217+
throw new Error('Document result is undefined');
218+
}
219+
220+
if (!apiReferenceResult.data) {
221+
throw new Error('API reference result is undefined');
222+
}
223+
224+
await Promise.all([
225+
...documentResult.data.allFileHtml.edges.map(documentCreator(documentTemplate)),
226+
...apiReferenceResult.data.allFileHtml.edges.map(documentCreator(apiReferenceTemplate)),
227+
]);
228+
};

0 commit comments

Comments
 (0)