1
1
import PropTypes from "prop-types" ;
2
- import type {
3
- ComponentClass ,
4
- ComponentType ,
5
- JSX ,
6
- WeakValidationMap
7
- } from "react" ;
8
- import { Component } from "react" ;
2
+ import type { WeakValidationMap , ComponentType , ComponentClass } from "react" ;
3
+ import React from "react" ;
9
4
10
5
declare global {
11
6
interface Window {
12
7
__REACT_ESI__ : { [ s : string ] : object } ;
13
8
}
9
+
10
+ // eslint-disable-next-line @typescript-eslint/no-namespace
11
+ namespace NodeJS {
12
+ interface Process {
13
+ browser ?: boolean ;
14
+ }
15
+ }
14
16
}
15
17
16
18
interface IWithESIProps {
@@ -20,6 +22,31 @@ interface IWithESIProps {
20
22
} ;
21
23
} ;
22
24
}
25
+
26
+ // Prevent bundlers to bundle server.js
27
+ const safeRequireServer = ( ) => {
28
+ try {
29
+ // Necessary for NextJS
30
+ return eval ( "require('react-esi/lib/server')" ) ;
31
+ } catch ( error ) {
32
+ // Necessary for Express and others
33
+ return eval ( "require('./server')" ) ;
34
+ }
35
+ } ;
36
+
37
+ const isClient = ( ) => {
38
+ return (
39
+ ( typeof process !== "undefined" && process ?. browser ) ||
40
+ typeof window !== "undefined"
41
+ ) ;
42
+ } ;
43
+
44
+ const isServer = ( ) => ! isClient ( ) ;
45
+
46
+ interface State {
47
+ childProps : object ;
48
+ initialChildPropsLoaded : boolean ;
49
+ }
23
50
/**
24
51
* Higher Order Component generating a <esi:include> tag server-side,
25
52
* and rendering the wrapped component client-side.
@@ -28,19 +55,19 @@ export default function withESI<P>(
28
55
WrappedComponent : ComponentType < P > ,
29
56
fragmentID : string
30
57
) : ComponentClass < IWithESIProps & P > {
31
- return class WithESI extends Component < P & IWithESIProps > {
58
+ return class WithESI extends React . Component < P & IWithESIProps , State > {
32
59
public static WrappedComponent = WrappedComponent ;
33
60
public static displayName = `WithESI(${
34
61
WrappedComponent . displayName || WrappedComponent . name || "Component"
35
62
} )`;
36
63
public static propTypes = {
37
64
esi : PropTypes . shape ( {
38
- attrs : PropTypes . objectOf ( PropTypes . string ) // extra attributes to add to the <esi:include> tag
39
- } )
65
+ attrs : PropTypes . objectOf ( PropTypes . string ) , // extra attributes to add to the <esi:include> tag
66
+ } ) ,
40
67
} as unknown as WeakValidationMap < IWithESIProps & P > ;
41
- public state = {
68
+ public state : State = {
42
69
childProps : { } ,
43
- initialChildPropsLoaded : true
70
+ initialChildPropsLoaded : true ,
44
71
} ;
45
72
private esi = { } ;
46
73
@@ -50,15 +77,15 @@ export default function withESI<P>(
50
77
this . esi = esi || { } ;
51
78
this . state . childProps = childProps ;
52
79
53
- if ( typeof window === "undefined" ) {
80
+ if ( isServer ( ) ) {
54
81
return ;
55
82
}
56
83
57
84
if ( window . __REACT_ESI__ ?. [ fragmentID ] ) {
58
85
// Inject server-side computed initial props
59
86
this . state . childProps = {
60
87
...window . __REACT_ESI__ [ fragmentID ] ,
61
- ...this . state . childProps
88
+ ...this . state . childProps ,
62
89
} ;
63
90
return ;
64
91
}
@@ -81,21 +108,22 @@ export default function withESI<P>(
81
108
. then ( ( initialProps : object ) =>
82
109
this . setState ( {
83
110
childProps : initialProps ,
84
- initialChildPropsLoaded : true
111
+ initialChildPropsLoaded : true ,
85
112
} )
86
113
) ;
87
114
}
88
115
89
116
public render ( ) {
90
- if ( typeof window !== "undefined" ) {
117
+ if ( isClient ( ) ) {
91
118
return (
92
119
< WrappedComponent
93
120
{ ...( this . state . childProps as JSX . IntrinsicAttributes & P ) }
94
121
/>
95
122
) ;
96
123
}
97
- // Prevent Webpack and other bundlers to ship server.js
98
- const server = eval ( 'require("./server")' ) ;
124
+
125
+ const server = safeRequireServer ( ) ;
126
+
99
127
return server . createIncludeElement ( fragmentID , this . props , this . esi ) ;
100
128
}
101
129
} ;
0 commit comments