:hourglass_flowing_sand: A higher order component for loading components with promises.

Last update: May 17, 2022

React Loadable

A higher order component for loading components with dynamic imports.

Install

yarn add react-loadable

Example

import Loadable from 'react-loadable';
import Loading from './my-loading-component';

const LoadableComponent = Loadable({
  loader: () => import('./my-component'),
  loading: Loading,
});

export default class App extends React.Component {
  render() {
    return <LoadableComponent/>;
  }
}

Happy Customers:

Users

If your company or project is using React Loadable, please open a PR and add yourself to this list (in alphabetical order please)

Also See:

  • react-loadable-visibility - Building on top of and keeping the same API as react-loadable, this library enables you to load content that is visible on the screen.

  • react-loadable-ssr-addon - Server Side Render add-on for react-loadable. Discover & load automatically dynamically all files dependencies, e.g. splitted chunks, css, etc.



GUIDE

Guide

So you've got your React app, you're bundling it with Webpack, and things are going smooth. But then one day you notice your app's bundle is getting so big that it's slowing things down.

It's time to start code-splitting your app!

A single giant bundle vs multiple smaller bundles

Code-splitting is the process of taking one large bundle containing your entire app, and splitting them up into multiple smaller bundles which contain separate parts of your app.

This might seem difficult to do, but tools like Webpack have this built in, and React Loadable is designed to make it super simple.

Route-based splitting vs. Component-based splitting

A common piece of advice you will see is to break your app into separate routes and load each one asynchronously. This seems to work well enough for many apps– as a user, clicking a link and waiting for a page to load is a familiar experience on the web.

But we can do better than that.

Using most routing tools for React, a route is simply a component. There's nothing particularly special about them (Sorry Ryan and Michael– you're what's special). So what if we optimized for splitting around components instead of routes? What would that get us?

Route vs. component centric code splitting

As it turns out: Quite a lot. There are many more places than just routes where you can pretty easily split apart your app. Modals, tabs, and many more UI components hide content until the user has done something to reveal it.

Example: Maybe your app has a map buried inside of a tab component. Why would you load a massive mapping library for the parent route every time when the user may never go to that tab?

Not to mention all the places where you can defer loading content until higher priority content is finished loading. That component at the bottom of your page which loads a bunch of libraries: Why should that be loaded at the same time as the content at the top?

And because routes are just components, we can still easily code-split at the route level.

Introducing new code-splitting points in your app should be so easy that you don't think twice about it. It should be a matter of changing a few lines of code and everything else should be automated.

Introducing React Loadable

React Loadable is a small library that makes component-centric code splitting incredibly easy in React.

Loadable is a higher-order component (a function that creates a component) which lets you dynamically load any module before rendering it into your app.

Let's imagine two components, one that imports and renders another.

import Bar from './components/Bar';

class Foo extends React.Component {
  render() {
    return <Bar/>;
  }
}

Right now we're depending on Bar being imported synchronously via import, but we don't need it until we go to render it. So why don't we just defer that?

Using a dynamic import (a tc39 proposal currently at Stage 3) we can modify our component to load Bar asynchronously.

class MyComponent extends React.Component {
  state = {
    Bar: null
  };

  componentWillMount() {
    import('./components/Bar').then(Bar => {
      this.setState({ Bar: Bar.default });
    });
  }

  render() {
    let {Bar} = this.state;
    if (!Bar) {
      return <div>Loading...</div>;
    } else {
      return <Bar/>;
    };
  }
}

But that's a whole bunch of work, and it doesn't even handle a bunch of cases. What about when import() fails? What about server-side rendering?

Instead you can use Loadable to abstract away the problem.

import Loadable from 'react-loadable';

const LoadableBar = Loadable({
  loader: () => import('./components/Bar'),
  loading() {
    return <div>Loading...</div>
  }
});

class MyComponent extends React.Component {
  render() {
    return <LoadableBar/>;
  }
}

Automatic code-splitting on import()

When you use import() with Webpack 2+, it will automatically code-split for you with no additional configuration.

This means that you can easily experiment with new code splitting points just by switching to import() and using React Loadable. Figure out what performs best for your app.

Creating a great "Loading..." Component

Rendering a static "Loading..." doesn't communicate enough to the user. You also need to think about error states, timeouts, and making it a nice experience.

function Loading() {
  return <div>Loading...</div>;
}

Loadable({
  loader: () => import('./WillFailToLoad'), // oh no!
  loading: Loading,
});

To make this all nice, your loading component receives a couple different props.

Loading error states

When your loader fails, your loading component will receive an error prop which will be an Error object (otherwise it will be null).

function Loading(props) {
  if (props.error) {
    return <div>Error! <button onClick={ props.retry }>Retry</button></div>;
  } else {
    return <div>Loading...</div>;
  }
}

Avoiding Flash Of Loading Component

Sometimes components load really quickly (<200ms) and the loading screen only quickly flashes on the screen.

A number of user studies have proven that this causes users to perceive things taking longer than they really have. If you don't show anything, users perceive it as being faster.

So your loading component will also get a pastDelay prop which will only be true once the component has taken longer to load than a set delay.

function Loading(props) {
  if (props.error) {
    return <div>Error! <button onClick={ props.retry }>Retry</button></div>;
  } else if (props.pastDelay) {
    return <div>Loading...</div>;
  } else {
    return null;
  }
}

This delay defaults to 200ms but you can also customize the delay in Loadable.

Loadable({
  loader: () => import('./components/Bar'),
  loading: Loading,
  delay: 300, // 0.3 seconds
});

Timing out when the loader is taking too long

Sometimes network connections suck and never resolve or fail, they just hang there forever. This sucks for the user because they won't know if it should always take this long, or if they should try refreshing.

The loading component will receive a timedOut prop which will be set to true when the loader has timed out.

function Loading(props) {
  if (props.error) {
    return <div>Error! <button onClick={ props.retry }>Retry</button></div>;
  } else if (props.timedOut) {
    return <div>Taking a long time... <button onClick={ props.retry }>Retry</button></div>;
  } else if (props.pastDelay) {
    return <div>Loading...</div>;
  } else {
    return null;
  }
}

However, this feature is disabled by default. To turn it on, you can pass a timeout option to Loadable.

Loadable({
  loader: () => import('./components/Bar'),
  loading: Loading,
  timeout: 10000, // 10 seconds
});

Customizing rendering

By default Loadable will render the default export of the returned module. If you want to customize this behavior you can use the render option.

Loadable({
  loader: () => import('./my-component'),
  render(loaded, props) {
    let Component = loaded.namedExport;
    return <Component {...props}/>;
  }
});

Loading multiple resources

Technically you can do whatever you want within loader() as long as it returns a promise and you're able to render something. But writing it out can be a bit annoying.

To make it easier to load multiple resources in parallel, you can use Loadable.Map.

Loadable.Map({
  loader: {
    Bar: () => import('./Bar'),
    i18n: () => fetch('./i18n/bar.json').then(res => res.json()),
  },
  render(loaded, props) {
    let Bar = loaded.Bar.default;
    let i18n = loaded.i18n;
    return <Bar {...props} i18n={i18n}/>;
  },
});

When using Loadable.Map the render() method is required. It will be passed a loaded param which will be an object matching the shape of your loader.

Preloading

As an optimization, you can also decide to preload a component before it gets rendered.

For example, if you need to load a new component when a button gets pressed, you could start preloading the component when the user hovers over the button.

The component created by Loadable exposes a static preload method which does exactly this.

const LoadableBar = Loadable({
  loader: () => import('./Bar'),
  loading: Loading,
});

class MyComponent extends React.Component {
  state = { showBar: false };

  onClick = () => {
    this.setState({ showBar: true });
  };

  onMouseOver = () => {
    LoadableBar.preload();
  };

  render() {
    return (
      <div>
        <button
          onClick={this.onClick}
          onMouseOver={this.onMouseOver}>
          Show Bar
        </button>
        {this.state.showBar && <LoadableBar/>}
      </div>
    )
  }
}



SERVER SIDE RENDERING

Server-Side Rendering

When you go to render all these dynamically loaded components, what you'll get is a whole bunch of loading screens.

This really sucks, but the good news is that React Loadable is designed to make server-side rendering work as if nothing is being loaded dynamically.

Here's our starting server using Express.

import express from 'express';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import App from './components/App';

const app = express();

app.get('/', (req, res) => {
  res.send(`
    <!doctype html>
    <html lang="en">
      <head>...</head>
      <body>
        <div id="app">${ReactDOMServer.renderToString(<App/>)}</div>
        <script src="/dist/main.js"></script>
      </body>
    </html>
  `);
});

app.listen(3000, () => {
  console.log('Running on http://localhost:3000/');
});

Preloading all your loadable components on the server

The first step to rendering the correct content from the server is to make sure that all of your loadable components are already loaded when you go to render them.

To do this, you can use the Loadable.preloadAll method. It returns a promise that will resolve when all your loadable components are ready.

Loadable.preloadAll().then(() => {
  app.listen(3000, () => {
    console.log('Running on http://localhost:3000/');
  });
});

Picking up a server-side rendered app on the client

This is where things get a little bit tricky. So let's prepare ourselves little bit.

In order for us to pick up what was rendered from the server we need to have all the same code that was used to render on the server.

To do this, we first need our loadable components telling us which modules they are rendering.

Declaring which modules are being loaded

There are two options in Loadable and Loadable.Map which are used to tell us which modules our component is trying to load: opts.modules and opts.webpack.

Loadable({
  loader: () => import('./Bar'),
  modules: ['./Bar'],
  webpack: () => [require.resolveWeak('./Bar')],
});

But don't worry too much about these options. React Loadable includes a Babel plugin to add them for you.

Just add the react-loadable/babel plugin to your Babel config:

{
  "plugins": [
    "react-loadable/babel"
  ]
}

Now these options will automatically be provided.

For typescript you can use react-loadable-ts-transformer which is a ts analog of react-loadable/babel plugin.

Finding out which dynamic modules were rendered

Next we need to find out which modules were actually rendered when a request comes in.

For this, there is Loadable.Capture component which can be used to collect all the modules that were rendered.

import Loadable from 'react-loadable';

app.get('/', (req, res) => {
  let modules = [];

  let html = ReactDOMServer.renderToString(
    <Loadable.Capture report={moduleName => modules.push(moduleName)}>
      <App/>
    </Loadable.Capture>
  );

  console.log(modules);

  res.send(`...${html}...`);
});

Mapping loaded modules to bundles

In order to make sure that the client loads all the modules that were rendered server-side, we'll need to map them to the bundles that Webpack created.

This comes in two parts.

First we need Webpack to tell us which bundles each module lives inside. For this there is the React Loadable Webpack plugin.

Import the ReactLoadablePlugin from react-loadable/webpack and include it in your webpack config. Pass it a filename for where to store the JSON data about our bundles.

// webpack.config.js
import { ReactLoadablePlugin } from 'react-loadable/webpack';

export default {
  plugins: [
    new ReactLoadablePlugin({
      filename: './dist/react-loadable.json',
    }),
  ],
};

Then we'll go back to our server and use this data to convert our modules to bundles.

To convert from modules to bundles, import the getBundles method from react-loadable/webpack and the data from Webpack.

import Loadable from 'react-loadable';
import { getBundles } from 'react-loadable/webpack'
import stats from './dist/react-loadable.json';

app.get('/', (req, res) => {
  let modules = [];

  let html = ReactDOMServer.renderToString(
    <Loadable.Capture report={moduleName => modules.push(moduleName)}>
      <App/>
    </Loadable.Capture>
  );

  let bundles = getBundles(stats, modules);

  // ...
});

We can then render these bundles into <script> tags in our HTML.

It is important that the bundles are included before the main bundle, so that they can be loaded by the browser prior to the app rendering.

However, as the Webpack manifest (including the logic for parsing bundles) lives in the main bundle, it will need to be extracted into its own chunk.

This is easy to do with the CommonsChunkPlugin

// webpack.config.js
export default {
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
      minChunks: Infinity
    })
  ]
}

Notice: As of Webpack 4 the CommonsChunkPlugin has been removed and the manifest doesn't need to be extracted anymore.

let bundles = getBundles(stats, modules);

res.send(`
  <!doctype html>
  <html lang="en">
    <head>...</head>
    <body>
      <div id="app">${html}</div>
      <script src="/dist/manifest.js"></script>
      <script src="/dist/main.js"></script>
      ${bundles.map(bundle => {
        return `<script src="/dist/${bundle.file}"></script>`
        // alternatively if you are using publicPath option in webpack config
        // you can use the publicPath value from bundle, e.g:
        // return `<script src="${bundle.publicPath}"></script>`
      }).join('\n')}
      <script>window.main();</script>
    </body>
  </html>
`);

Preloading ready loadable components on the client

We can use the Loadable.preloadReady() method on the client to preload the loadable components that were included on the page.

Like Loadable.preloadAll(), it returns a promise, which on resolution means that we can hydrate our app.

// src/entry.js
import React from 'react';
import ReactDOM from 'react-dom';
import Loadable from 'react-loadable';
import App from './components/App';

window.main = () => {
  Loadable.preloadReady().then(() => {
    ReactDOM.hydrate(<App/>, document.getElementById('app'));
  });
};

Now server-side rendering should work perfectly!



API DOCS

API Docs

Loadable

A higher-order component for dynamically loading a module before rendering it, a loading component is rendered while the module is unavailable.

const LoadableComponent = Loadable({
  loader: () => import('./Bar'),
  loading: Loading,
  delay: 200,
  timeout: 10000,
});

This returns a LoadableComponent.

Loadable.Map

A higher-order component that allows you to load multiple resources in parallel.

Loadable.Map's opts.loader accepts an object of functions, and needs a opts.render method.

Loadable.Map({
  loader: {
    Bar: () => import('./Bar'),
    i18n: () => fetch('./i18n/bar.json').then(res => res.json()),
  },
  render(loaded, props) {
    let Bar = loaded.Bar.default;
    let i18n = loaded.i18n;
    return <Bar {...props} i18n={i18n}/>;
  }
});

When using Loadable.Map the render() method's loaded param will be an object with the same shape as your loader.

Loadable and Loadable.Map Options

opts.loader

A function returning a promise that loads your module.

Loadable({
  loader: () => import('./Bar'),
});

When using with Loadable.Map this accepts an object of these types of functions.

Loadable.Map({
  loader: {
    Bar: () => import('./Bar'),
    i18n: () => fetch('./i18n/bar.json').then(res => res.json()),
  },
});

When using with Loadable.Map you'll also need to pass a opts.render function.

opts.loading

A LoadingComponent that renders while a module is loading or when it errors.

Loadable({
  loading: LoadingComponent,
});

This option is required, if you don't want to render anything, return null.

Loadable({
  loading: () => null,
});

opts.delay

Time to wait (in milliseconds) before passing props.pastDelay to your loading component. This defaults to 200.

Loadable({
  delay: 200
});

Read more about delays.

opts.timeout

Time to wait (in milliseconds) before passing props.timedOut to your loading component. This is turned off by default.

Loadable({
  timeout: 10000
});

Read more about timeouts.

opts.render

A function to customize the rendering of loaded modules.

Receives loaded which is the resolved value of opts.loader and props which are the props passed to the LoadableComponent.

Loadable({
  render(loaded, props) {
    let Component = loaded.default;
    return <Component {...props}/>;
  }
});

opts.webpack

An optional function which returns an array of Webpack module ids which you can get with require.resolveWeak.

Loadable({
  loader: () => import('./Foo'),
  webpack: () => [require.resolveWeak('./Foo')],
});

This option can be automated with the Babel Plugin.

opts.modules

An optional array with module paths for your imports.

Loadable({
  loader: () => import('./my-component'),
  modules: ['./my-component'],
});

This option can be automated with the Babel Plugin.

LoadableComponent

This is the component returned by Loadable and Loadable.Map.

const LoadableComponent = Loadable({
  // ...
});

Props passed to this component will be passed straight through to the dynamically loaded component via opts.render.

LoadableComponent.preload()

This is a static method on LoadableComponent which can be used to load the component ahead of time.

const LoadableComponent = Loadable({...});

LoadableComponent.preload();

This returns a promise, but you should avoid waiting for that promise to resolve to update your UI. In most cases it creates a bad user experience.

Read more about preloading.

LoadingComponent

This is the component you pass to opts.loading.

function LoadingComponent(props) {
  if (props.error) {
    // When the loader has errored
    return <div>Error! <button onClick={ props.retry }>Retry</button></div>;
  } else if (props.timedOut) {
    // When the loader has taken longer than the timeout
    return <div>Taking a long time... <button onClick={ props.retry }>Retry</button></div>;
  } else if (props.pastDelay) {
    // When the loader has taken longer than the delay
    return <div>Loading...</div>;
  } else {
    // When the loader has just started
    return null;
  }
}

Loadable({
  loading: LoadingComponent,
});

Read more about loading components

props.error

An Error object passed to LoadingComponent when the loader has failed. When there is no error, null is passed.

function LoadingComponent(props) {
  if (props.error) {
    return <div>Error!</div>;
  } else {
    return <div>Loading...</div>;
  }
}

Read more about errors.

props.retry

A function prop passed to LoadingComponent when the loader has failed, used to retry loading the component.

function LoadingComponent(props) {
  if (props.error) {
    return <div>Error! <button onClick={ props.retry }>Retry</button></div>;
  } else {
    return <div>Loading...</div>;
  }
}

Read more about errors.

props.timedOut

A boolean prop passed to LoadingComponent after a set timeout.

function LoadingComponent(props) {
  if (props.timedOut) {
    return <div>Taking a long time...</div>;
  } else {
    return <div>Loading...</div>;
  }
}

Read more about timeouts.

props.pastDelay

A boolean prop passed to LoadingComponent after a set delay.

function LoadingComponent(props) {
  if (props.pastDelay) {
    return <div>Loading...</div>;
  } else {
    return null;
  }
}

Read more about delays.

Loadable.preloadAll()

This will call all of the LoadableComponent.preload methods recursively until they are all resolved. Allowing you to preload all of your dynamic modules in environments like the server.

Loadable.preloadAll().then(() => {
  app.listen(3000, () => {
    console.log('Running on http://localhost:3000/');
  });
});

It's important to note that this requires that you declare all of your loadable components when modules are initialized rather than when your app is being rendered.

Good:

// During module initialization...
const LoadableComponent = Loadable({...});

class MyComponent extends React.Component {
  componentDidMount() {
    // ...
  }
}

Bad:

// ...

class MyComponent extends React.Component {
  componentDidMount() {
    // During app render...
    const LoadableComponent = Loadable({...});
  }
}

Note: Loadable.preloadAll() will not work if you have more than one copy of react-loadable in your app.

Read more about preloading on the server.

Loadable.preloadReady()

Check for modules that are already loaded in the browser and call the matching LoadableComponent.preload methods.

Loadable.preloadReady().then(() => {
  ReactDOM.hydrate(<App/>, document.getElementById('app'));
});

Read more about preloading on the client.

Loadable.Capture

A component for reporting which modules were rendered.

Accepts a report prop which is called for every moduleName that is rendered via React Loadable.

let modules = [];

let html = ReactDOMServer.renderToString(
  <Loadable.Capture report={moduleName => modules.push(moduleName)}>
    <App/>
  </Loadable.Capture>
);

console.log(modules);

Read more about capturing rendered modules.

Babel Plugin

Providing opts.webpack and opts.modules for every loadable component is a lot of manual work to remember to do.

Instead you can add the Babel plugin to your config and it will automate it for you:

{
  "plugins": ["react-loadable/babel"]
}

Input

import Loadable from 'react-loadable';

const LoadableMyComponent = Loadable({
  loader: () => import('./MyComponent'),
});

const LoadableComponents = Loadable.Map({
  loader: {
    One: () => import('./One'),
    Two: () => import('./Two'),
  },
});

Output

import Loadable from 'react-loadable';
import path from 'path';

const LoadableMyComponent = Loadable({
  loader: () => import('./MyComponent'),
  webpack: () => [require.resolveWeak('./MyComponent')],
  modules: [path.join(__dirname, './MyComponent')],
});

const LoadableComponents = Loadable.Map({
  loader: {
    One: () => import('./One'),
    Two: () => import('./Two'),
  },
  webpack: () => [require.resolveWeak('./One'), require.resolveWeak('./Two')],
  modules: [path.join(__dirname, './One'), path.join(__dirname, './Two')],
});

Read more about declaring modules.

Webpack Plugin

In order to send the right bundles down when rendering server-side, you'll need the React Loadable Webpack plugin  to provide you with a mapping of modules to bundles.

// webpack.config.js
import { ReactLoadablePlugin } from 'react-loadable/webpack';

export default {
  plugins: [
    new ReactLoadablePlugin({
      filename: './dist/react-loadable.json',
    }),
  ],
};

This will create a file (opts.filename) which you can import to map modules to bundles.

Read more about mapping modules to bundles.

getBundles

A method exported by react-loadable/webpack for converting modules to bundles.

import { getBundles } from 'react-loadable/webpack';

let bundles = getBundles(stats, modules);

Read more about mapping modules to bundles.



FAQ

FAQ

How do I avoid repetition?

Specifying the same loading component or delay every time you use Loadable() gets repetitive fast. Instead you can wrap Loadable with your own Higher-Order Component (HOC) to set default options.

import Loadable from 'react-loadable';
import Loading from './my-loading-component';

export default function MyLoadable(opts) {
  return Loadable(Object.assign({
    loading: Loading,
    delay: 200,
    timeout: 10000,
  }, opts));
};

Then you can just specify a loader when you go to use it.

import MyLoadable from './MyLoadable';

const LoadableMyComponent = MyLoadable({
  loader: () => import('./MyComponent'),
});

export default class App extends React.Component {
  render() {
    return <LoadableMyComponent/>;
  }
}

Unfortunately at the moment using wrapped Loadable breaks react-loadable/babel so in such case you have to add required properties (modules, webpack) manually.

import MyLoadable from './MyLoadable';

const LoadableMyComponent = MyLoadable({
  loader: () => import('./MyComponent'),
  modules: ['./MyComponent'],
  webpack: () => [require.resolveWeak('./MyComponent')],
});

export default class App extends React.Component {
  render() {
    return <LoadableMyComponent/>;
  }
}

How do I handle other styles .css or sourcemaps .map with server-side rendering?

When you call getBundles, it may return file types other than JavaScript depending on your Webpack configuration.

To handle this, you should manually filter down to the file extensions that you care about:

let bundles = getBundles(stats, modules);

let styles = bundles.filter(bundle => bundle.file.endsWith('.css'));
let scripts = bundles.filter(bundle => bundle.file.endsWith('.js'));

res.send(`
  <!doctype html>
  <html lang="en">
    <head>
      ...
      ${styles.map(style => {
        return `<link href="/dist/${style.file}" rel="stylesheet"/>`
      }).join('\n')}
    </head>
    <body>
      <div id="app">${html}</div>
      <script src="/dist/main.js"></script>
      ${scripts.map(script => {
        return `<script src="/dist/${script.file}"></script>`
      }).join('\n')}
    </body>
  </html>
`);

GitHub

https://github.com/jamiebuilds/react-loadable
Comments
  • 1. Add babel-plugin-dynamic-import-node suggestion to README.

    Hello, firstly thanks for making this library and sorry for my english. I had an issue and found a solution but I'm not sure about it. Here is my story;

    After using react-loadable with babel-plugin i'm encounter an issue which causes my first renders on server wont serves loadable component. After some digging i realise webpack splits my code into two chunks (one for main and one for loadable) and tries to load loadable component with promise (with load() function in library). And because server dont waits for this loading completed; my first requests always returns null for loadable-component and others work well.

    I dont know if this issue is common or just because of my webpack configuration, or because im using babel "syntax-dynamic-import" plugin (etc), but after digging for hours i found solution as using babel-plugin-dynamic-import-node plugin for only my server side webpack (babel actually).

    Since issues are disabled i had to open this PR, its okay if you dont accept it. But now it works like a charm! Thanks again :)

    Reviewed by ramesaliyev at 2017-04-20 21:22
  • 2. fix webpack integration

    ❗️ This is actually a much bigger deal than originally thought. Check out this repo for more info. Here's the README (saved you a click):


    This demonstrates a bug in the way that react-loadable intracts with webpack. If you pop open the index.js you'll see it's simply importing react-loadable. Check out the bundle.js file (which is generated by webpack) and you'll see some interesting things in there:

    1. webpackEmptyContext - a module that webpack makes when you do require(somethingDynamic).
    2. require replaced by IIFE that throws

    So, basically, the try/catch there will always result in a throw with an ignored catch.

    Now, if you look at this commit, it uses my branch of react-loadable instead and the problem is fixed. Now:

    1. webpackEmptyContext is replaced by a module polyfill (to account for module.require). This is actually dead code because module.require will never be used when running this with webpack anyway. :shrug:
    2. require is now requireFn which will be assigned to __webpack_require__ when running with webpack and simply module.require when running in node.

    I've verified that my fix works wonderfully in my app. :)


    This uses __webpack_require__ if isWebpack is true and module.require if not. This should work in both node and when bundled with webpack without causing issues.

    Closes #10

    Reviewed by kentcdodds at 2017-03-15 20:57
  • 3. Remove use of componentWillMount

    React 16.9.0 deprecated componentWillMount so it now throws a warning when used.

    As far as I can see this should be a simple swap to componentDidMount

    Reviewed by dr3 at 2019-08-12 13:53
  • 4. [WIP] pass params to loader (based on props)

    Sometimes I've found I need to pass dynamic parameters to the loader, usually based on the props. This is useful because our component server can attach additional data to the component props.

    If you agree with the general idea behind this PR, I'll be happy to polish it by writing tests and docs :)

    Reviewed by debelbot at 2017-11-23 10:17
  • 5. add support for HMR, flushWebpackRequireWeakIds test, new flushRequires method

    This commit is a long time coming. This repo has the comments turned off, so I'm going to take a second to describe the journey to this point:

    Originally my commit here had the code for comprehensive chunk flushing support, but then I realized it made the most sense to follow the Unix philosophy and create another package since the API boundaries were so clean.

    As a result, the following packages handle javascript and css chunk flushing by being passed the requires of react-loadable:

    https://github.com/faceyspacey/webpack-flush-chunks https://github.com/faceyspacey/extract-css-chunks-webpack-plugin

    And here's a new boilerplate putting all 3 of these packages together: https://github.com/faceyspacey/flush-chunks-boilerplate it works now, even without this PR. Give it a try!

    A LOT of work has gone into making those packages and the boilerplate feature-complete, tested and well-documented. This commit would have come several weeks ago, except handling CSS (the creation of multiple css chunk files) and support for css HMR ended up being quite the unanticipated trek. But I think the result is actually a solution that gives competing CSS solutions a run for their money. My notes on the matter are in the extract-css-chunks-webpack-plugin readme.

    In general, every which scenario I could think of has been covered in webpack-flush-chunks and its corresponding boilerplate: babel building, universal webpack bundling, development, production, embedding your chunks as strings or React Components, embedding CSS instead of stylesheets, HMR, sending the smallest amount of CSS over the wire and more. As I said, I originally intended for the webpack-flush-chunks package to be part of React Loadable, but after you added the 2 flushing functions it just made the most sense to keep it separate, so that other packages can rely on it as well.

    If you have the time, I'd love your feedback on the above tools. My hope is for them to become official companion tools to React Loadable for their given purposes.

    ...What was left after I removed the chunk flushing are the following things in this commit:

    • support for HMR by storing the updated component in the closure rather than instance state
    • the missing test for flushWebpackRequireWeakIds()
    • a proposed flushRequires method which provides a clean API to perform module flushing regardless of the environment. It helps make documentation for using webpack-flush-chunks a bit easier to digest.
    • and a wallaby.js file because that's central to my workflow and I'd like to provide any help you need in maintaining this package 💯
    Reviewed by faceyspacey at 2017-04-27 16:28
  • 6. Expose promise to react tree for monitoring

    This makes it possible to use it as a hook in testing.

    I was thinking about adding a component that is exported so that it would be easy to do a enzyme.find(Component), but thought I'd start with the smallest possible change.

    Reviewed by tarjei at 2017-08-01 07:04
  • 7. Transforming Object.assign() with Babel (fix IE11 issue)

    Thanks a lot for this awesome library!

    We detected an issue on IE11, as Babel does not include the polyfill for Object.assign() in its es2015 preset. You need to include yourself the plugin to transform it, so here it is ^^

    Reviewed by PerrineBoissieres at 2017-11-14 16:49
  • 8. Strawman: babel-plugin-transform-react-loadable

    Hey there,

    I made babel-plugin-transform-react-loadable following this random thought I had.

    Weirdly enough, I don't actually have react-loadable set up in any of my projects at the moment. But I hadn't written a Babel plugin in a while, and the idea seemed valid enough, so I figured, what the heck. So this is me sharing it super early, but hopefully in a rather complete state, unless more rigorous testing shows otherwise.

    I welcome any feedback, especially if anyone actually uses the plugin and has anything to report. The actual PR here is fairly minimal and should probably only be merged after it's rewritten and after we have evidence that this works in a real-world project.

    Reviewed by motiz88 at 2017-04-02 18:25
  • 9. Add retry() function to the loading component when import failed

    To improve the user experience, give the user a chance to retry loading the component when the import failed. The loading component receive a retry prop, which is a function to retry the operation.

    const Loading = props => {
      if (props.error) {
        return <div>Error! <button type="button" onClick={ props.retry }>Retry</button></div>;
      } else {
        return <div>Loading...</div>;
      }
    };
    
    Reviewed by sanderdebruijne at 2017-11-08 19:45
  • 10. Add webpackChunkName option and update babel plugin

    This builds on ideas from flushServerSideRequirePaths but focuses on chunks rather than file-system paths.

    By utilizing webpackChunkName alongside a new method flushWebpackChunkNames, you'll be able to generate list of chunks that were included in a server-side render. This can then be used with something like webpack-manifest-plugin to map chunk names to chunk output filenames.

    LoadingComponent.js

    const Page = withLoadable({
      loader: () => import('./MyComponent' /* webpackChunkName: "my-component" */),
    });
    

    server.js

    import { flushWebpackChunkNames } from 'react-loadable';
    
    ...
    const manifest = require('./build/manifest.json');
    const chunks = flushWebpackChunkNames().map(name => `/${name}.js`);
    const scripts = chunks.map(path => manifest[path]);
    
    renderToStaticMarkup(
      <html>
        <head>
          {scripts.map(src => <script src={src} />)}
        </head>
      </html>
    );
    

    It's possible to manually specify the chunk name using the webpackChunkName option as with serverSideRequirePath. The updated babel plugin includes generation of this property based on the comment contents.

    I haven't updated the README yet incase you decide against this new feature or want to change it but I'd be more than happy update that as well.

    Reviewed by simenbrekken at 2017-05-13 09:11
  • 11. Pass props to Loading component

    There are cases when would want to render the loader with the props. This passes the props to the loading component, so can render them in the loader.

    Reviewed by michaltk at 2018-07-02 19:13
  • 12. Add Online Solitaire to Readme

    I run https://online-solitaire.com/, a website where more than 4 million solitaire games are played each month. I make pretty heavy use of react-loadable to speed up the site, so I thought it might be a nice example in the users list.

    Reviewed by holgersindbaek at 2022-02-21 09:38
  • 13. Add Wave Digital to the list of users

    First, thanks for this awesome library. We have been using it for all of our projects that require SSR and Code Splitting.

    Can our company Wave Digital be added to the list of users ?

    Thanks and happy new year from Australia.

    Reviewed by t49tran at 2020-12-23 03:55
  • 14. Bump handlebars from 4.0.11 to 4.7.6

    Bumps handlebars from 4.0.11 to 4.7.6.

    Changelog

    Sourced from handlebars's changelog.

    v4.7.6 - April 3rd, 2020

    Chore/Housekeeping:

    Compatibility notes:

    • Restored Node.js compatibility

    Commits

    v4.7.5 - April 2nd, 2020

    Chore/Housekeeping:

    • Node.js version support has been changed to v6+ Reverted in 4.7.6

    Compatibility notes:

    • Node.js < v6 is no longer supported Reverted in 4.7.6

    Commits

    v4.7.4 - April 1st, 2020

    Chore/Housekeeping:

    Compatibility notes:

    • No incompatibilities are to be expected

    Commits

    v4.7.3 - February 5th, 2020

    Chore/Housekeeping:

    • #1644 - Download links to aws broken on handlebarsjs.com - access denied (@Tea56)
    • Fix spelling and punctuation in changelog - d78cc73

    Bugfixes:

    • Add Type Definition for Handlebars.VERSION, Fixes #1647 - 4de51fe
    • Include Type Definition for runtime.js in Package - a32d05f

    Compatibility notes:

    Commits
    Maintainer changes

    This version was pushed to npm by erisds, a new releaser for handlebars since your current version.


    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    Reviewed by dependabot[bot] at 2020-09-04 18:05
Component to build simple, flexible, and accessible toggle components
Component to build simple, flexible, and accessible toggle components

react-toggled ⚛️ Component to build simple, flexible, and accessible toggle components The problem You want a toggle component that's simple and gives

Mar 15, 2022
Tweak React components in real time. (Deprecated: use Fast Refresh instead.)

React Hot Loader Tweak React components in real time ⚛️ ⚡️ Watch Dan Abramov's talk on Hot Reloading with Time Travel. Moving towards next step React-

May 11, 2022
📑 CLI tool for creating demos of React components
📑  CLI tool for creating demos of React components

React DemoTab CLI ?? Easily create demos of React components Maintaining example code and demo separately makes it painful, it's easy to get them out

May 10, 2022
An isolated development space with integrated fuzz testing for your components. See them individually, explore them in different states and quickly and confidently develop them.
An isolated development space with integrated fuzz testing for your components. See them individually, explore them in different states and quickly and confidently develop them.

Carte Blanche IMPORTANT: This project is unfinished and not maintained. Do not try to use it, it likely does not work anymore. Carte Blanche is an iso

Mar 6, 2022
The smartest way to share interactive components with your team.
The smartest way to share interactive components with your team.

A React component that works like a preview of other components. An excellent tool to show how your component works and looks with. Easy to install an

Apr 26, 2022
Chai.js assertions and convenience functions for testing React Components with enzyme
Chai.js assertions and convenience functions for testing React Components with enzyme

chai-enzyme Chai.js assertions for enzyme. Table of Contents Installation Setup Debug output in assertion exceptions Assertions 1. checked() 1. classN

Apr 24, 2022
Harness the power of reactive programming to supercharge your components
Harness the power of reactive programming to supercharge your components

Handle your component effects and side-effects in a clear and declarative fashion by using asynchronous data streams (reactive programming). Why? · In

May 2, 2022
Create, isolate and test modular UI components in React.
Create, isolate and test modular UI components in React.

ui-harness Isolate, test and document modular UI with React using familiar describe/it testing semantics. http://uiharness.com Quick Start (1-minute)

Dec 24, 2021
React server components + MDX
React server components + MDX

server-components-mdx-demo Go to demo » Build Clone this repo, cd into it, make sure you’re using Node 12+, and then: npm i --legacy-peer-deps npm run

Jan 7, 2022
Smarter layout components. Based on css flexbox. Support responsive design, Typescript, server side render. 3 KB gzipped.
Smarter layout components. Based on css flexbox. Support responsive design, Typescript, server side render. 3 KB gzipped.

react-colrow English | 中文 Smarter layout components. Based on css flexbox. Support responsive design, Typescript, server side render. 3 KB gzipped. 更智

Mar 23, 2022
This script is to take simplify duplicating components in webpages
This script is to take simplify duplicating components in webpages

style-extractor The purpose of this script is to take simplify duplicating components in webpages. How to use Clone the repo npm install install types

Dec 11, 2021
Camouflage components help to change view as per various status

react-camouflage react-camouflage components help to change view as per various

Dec 30, 2021
Intro to React, TypeScript and Styled-Components

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

Feb 11, 2022
transform react class component to function component
transform react class component to function component

react-class-to-fc ⭐ 特性 将react class组件转化为react 函数组件 ?? 安装 npm i react-class-to-fc -g ?? 使用 ctfc -i react-demo.js -o fc.js 就会将 react-demo.js文件中的class组

Nov 22, 2021
An extension that allows inspection of React component hierarchy in the Chrome and Firefox Developer Tools.

This project has migrated to github.com/facebook/react The source code for the v3 of the extension can be found in the v3 branch. To build the v3 brow

May 17, 2022
Isolated React component development environment with a living style guide
Isolated React component development environment with a living style guide

Isolated React component development environment with a living style guide React Styleguidist is a component development environment with hot reloaded

May 16, 2022
React JSON inspector component
React JSON inspector component

React JSON Inspector Component React-based JSON inspector that features tree expansion and fast search. Live demo Installation npm install react-json-

May 7, 2022
Isolated React component development environment with a living style guide
Isolated React component development environment with a living style guide

Isolated React component development environment with a living style guide React Styleguidist is a component development environment with hot reloaded

May 17, 2022
A mobile-first React prototyping tool with React-Bootstrap component integration
A mobile-first React prototyping tool with React-Bootstrap component integration

A mobile-first React prototyping tool with React-Bootstrap component integration

Apr 17, 2022