Skip to content

Commit

Permalink
refactor(lib/withESI): improve types, add safeRequireServer, isClient…
Browse files Browse the repository at this point in the history
… and isServer functions
  • Loading branch information
JH committed Mar 7, 2024
1 parent 4b470dd commit 2b2315a
Showing 1 changed file with 46 additions and 18 deletions.
64 changes: 46 additions & 18 deletions lib/src/withESI.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import PropTypes from "prop-types";
import type {
ComponentClass,
ComponentType,
JSX,
WeakValidationMap
} from "react";
import { Component } from "react";
import type { WeakValidationMap, ComponentType, ComponentClass } from "react";
import React from "react";

declare global {
interface Window {
__REACT_ESI__: { [s: string]: object };
}

// eslint-disable-next-line @typescript-eslint/no-namespace
namespace NodeJS {
interface Process {
browser?: boolean;
}
}
}

interface IWithESIProps {
Expand All @@ -20,6 +22,31 @@ interface IWithESIProps {
};
};
}

// Prevent bundlers to bundle server.js
const safeRequireServer = () => {
try {
// Necessary for NextJS
return eval("require('react-esi/lib/server')");
} catch (error) {
// Necessary for Express and others
return eval("require('./server')");
}
};

const isClient = () => {
return (
(typeof process !== "undefined" && process?.browser) ||
typeof window !== "undefined"
);
};

const isServer = () => !isClient();

interface State {
childProps: object;
initialChildPropsLoaded: boolean;
}
/**
* Higher Order Component generating a <esi:include> tag server-side,
* and rendering the wrapped component client-side.
Expand All @@ -28,19 +55,19 @@ export default function withESI<P>(
WrappedComponent: ComponentType<P>,
fragmentID: string
): ComponentClass<IWithESIProps & P> {
return class WithESI extends Component<P & IWithESIProps> {
return class WithESI extends React.Component<P & IWithESIProps, State> {
public static WrappedComponent = WrappedComponent;
public static displayName = `WithESI(${
WrappedComponent.displayName || WrappedComponent.name || "Component"
})`;
public static propTypes = {
esi: PropTypes.shape({
attrs: PropTypes.objectOf(PropTypes.string) // extra attributes to add to the <esi:include> tag
})
attrs: PropTypes.objectOf(PropTypes.string), // extra attributes to add to the <esi:include> tag
}),
} as unknown as WeakValidationMap<IWithESIProps & P>;
public state = {
public state: State = {
childProps: {},
initialChildPropsLoaded: true
initialChildPropsLoaded: true,
};
private esi = {};

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

if (typeof window === "undefined") {
if (isServer()) {
return;
}

if (window.__REACT_ESI__?.[fragmentID]) {
// Inject server-side computed initial props
this.state.childProps = {
...window.__REACT_ESI__[fragmentID],
...this.state.childProps
...this.state.childProps,
};
return;
}
Expand All @@ -81,21 +108,22 @@ export default function withESI<P>(
.then((initialProps: object) =>
this.setState({
childProps: initialProps,
initialChildPropsLoaded: true
initialChildPropsLoaded: true,
})
);
}

public render() {
if (typeof window !== "undefined") {
if (isClient()) {
return (
<WrappedComponent
{...(this.state.childProps as JSX.IntrinsicAttributes & P)}
/>
);
}
// Prevent Webpack and other bundlers to ship server.js
const server = eval('require("./server")');

const server = safeRequireServer();

return server.createIncludeElement(fragmentID, this.props, this.esi);
}
};
Expand Down

0 comments on commit 2b2315a

Please sign in to comment.