Skip to content
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 25 additions & 18 deletions packages/sui-react-initial-props/src/loadPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,17 @@
import {useContext} from 'react'

import InitialPropsContext from './initialPropsContext'
import {
type ClientPageComponent,
type DoneImportingPageCallback,
type ReactRouterTypes,
type WithInitialPropsComponent
} from './types'
import {type ClientPageComponent, type ReactRouterTypes, type WithInitialPropsComponent} from './types'
import withInitialProps from './withInitialProps'

const EMPTY_GET_INITIAL_PROPS = async (): Promise<object> => ({})

interface Logger {
error: (message: string, error: Error) => void
}

const createUniversalPage =
(routeInfo: ReactRouterTypes.RouteInfo) =>
(routeInfo: ReactRouterTypes.RouteInfo, logger?: Logger) =>
async ({default: Page}: {default: ClientPageComponent}) => {
// check if the Page page has a getInitialProps, if not put a resolve with an empty object
Page.getInitialProps = typeof Page.getInitialProps === 'function' ? Page.getInitialProps : EMPTY_GET_INITIAL_PROPS
Expand All @@ -23,13 +22,15 @@ const createUniversalPage =
// let withInitialProps HOC handle client getInitialProps logic
return Promise.resolve(withInitialProps(Page))
}

// SERVER
// Create a component that gets the initialProps from context
// this context has been created on the `ssrWithComponentWithInitialProps`
const ServerPage: WithInitialPropsComponent = (props: object) => {
const {initialProps} = useContext(InitialPropsContext)
return <Page {...props} {...initialProps} />
}

// recover the displayName from the original page
ServerPage.displayName = Page.displayName
// detect if the page has getInitialProps and wrap it with the routeInfo
Expand All @@ -38,18 +39,24 @@ const createUniversalPage =
context: object,
req: IncomingMessage.ServerRequest,
res: IncomingMessage.ClientResponse
) => await Page.getInitialProps({context, routeInfo, req, res})
) => {
try {
return await Page.getInitialProps({context, routeInfo, req, res})
} catch (error) {
const message = 'Error executing getInitialProps on server'

logger?.error?.(message, error as Error)

return {error: error instanceof Error ? error.message : message}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just throw an error so we do not change the previous behavior?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, maybe it's better to log the error and then throw it instead of returning a new object, I'm doing some tests locally before

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed

}
}

// return the component to be used on the server
return ServerPage
}

// TODO: Remove this method on next major as it's using unnecessary contextFactory param
// and unnecesary calling done method instead relying on promises
export default (_: any, importPage: () => Promise<any>) =>
async (routeInfo: ReactRouterTypes.RouteInfo, done: DoneImportingPageCallback) => {
importPage()
.then(createUniversalPage(routeInfo))
.then(Page => {
done(null, Page)
})
}
export default (importPage: () => Promise<any>, logger?: Logger) => async (routeInfo: ReactRouterTypes.RouteInfo) => {
await importPage()

return createUniversalPage(routeInfo, logger)
}