Skip to content

Commit 2b2315a

Browse files
author
JH
committed
refactor(lib/withESI): improve types, add safeRequireServer, isClient and isServer functions
1 parent 4b470dd commit 2b2315a

File tree

1 file changed

+46
-18
lines changed

1 file changed

+46
-18
lines changed

lib/src/withESI.tsx

+46-18
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
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";
94

105
declare global {
116
interface Window {
127
__REACT_ESI__: { [s: string]: object };
138
}
9+
10+
// eslint-disable-next-line @typescript-eslint/no-namespace
11+
namespace NodeJS {
12+
interface Process {
13+
browser?: boolean;
14+
}
15+
}
1416
}
1517

1618
interface IWithESIProps {
@@ -20,6 +22,31 @@ interface IWithESIProps {
2022
};
2123
};
2224
}
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+
}
2350
/**
2451
* Higher Order Component generating a <esi:include> tag server-side,
2552
* and rendering the wrapped component client-side.
@@ -28,19 +55,19 @@ export default function withESI<P>(
2855
WrappedComponent: ComponentType<P>,
2956
fragmentID: string
3057
): ComponentClass<IWithESIProps & P> {
31-
return class WithESI extends Component<P & IWithESIProps> {
58+
return class WithESI extends React.Component<P & IWithESIProps, State> {
3259
public static WrappedComponent = WrappedComponent;
3360
public static displayName = `WithESI(${
3461
WrappedComponent.displayName || WrappedComponent.name || "Component"
3562
})`;
3663
public static propTypes = {
3764
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+
}),
4067
} as unknown as WeakValidationMap<IWithESIProps & P>;
41-
public state = {
68+
public state: State = {
4269
childProps: {},
43-
initialChildPropsLoaded: true
70+
initialChildPropsLoaded: true,
4471
};
4572
private esi = {};
4673

@@ -50,15 +77,15 @@ export default function withESI<P>(
5077
this.esi = esi || {};
5178
this.state.childProps = childProps;
5279

53-
if (typeof window === "undefined") {
80+
if (isServer()) {
5481
return;
5582
}
5683

5784
if (window.__REACT_ESI__?.[fragmentID]) {
5885
// Inject server-side computed initial props
5986
this.state.childProps = {
6087
...window.__REACT_ESI__[fragmentID],
61-
...this.state.childProps
88+
...this.state.childProps,
6289
};
6390
return;
6491
}
@@ -81,21 +108,22 @@ export default function withESI<P>(
81108
.then((initialProps: object) =>
82109
this.setState({
83110
childProps: initialProps,
84-
initialChildPropsLoaded: true
111+
initialChildPropsLoaded: true,
85112
})
86113
);
87114
}
88115

89116
public render() {
90-
if (typeof window !== "undefined") {
117+
if (isClient()) {
91118
return (
92119
<WrappedComponent
93120
{...(this.state.childProps as JSX.IntrinsicAttributes & P)}
94121
/>
95122
);
96123
}
97-
// Prevent Webpack and other bundlers to ship server.js
98-
const server = eval('require("./server")');
124+
125+
const server = safeRequireServer();
126+
99127
return server.createIncludeElement(fragmentID, this.props, this.esi);
100128
}
101129
};

0 commit comments

Comments
 (0)