🚀 Focus on improving the first screen loading speed of applications and providing the best user experience, inspiration comes from the preloading of NextJS.
As we can see from the gif, the display time of the loading component is greatly reduced by route-resource-preload
relative to react.lazy
.
Split modules loads as needed
, improving the first screen loading experience of your App.Minimize dynamic component loading time
and providing the best user experience.- Support
automatic the preloading of resources
( JS / Component / Module-Federation / UMD / Svg / Png , Etc) and providing the best user experience. - Support
manually to preload
. - Support lazy-loading、code-splitting and preloading of
non-component
. - Support
typescript
. - Support
React <Suspense>
.
Why route-resoure-preload over react.lazy?
- Support
automatic preloading
andmanual preloading
of components to avoid poor component interaction experience due to component rendering delays. - Support code-splitting and preloading of
non-component
Why route-resource-preload over webpack-prefetch/preload and loadable-components-prefetch/preload?
- Control
when to preload in more detail
- Support preload
Module-Federation
- Support
More types
of resource (image/font/svg/css/js/...) - Support lazy-loading、code-splitting and preloading of
non-component
. - Support
typescript
.
Component | Normal Lazy Load(ms) | Preload (ms) |
---|---|---|
Simple Component (one-resource) | 150 | 1 |
Complex Component (six-resource) | 350 | 10 |
It can be seen from the table that preloading significantly improves the loading speed of components, especially for complex components, the improvement of loading speed is more obvious. This shows that in complex business scenarios,
preloading can significantly improve component loading speed and user experience
.
npm install @route-resource-preload/webpack-plugin @route-resource-preload/react
import { dynamic } from '@route-resource-preload/react'
const Image = dynamic({
loader: () => import('Components'),
loading: (props) => <>loading...</>,
})
const handleClick = () => {
// execute preloading
Image.preload()
}
export default function Main(props){
return <div onClick={handleClick}>
<Image {...props} />
</div>
}
- Step 1: First, you need add
plugin
in your build config.
const RouteResourcePreloadPlugin = require('@route-resource-preload/webpack-plugin')
webpack: {
plugins: {
add: [
new RouteResourcePreloadPlugin({
// [the-preloading-flag]: ['path']
// project's components(modules)
modulePreloadMap: {
"flagA": ["../components/A"]
},
// module-federation's components(modules)
mfPreloadMap: {
"flagMF": ["ling_core/Components"]
},
// static assets (just like js/css/png/jpg/font, etc.)
assetPreloadMap: {
"flagA": ['https://domain.com/xxx.png']
}
})
]
},
}
- Step 2: Create a
Preloader
andrun
import { Preloader } from '@route-resource-preload/react'
const preloader = new Preloader()
// execute preloading
preloader.run('flagA')
- Step 1: First, you need add
plugin
in your build config.
const RouteResourcePreloadPlugin = require('@route-resource-preload/webpack-plugin')
webpack: {
plugins: {
add: [
new RouteResourcePreloadPlugin({
// [the-preloading-flag]: ['path']
// project's components(modules)
modulePreloadMap: {
"flagA": ["../components/A"]
},
// module-federation's components(modules)
mfPreloadMap: {
"flagMF": ["ling_core/Components"]
},
// static assets (just like js/css/png/jpg/font, etc.)
assetPreloadMap: {
"flagA": ['https://domain.com/xxx.png']
}
})
]
},
}
- Step 2:
Dynamic
import component and renderPreloadLink
import { dynamic, PreloadLink } from '@route-resource-preload/react'
// project's component
const ComponentA = dynamic({
loader: ()=>import('../components/A'),
loading: () => <>loading...</>
})
// module-federation's component
const Image = dynamic({
loader: ()=>import('your_lib/Components'),
loading: () => <>loading...</>,
submodule: 'Image' // may be you didn't export default, just like " export { Image, ...Others } " in js.
})
export default function Main(props){
return <>
<PreloadLink flag="flagA" onClick={()=>{
navigate('/A') // navigate comes from react-router-dom, you can custom your code.
}}
>
Preload Component A
</PreloadLink>
<PreloadLink flag="flagMF">
{/* Link comes from react-router-dom, you can custom your code. */}
<Link to="flagMF" >Preload MF</Link>
</PreloadLink>
</>
}
const Modal = dynamic({
loader: () => import('xxx/Modal'),
// loading: () => <>loading...</>,
// suspense: true,
// submodule: 'submodule',
// visible: true,
})
Param | Description | Type | Default Value | necessary |
---|---|---|---|---|
loader | dynamic import module | () => Promise<Record<string, T extends ComponentType>> | - | ✅ |
loading | A spinner for displaying loading state | ComponentType | - | ❌ |
submodule | maybe you didn't export default, you need it | string | - | ❌ |
visible | whether to render immediately after the components in the view are preloaded | boolean | true | ❌ |
suspense | use react <Suspense> for displaying loading state |
boolean | - | ❌ |
dynamic
will return a HOC withonEnd
prop, which will call back after the component is dynamically rendered to adapt to complex and changeable business scenarios, such as custom loading package elements/or computing component rendering time-consuming, etc.
function CommonLoading (props: { moduleName: string }) {
const { moduleName } = props
const [loading, setLoading] = useState(true)
const Com = useMemo(()=>dynamic({ loader: () => import(`${moduleName}`)}),[moduleName])
// custom loading
return <Spin spinning={loading}>
<Com onEnd={()=>{ setLoading(false)}} />
</Spin>
}
<CommonLoading moduleName={moduleName} />
const preload = new Preloader(options)
preload.run('flag') // plugin flag
Param | Description | Type | Default Value | necessary |
---|---|---|---|---|
publicPath | yout server publicPath | string | - | ❌ |
Preloader's
publicPath
is the same as RouteResourcePreloadPlugin'spublicPath
<PreloadLink flag="flagA" >
Preload Component
</PreloadLink>
Props | Description | Type | Default Value | necessary |
---|---|---|---|---|
flag | the preloading flag | string | - | ✅ |
children | children ReactNode | ReactNode | - | ✅ |
action | trigger preload action | string (init / inview / hover) | hover | ❌ |
onClick | PreloadLink click event | () => void | - | ❌ |
className | PreloadLink classname | string | - | ❌ |
publicPath | yout server publicPath | string | - | ❌ |
PreloadLink's
publicPath
is the same as RouteResourcePreloadPlugin'spublicPath
RouteResourcePreloadPlugin's
publicPath
is the same as PreloadLink'spublicPath
new RouteResourcePreloadPlugin({
// [the-preloading-flag]: ['path']
// project's components(modules)
modulePreloadMap: {
"flagA": ["../components/A"]
},
// module-federation's components(modules)
mfPreloadMap: {
"flagMF": ["xxx/Components"]
},
// static assets (just like js/css/png/jpg/font, etc.)
assetPreloadMap: {
"flagA": ['https://domain.com/xxx.png']
}
})
Params | Description | Type | Default Value | necessary |
---|---|---|---|---|
modulePreloadMap | project's components(modules) | modulePreloadMap Object | - | ❌ |
mfPreloadMap | module-federation's components(modules) | mfPreloadMap Object | - | ❌ |
assetPreloadMap | static assets | assetPreloadMap Object | - | ❌ |
publicPath | your server publicPath | string | - | ❌ |
value | Description |
---|---|
init | Trigger preload after PreloadLink rendering |
inview | Trigger preload after PreloadLink in the view |
hover | Trigger preload after your mouse hover in the PreloadLink |
{
"flagA": ["../components/A"],
// [the-preloading-flag]: ['your project's components path']
}
{
"flagMF": ["ling_core/Components"]
// [the-preloading-flag]: ['your module-federation's components path']
}
{
"flagA": ['https://domain.com/xxx.png']
// [the-preloading-flag]: ['your static assets link'] (image/font/svg/css/js/...)
}