Skip to content

Commit

Permalink
syncLoader
Browse files Browse the repository at this point in the history
  • Loading branch information
Tobbe committed Mar 18, 2023
1 parent 08e820c commit 52b6166
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ describe('page auto loader correctly imports pages', () => {
delete process.env.RWJS_CWD
})

test('Pages are automatically imported', () => {
test('Pages get both a loader and a syncLoader', () => {
expect(result?.code).toContain(`const HomePage = {
name: "HomePage",
loader: () => import("`)
loader: () => import("./pages/HomePage/HomePage"),
syncLoader: () => __webpack_require__("`)
})

test('Already imported pages are left alone.', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ export default function (
// with declarations like these:
// const HomePage = {
// name: "HomePage",
// loader: () => require("./pages/HomePage/HomePage")
// loader: () => import("./pages/HomePage/HomePage")
// syncLoader: () => require("./pages/HomePage/HomePage")
// };
// This is to make sure that all the imported "Page modules" are normal
// imports and not asynchronous ones.
Expand Down Expand Up @@ -114,7 +115,11 @@ export default function (
const nodes = []
// Prepend all imports to the top of the file
for (const { importName, relativeImport } of pages) {
// + const <importName> = { name: <importName>, loader: () => import(<relativeImportPath>) }
// + const <importName> = {
// name: <importName>,
// loader: () => import(<relativeImportPath>)
// syncLoader: () => require(<relativeImportPath>)
// }

nodes.push(
t.variableDeclaration('const', [
Expand All @@ -125,16 +130,28 @@ export default function (
t.identifier('name'),
t.stringLiteral(importName)
),
// loader for dynamic imports (browser)
t.objectProperty(
t.identifier('loader'),
t.arrowFunctionExpression(
[],
t.callExpression(t.identifier('import'), [
t.stringLiteral(relativeImport),
])
)
),
// syncLoader for ssr/prerender and first load of
// prerendered pages in browser (csr)
t.objectProperty(
t.identifier('syncLoader'),
t.arrowFunctionExpression(
[],
t.callExpression(
// If useStaticImports, do a synchronous import with require (ssr/prerender)
// otherwise do a dynamic import (browser)
useStaticImports
? t.identifier('require')
: t.identifier('import'),
t.identifier(
// Use __webpack_require__ otherwise all pages will
// be bundled
useStaticImports ? 'require' : '__webpack_require__'
),
[t.stringLiteral(relativeImport)]
)
)
Expand Down
34 changes: 18 additions & 16 deletions packages/router/src/active-route-loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@ import { ParamsProvider, useLocation } from '.'

const DEFAULT_PAGE_LOADING_DELAY = 1000 // milliseconds

type LoadedLoaderSpec = { default: React.ComponentType<unknown> }

interface Props {
path: string
spec: Spec
prerender?: boolean
delay?: number
params?: Record<string, string>
whileLoadingPage?: () => React.ReactElement | null
Expand All @@ -36,6 +35,7 @@ const ArlWhileLoadingNullPage = () => null
export const ActiveRouteLoader = ({
path,
spec,
prerender,
delay,
params,
whileLoadingPage,
Expand All @@ -46,9 +46,16 @@ export const ActiveRouteLoader = ({
const loadingTimeout = useRef<NodeJS.Timeout>()
const announcementRef = useRef<HTMLDivElement>(null)
const waitingFor = useRef<string>('')

const [loadingState, setLoadingState] = useState<LoadingStateRecord>({
[path]: { page: ArlNullPage, specName: '', state: 'PRE_SHOW', location },
[path]: {
page: prerender ? spec.syncLoader().default : ArlNullPage,
specName: '',
state: 'DONE',
location,
},
})

const [renderedChildren, setRenderedChildren] = useState<
React.ReactNode | undefined
>(children)
Expand Down Expand Up @@ -184,10 +191,7 @@ export const ActiveRouteLoader = ({
let renderedLoadingState = loadingState

if (globalThis.__REDWOOD__PRERENDERING) {
// babel auto-loader plugin uses withStaticImport in prerender mode
// override the types for this condition
const PageFromLoader = (spec.loader() as unknown as LoadedLoaderSpec)
.default
const PageFromLoader = spec.syncLoader().default

renderedLoadingState = {
[path]: {
Expand All @@ -204,13 +208,11 @@ export const ActiveRouteLoader = ({
path={renderedPath}
location={loadingState[renderedPath]?.location}
>
<PageLoadingContextProvider
value={{
loading: loadingState[renderedPath]?.state === 'SHOW_LOADING',
}}
>
<ActivePageContextProvider
value={{ loadingState: renderedLoadingState }}
<ActivePageContextProvider value={{ loadingState: renderedLoadingState }}>
<PageLoadingContextProvider
value={{
loading: loadingState[renderedPath]?.state === 'SHOW_LOADING',
}}
>
{renderedChildren}
{renderedLoadingState[path]?.state === 'DONE' && (
Expand All @@ -233,8 +235,8 @@ export const ActiveRouteLoader = ({
ref={announcementRef}
></div>
)}
</ActivePageContextProvider>
</PageLoadingContextProvider>
</PageLoadingContextProvider>
</ActivePageContextProvider>
</ParamsProvider>
)
}
17 changes: 10 additions & 7 deletions packages/router/src/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,11 +206,8 @@ const LocationAwareRouter: React.FC<RouterProps> = ({
)
}

const { root, activeRoute, NotFoundPage } = analyzeRouterTree(
children,
location.pathname,
paramTypes
)
const { root, activeRoute, NotFoundPage, notFoundPrerendered } =
analyzeRouterTree(children, location.pathname, paramTypes)

if (!activeRoute) {
if (NotFoundPage) {
Expand All @@ -219,6 +216,7 @@ const LocationAwareRouter: React.FC<RouterProps> = ({
<ParamsProvider>
<ActiveRouteLoader
spec={normalizePage(NotFoundPage)}
prerender={notFoundPrerendered}
delay={pageLoadingDelay}
path={location.pathname}
/>
Expand All @@ -230,7 +228,8 @@ const LocationAwareRouter: React.FC<RouterProps> = ({
return null
}

const { path, page, name, redirect, whileLoadingPage } = activeRoute.props
const { path, page, name, redirect, whileLoadingPage, prerender } =
activeRoute.props

if (!path) {
throw new Error(`Route "${name}" needs to specify a path`)
Expand All @@ -254,6 +253,7 @@ const LocationAwareRouter: React.FC<RouterProps> = ({
<ActiveRouteLoader
path={path}
spec={normalizePage(page)}
prerender={prerender}
delay={pageLoadingDelay}
params={allParams}
whileLoadingPage={whileLoadingPage}
Expand Down Expand Up @@ -284,8 +284,10 @@ function analyzeRouterTree(
root: React.ReactElement | undefined
activeRoute: React.ReactElement<InternalRouteProps> | undefined
NotFoundPage: PageType | undefined
notFoundPrerendered: boolean | undefined
} {
let NotFoundPage: PageType | undefined = undefined
let notFoundPrerendered: boolean | undefined = undefined
let activeRoute: React.ReactElement | undefined = undefined

function isActiveRoute(route: React.ReactElement<InternalRouteProps>) {
Expand Down Expand Up @@ -313,6 +315,7 @@ function analyzeRouterTree(
if (isRoute(child)) {
if (child.props.notfound && child.props.page) {
NotFoundPage = child.props.page
notFoundPrerendered = child.props.prerender
}

// We have a <Route ...> element, let's check if it's the one we should
Expand Down Expand Up @@ -351,7 +354,7 @@ function analyzeRouterTree(

const root = analyzeRouterTreeInternal(children)

return { root, activeRoute, NotFoundPage }
return { root, activeRoute, NotFoundPage, notFoundPrerendered }
}

export { Router, Route, namedRoutes as routes, isRoute, PageType }
2 changes: 2 additions & 0 deletions packages/router/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ export function flattenSearchParams(
export interface Spec {
name: string
loader: () => Promise<{ default: React.ComponentType<unknown> }>
syncLoader: () => { default: React.ComponentType<unknown> }
}

export function isSpec(
Expand Down Expand Up @@ -363,6 +364,7 @@ export function normalizePage(
return {
name: specOrPage.name,
loader: async () => ({ default: specOrPage }),
syncLoader: () => ({ default: specOrPage }),
}
}

Expand Down
10 changes: 8 additions & 2 deletions packages/web/src/components/createCell.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ComponentProps, JSXElementConstructor } from 'react'
import { ComponentProps, JSXElementConstructor, Suspense } from 'react'

import type { DocumentNode } from 'graphql'
import type { A } from 'ts-toolbelt'
Expand Down Expand Up @@ -391,5 +391,11 @@ export function createCell<

NamedCell.displayName = displayName

return NamedCell
return (props: CellProps) => {
return (
<Suspense fallback={<div>Loading suspense...</div>}>
<NamedCell {...props} />
</Suspense>
)
}
}

0 comments on commit 52b6166

Please sign in to comment.