This repository has been archived by the owner on Apr 7, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
/
with-fork.tsx
93 lines (70 loc) · 2.79 KB
/
with-fork.tsx
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
import * as React from "react";
import NextDocument, { DocumentContext, DocumentProps } from "next/document";
import { fork, serialize, allSettled } from "effector/fork";
import cookies from "next-cookies";
import { domain } from "./domain";
import { PageContext } from "./types";
import { getStartUnits, renderPageWithScope, INITIAL_STATE_KEY } from "./lib";
/* eslint-disable no-console, complexity */
type NextData = DocumentProps["__NEXT_DATA__"];
type InitialStateKey = typeof INITIAL_STATE_KEY;
type InitialState = ReturnType<typeof serialize>;
type ExtendedNextData = NextData & { [key in InitialStateKey]: InitialState };
interface CustomDocumentProps extends DocumentProps {
initialState: InitialState;
__NEXT_DATA__: ExtendedNextData;
}
export interface WithForkConfig {
debug?: boolean;
}
export function withFork({ debug }: WithForkConfig = {}) {
return (Document: typeof NextDocument) =>
class WithForkDocument extends React.Component<CustomDocumentProps> {
static renderDocument = Document.renderDocument;
static headTagsMiddleware = Document.headTagsMiddleware;
static bodyTagsMiddleware = Document.bodyTagsMiddleware;
static htmlPropsMiddleware = Document.htmlPropsMiddleware;
static async getInitialProps(ctx: DocumentContext) {
const originalRenderPage = ctx.renderPage;
const startUnits = getStartUnits(originalRenderPage);
if (debug) console.time("1.Domain forked");
const scope = fork(domain);
if (debug) console.timeEnd("1.Domain forked");
ctx.renderPage = renderPageWithScope(scope, originalRenderPage);
if (debug) console.time("2.All units settled");
if (startUnits.length > 0) {
await Promise.all(
startUnits.map((unit) =>
allSettled<PageContext>(unit, {
scope,
params: {
req: ctx.req!,
res: ctx.res!,
query: ctx.query,
cookies: cookies(ctx),
pathname: ctx.pathname,
},
}),
),
);
}
if (debug) console.timeEnd("2.All units settled");
if (debug) console.time("3.Document.getInitialProps called");
const initialProps = await Document.getInitialProps(ctx);
if (debug) console.timeEnd("3.Document.getInitialProps called");
const initialState = serialize(scope);
if (debug) console.log("4.Received initial state:", initialState);
return {
...initialProps,
initialState,
};
}
constructor(props: CustomDocumentProps) {
super(props);
props.__NEXT_DATA__[INITIAL_STATE_KEY] = props.initialState;
}
render() {
return <Document {...this.props} />;
}
};
}