Skip to content

Instantly share code, notes, and snippets.

@mxstbr mxstbr/idea.md
Last active Nov 4, 2017

Embed
What would you like to do?
Code splitting react-router routes with webpack 2

NOTE: Sokra confirmed I had a misunderstanding, Webpack is still a static build tool and the below won't work. It's still a nice concept though...

With webpack 1, code splitting react-router routes is quite tedious. It requires us to repeat the getComponent function over and over again. (See here for an explanation how it works with webpack 1)

Example:

<Router history={history}>
  <Route
    path="/"
    getComponent={(location, callback) => {
      require.ensure([], function (require) {
        callback(null, require('./HomePage.jsx'));
      });
    }}
  />
  <Route
    path="/about"
    getComponent={(location, callback) => {
      require.ensure([], function (require) {
        callback(null, require('./AboutPage.jsx'));
      });
    }}
  />
</Router>

The getComponent function is almost the same across all routes, that's not very DRY. The problem is that with webpack v1, it needed the requires as static strings because it analyses the code before evaluation, and it needs to somehow determine there which modules should go into seperate chunks.

With webpack 2 though, we're getting System.import and dynamic expressions! (src) This'll make code splitting react-router routes so much easier. Imagine a component like this:

class Page extends React.Component {
  render() {
    <Route
      path={this.props.path}
      getComponent={(location, callback) => {
        System.import(this.props.component)
          .then((component) => {
            callback(null, component);
          });
      }
  }
}

Used like this:

<Router history={history}>
  <Page path="/about" component="./AboutPage.jsx" />
</Router>

And all of these <Page>s are now in seperate chunks! Code splitting react-router routes: easy with webpack 2.

Note: This is just an idea, none of the new code above is tested.

@hufeng

This comment has been minimized.

Copy link

commented Jul 4, 2016

cool

@hufeng

This comment has been minimized.

Copy link

commented Jul 4, 2016

because this issue. webpack/webpack#2188

class Page extends React.Component {
  render() {
    <Route
      path={this.props.path}
      getComponent={(location, callback) => {
        System.import(this.props.component)
          .then((component) => {
            callback(null, component.default || component);
          });
      }
  }
}
@dinesh2609

This comment has been minimized.

Copy link

commented Aug 17, 2016

Any idea on how to send props along with component when used with code splitting..

In the above example

@sagiavinash

This comment has been minimized.

Copy link

commented Feb 5, 2017

With this Page definition we can completely abstract out normal and onDemand routes

class Page extends React.Component {
  render() {
    if (this.props.isOnDemand) {
      return (
        <Route
          {...this.props}
          getComponent={(location, callback) => {
            System.import(this.props.component).then((component) => {
              callback(null, component.default || component);
            });
          }}
        >{this.props.children}</Route>
      );
    } else {
      return <Route {...this.props} />;
    }
  }
}
@rubencodes

This comment has been minimized.

Copy link

commented Mar 22, 2017

Just, for the record: I wasn't able to implement this several reasons:

  1. React-Router@3.0.2 (at least in my testing) was not happy with direct non-Route children 😕
  2. WebPack@2.2.1 wouldn't allow me to System.import a dynamic path—I had to hard code in the paths for it to work (e.g. System.import('/my/path/here'). This is conflicting with it's documentation, which seems to imply you can do this; I think you have to provide at least part of the path for it to make guesses about all the files you would like to include.

So maybe I did something wrong, but I, at least, was not able to get this to work through this really really nice-looking abstraction.

@kamleshchandnani

This comment has been minimized.

Copy link

commented Jul 2, 2017

With webpack 2.6 I tried this
import(this.props.chunkname) but this doesn't seems to work, where chunkname = "./container/componentName" but this is not resolved at runtime

@ananddodia

This comment has been minimized.

Copy link

commented Aug 25, 2017

I implemented code splitting same way. Separate modules js files are build. So webpack build is successfully completed.
Now when i load index page. It loads but when i open new page. New page module is loaded dynamic successful.
But issue it that new js file that loaded, that component is not rendered. It does not show any error also.
<Route path="connections" getComponent={ (location, cb) => { if (__SERVER__) { Promise.all('./containers/Connections/Connections').then(loadRoute(cb)).catch(errorLoading); } else { // System.import('./containers/Connections/Connections').then(loadRoute(cb)).catch(errorLoading); require.ensure([], (require) => cb(null, require('./containers/Connections/Connections').default), 'Directory'); } } } />
this module is not rendered

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.