Skip to content

Commit

Permalink
Merge pull request #16 from rambler-digital-solutions/fix-preload
Browse files Browse the repository at this point in the history
fix: don't use react lazy after preloading the component
  • Loading branch information
andrepolischuk authored Dec 14, 2023
2 parents ba64dc9 + 56e04f8 commit 5563aea
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 16 deletions.
4 changes: 2 additions & 2 deletions .size-limit.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
[
{
"path": "dist/client/index.js",
"limit": "7.1 KB"
"limit": "7.15 KB"
},
{
"path": "dist/server/index.js",
"limit": "7.1 KB"
"limit": "7.05 KB"
}
]
4 changes: 2 additions & 2 deletions src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export type GetMetaData = Loader<MetaData, {data: InitialData}>
* ```
*/

/** Page component */
export type PageComponent<P = any> = React.ComponentType<
P & {isLoading: boolean}
> & {
Expand All @@ -86,8 +87,7 @@ export type PageComponent<P = any> = React.ComponentType<
}

/** Lazy page component */
export interface LazyPageComponent<P = any>
extends React.LazyExoticComponent<PageComponent<P>> {
export type LazyPageComponent<P = any> = PageComponent<P> & {
preload: Loader<void>
getMetaData: GetMetaData
getInitialData: GetInitialData
Expand Down
39 changes: 27 additions & 12 deletions src/components/lazy.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {lazy as reactLazy} from 'react'
import React, {lazy as reactLazy} from 'react'
import type {
Context,
PageComponent,
Expand All @@ -8,9 +8,14 @@ import type {
InitialData
} from '../common/types'

/** Component factory */
/** Page component factory */
export interface ComponentModule {
default: PageComponent
}

/** Page component factory */
export interface ComponentFactory {
(): Promise<{default: PageComponent}>
(): Promise<ComponentModule>
}

/** Data factory */
Expand All @@ -32,12 +37,16 @@ export interface DataFactory<T, C = any> {
* ```
*/
export const lazy = (componentFactory: ComponentFactory): LazyPageComponent => {
let promise: ReturnType<ComponentFactory>
let componentModule: ComponentModule
let componentPromise: ReturnType<ComponentFactory>

const onceFactory: ComponentFactory = () => {
promise ??= componentFactory()
const onceFactory: ComponentFactory = async () => {
if (!componentModule) {
componentPromise ??= componentFactory()
componentModule = await componentPromise
}

return promise
return componentModule
}

function loaderFactory<T, C = any>(
Expand All @@ -50,17 +59,23 @@ export const lazy = (componentFactory: ComponentFactory): LazyPageComponent => {
}
}

const Component = reactLazy(onceFactory) as LazyPageComponent
const ReactLazy = reactLazy(onceFactory)

const Lazy: LazyPageComponent = (props) => {
const Component = componentModule?.default ?? ReactLazy

return <Component {...props} />
}

Component.getMetaData = loaderFactory<MetaData, {data: InitialData}>(
Lazy.getMetaData = loaderFactory<MetaData, {data: InitialData}>(
({getMetaData}, context) => getMetaData?.(context)
)

Component.getInitialData = loaderFactory<InitialData>(
Lazy.getInitialData = loaderFactory<InitialData>(
({getInitialData}, context) => getInitialData?.(context)
)

Component.preload = loaderFactory<void>()
Lazy.preload = loaderFactory<void>()

return Component
return Lazy
}

0 comments on commit 5563aea

Please sign in to comment.