Skip to content

Commit 56a44ae

Browse files
committed
Client: Add structured storage to SSR
1 parent b66b5f3 commit 56a44ae

File tree

3 files changed

+56
-13
lines changed

3 files changed

+56
-13
lines changed

client/src/utils/postprocess/misc.ts

+17-3
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,30 @@
1-
import { createMemoryHistory, createBrowserHistory } from "history";
1+
import {
2+
createMemoryHistory,
3+
createBrowserHistory,
4+
History
5+
}
6+
from "history";
27

38
export const isServer = (): boolean => {
49
return typeof window === "undefined";
510
}
611

712
// https://stackoverflow.com/a/51511967/12005425
8-
// eslint-disable-next-line
9-
export const getHistory = (url = "/") => {
13+
export const getHistory = (url = "/"): History<unknown> => {
1014
const history = isServer() ?
1115
createMemoryHistory({
1216
initialEntries: [url]
1317
}) : createBrowserHistory();
1418

1519
return history;
1620
}
21+
22+
type PromiseCallback = () => void;
23+
24+
export class CallbackWrapper {
25+
constructor(readonly callback: PromiseCallback) {
26+
}
27+
readonly invoke = (): void => {
28+
this.callback();
29+
}
30+
}

client/src/utils/postprocess/postProcess.ts

+1-10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as fs from "fs";
22
import * as path from "path";
33
import { promisify } from "util";
44
import { webpack } from "webpack";
5+
import { CallbackWrapper } from "./misc"
56
import { postProcess as postProcessSSR } from "./postProcessSSR";
67
import { postProcess as postProcessCSS } from "./postProcessCSS";
78

@@ -39,16 +40,6 @@ export async function postProcess(): Promise<void> {
3940
const webpackConfig = require("../../../webpack.config.ssr.js");
4041
const compiler = webpack({...webpackConfig, entry: tp[1]});
4142

42-
type PromiseCallback = () => void;
43-
44-
class CallbackWrapper {
45-
constructor(readonly callback: PromiseCallback) {
46-
}
47-
readonly invoke = (): void => {
48-
this.callback();
49-
}
50-
}
51-
5243
let cbWrapper: CallbackWrapper|undefined;
5344
const waitForCompiler = new Promise<void>((resolve) => { cbWrapper = new CallbackWrapper(resolve)});
5445

client/src/utils/postprocess/postProcessSSR.ts

+38
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import * as fs from "fs";
22
import * as path from "path";
33
import { promisify } from "util";
4+
import { JSDOM } from "jsdom";
5+
import { CallbackWrapper } from "./misc"
46

57
export async function postProcess(workDir: string, filePattern: string): Promise<void> {
68
const readdir = promisify(fs.readdir);
@@ -15,6 +17,7 @@ export async function postProcess(workDir: string, filePattern: string): Promise
1517
}
1618

1719
await postProcessBody(workDir, htmlFiles[0], txtFiles[0]);
20+
await postProcessHeader(workDir, htmlFiles[0]);
1821
}
1922

2023
async function postProcessBody(workDir: string, htmlFile: string, ssrFile: string): Promise<void> {
@@ -41,5 +44,40 @@ async function postProcessBody(workDir: string, htmlFile: string, ssrFile: strin
4144
console.error(`Failed to write to file ${htmlFilePath}, error: ${err}`)
4245
});
4346
out.forEach(str => { stream.write(str); });
47+
4448
stream.end();
49+
50+
let cbWrapper: CallbackWrapper|undefined;
51+
const waitForBufferFlush = new Promise<void>((resolve) => { cbWrapper = new CallbackWrapper(resolve); });
52+
53+
stream.on("close", function() {
54+
cbWrapper?.invoke();
55+
});
56+
57+
await waitForBufferFlush;
58+
}
59+
60+
async function postProcessHeader(workDir: string, htmlFile: string): Promise<void> {
61+
const htmlFilePath = path.join(workDir, htmlFile);
62+
const jsdom = await JSDOM.fromFile(htmlFilePath);
63+
64+
if (!jsdom) {
65+
throw "JSDOM creation failure";
66+
}
67+
68+
const writeFile = promisify(fs.writeFile);
69+
const hdr: HTMLHeadElement = jsdom.window.document.head;
70+
const script = jsdom.window.document.createElement("script");
71+
const structuredData = `{
72+
"@context": "https://schema.org",
73+
"@type": "WebPage",
74+
"datePublished": "${new Date().toISOString().split("T")[0]}",
75+
}`;
76+
77+
script.setAttribute("type", "application/ld+json");
78+
script.textContent = structuredData;
79+
hdr.appendChild(script);
80+
await writeFile(htmlFilePath, jsdom.serialize());
4581
}
82+
83+

0 commit comments

Comments
 (0)