问题描述:

Using tools like Webpack we can enable code splitting and only

load our application code asynchronously when required.

Example in the context of a react application with react-router.

Load initial page.

-> go to new route

---> webpack loads in the component file required asynchronous.

Webpack waits until the code is required in order to initiate the request.

My question is, once the base application code load, can we start loading the rest of the code, even before the user initiates the transition to the new route?

My view is that will prevent the user from waiting for the webpack chunk to download.

-> Load initial page

--> user sitting idle or browsing on home page

----> Start loading application code for rest of the application

---> user goes to new route (faster UX because code has already download in the background)

I hope this makes sense

网友答案:

Yes you can achieve this. I will show one of the possible solutions.

Firstly let's create backgroundLoader for queuing required chunks:

const queue = [];
const delay = 1000;

let isWaiting = false;

function requestLoad() {
    if (isWaiting) {
      return;
    }
    if (!queue.length) {
      return;
    }
    const loader = queue.pop();
    isWaiting = true;
    loader(() => {
      setTimeout(() => {
        isWaiting = false;
        requestLoad();
      }, delay)
    });
}

export default (loader) => {
  queue.push(loader);
  requestLoad();
}

This function will load your chunks in background with 1 second delay (you can tweak it - for example start popping queue after for example 5 second or shuffle array of chunks).

Next you must register your require.ensure in queuing function backgroundLoader:

import render from './render'; // not relevant in this example
import backgroundLoader from './backgroundLoader';

let lightTheme = (cb) => {
  require.ensure([], () => {
    cb(require('./themeA.css'));
  }, 'light');
}

let darkTheme = (cb) => {
  require.ensure([], () => {
    cb(require('./themeB.css'));
  }, 'dark');
}

let pinkTheme = (cb) => {
  require.ensure([], () => {
    cb(require('./themeC.css'));
  }, 'pink');
}
backgroundLoader(lightTheme);
backgroundLoader(darkTheme);
backgroundLoader(pinkTheme);

export default (themeName) => { // router simulation
  switch(themeName) {
    case 'light':
      lightTheme(render);
      break;
    case 'dark':
      darkTheme(render);
      break;
    case 'pink':
      pinkTheme(render);
      break;
  }
};

Once you require your chunk in switch statement you pass render function containing resolve function. In backgroundLoader this function will be empty resulting only loading chunk to head of your app.

Full code for this example you can see on WebpackBin (you can check network to see how chunks are loaded in background)

相关阅读:
Top