Skip to content

Latest commit

 

History

History
332 lines (262 loc) · 11.2 KB

README.md

File metadata and controls

332 lines (262 loc) · 11.2 KB

route-resource-preload - Any code can be split

🚀 Focus on improving the first screen loading speed of applications and providing the best user experience, inspiration comes from the preloading of NextJS.

Comparison

Based-on-react.lazy-normal-loading.gif

Based-on-route-resource-preload.gif

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.

Why do you need route-resource-preload ?

Why route-resoure-preload over react.lazy?

  • Support automatic preloading and manual preloading of components to avoid poor component interaction experience due to component rendering delays.
  • Support code-splitting and preloading of non-component
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.

Install

npm install @route-resource-preload/webpack-plugin @route-resource-preload/react

Using in react

Method 1 - Manually To Preload Single Component Based on Dynamic

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>
}

Method 2 - Manually To Preload Multiple Components

  1. 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']
        }
      })
    ]
  },
}
  1. Step 2: Create a Preloader and run
import { Preloader } from '@route-resource-preload/react'

const preloader = new Preloader()

// execute preloading
preloader.run('flagA')

Method 3 - Automatic Preloading.

  1. 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']
        }
      })
    ]
  },
}
  1. Step 2: Dynamic import component and render PreloadLink
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>
  </>
}

API

  • dynamic - Split your component code and load it dynamically

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 with onEnd 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} />
  • Preloader - Manually to preload based on flag

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's publicPath

  • PreloadLink - Automatic the preloading of resources based on flag

<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's publicPath

Plugin

  • Webpack-RouteResourcePreloadPlugin

RouteResourcePreloadPlugin's publicPath is the same as PreloadLink's publicPath

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 -

Others

  • init / inview / hover

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
  • modulePreloadMap Object

{
  "flagA": ["../components/A"],
  // [the-preloading-flag]: ['your project's components path']
}
  • mfPreloadMap Object

{
  "flagMF": ["ling_core/Components"]
  // [the-preloading-flag]: ['your module-federation's components path']
}
  • assetPreloadMap Object

{
  "flagA": ['https://domain.com/xxx.png']
  // [the-preloading-flag]: ['your static assets link'] (image/font/svg/css/js/...)
}

Stargazers

Stargazers repo roster for @AwesomeDevin/route-resource-preload

Forkers

Forkers repo roster for @AwesomeDevin/route-resource-preload