question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

SSR + code-splitting

See original GitHub issue

Hey @leebenson!

Nice starter kit! I have a similar setup with SSR based on react-router@3 and everything works fine. I aim to refactor in the near future and this setup looks great for that. Wondering what your thoughts are on SSR + code-splitting with v4?

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:8 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
leebensoncommented, May 28, 2017

@scf4 - this actually works in production, but not via the new dev server:

test.js

import React from 'react';

export default () => (<h1>Test!</h1>);

app.js

// ...
function asyncComponent(getComponent) {
  return class AsyncComponent extends React.Component {
    static Component = null;
    state = { Component: AsyncComponent.Component };

    componentWillMount() {
      if (!this.state.Component) {
        getComponent().then(Component => {
          AsyncComponent.Component = Component;
          this.setState({ Component });
        });
      }
    }
    render() {
      const { Component } = this.state;
      if (Component) {
        return <Component {...this.props} />;
      }
      return null;
    }
  };
}

const Test = asyncComponent(() =>
  import('./test').then(module => module.default),
);

// Export a simple component that allows clicking on list items to change
// the route, along with a <Route> 'listener' that will conditionally display
// the <Page> component based on the route name
export default () => (
  <div>
    <Helmet
      title="ReactQL application"
      meta={[{
        name: 'description',
        content: 'ReactQL starter kit app',
      }]} />
    <div className={css.hello}>
      <img src={logo} alt="ReactQL" className={css.logo} />
    </div>
    <hr />
    <GraphQLMessage />
    <hr />
    <ul>
      <li><Link to="/">Home</Link></li>
      <li><Link to="/page/about">About</Link></li>
      <li><Link to="/page/contact">Contact</Link></li>
    </ul>
    <hr />
    <Switch>
      <Route exact path="/" component={Home} />
      <Route path="/page/:name" component={Page} />
      <Route path="/test" component={Test} />
      <Route component={NotFound} />
    </Switch>
    <hr />
    <p>Runtime info:</p>
    <Stats />
    <hr />
    <p>Stylesheet examples:</p>
    <Styles />
  </div>
);

// ...

I’m tracking this in https://github.com/reactql/kit/issues/30

2reactions
leebensoncommented, Mar 31, 2017

Thanks @kuka.

Code-splitting on the server should actually work out-the-box.

Because we’re using Webpack 2 to generate bundles on both the client and the server, any strategy that uses require.ensure() (or import()-based Promises - I’m pushing an update for that this morning) should resolve well on the server, too. The reason I opted for server-side bundling is exactly for that reason - it should be possible (for the most part) to write code in one place, and know that it’ll work on the server, too. Same with .css, .json, inline image loading, etc.

The one thing that’s currently missing is a built-in HOC for returning a ‘loading’ component whilst split code hasn’t yet returned back from its round-trip, and a recommended pattern in the docs for doing the actual split.

In the meantime, I whipped together this very quick example to demonstrate it working in practice:

Let’s say you have this:

src/test.js

export default 'code-splitting for the win!';

And then inside src/app.js, we modify the <Message> component to grab the code-split message, instead of the current GraphQL:

class Message extends React.PureComponent {
  constructor() {
    super();
    this.state = {
      message: '',
    };
  }

  componentDidMount() {
    import('./test').then(mod => {
      this.setState({
        message: mod.default,
      });
    });
  }

  render() {
    return (
      <div>
        <h2>Message from code-splitting: <em>{this.state.message}</em></h2>
      </div>
    );
  }
}

Running npm start will yield the expected result:

screen shot 2017-03-31 at 08 14 56

And you can see the network request that grabbed this asynchronously:

network

Now, the neat this is that you also get this on the server, too - running npm run build-run will confirm:

Browser files generated

Hash: c09946598a0df5285bba2bd58c399409d8f2a767 Version: webpack 2.3.2 Child Hash: c09946598a0df5285bba Time: 8738ms Asset Size Chunks Chunk Names 0.js 143 bytes 0 [emitted] <— this is the async code-split browser.js 5.98 kB 1 [emitted] browser vendor.js 344 kB 2 [emitted] [big] vendor assets/css/style.css 452 bytes 1 [emitted] browser browser.js.gz 2.32 kB [emitted]
assets/css/style.css.gz 285 bytes [emitted]
vendor.js.gz 99.9 kB [emitted]

And on the server, too

Hash: 2bd58c399409d8f2a767
Time: 1949ms
      Asset       Size  Chunks             Chunk Names
0.server.js  251 bytes       0  [emitted]   <--- automatically loaded by the server!
  server.js    23.5 kB       1  [emitted]  javascript

Of course, in this example, the <Message> component attempts to set its internal ‘message’ state after the import() Promise resolves. At this point, the server has already turned the React chain into HTML and fired it back to the screen.

Since import() returns a Promise when the code-split data is available, the solution is to use a lib like redial to decorate components with data requirements, and then await the full chain being ready before rendering into HTML. This would work in the same way that Apollo’s getDataFromTree does for GraphQL queries.

In a (soon-ish) future version, I’ll add those features to the starter kit, and update src/app.js to show examples of code splitting at work, and how you can simulate synchronous loading for a server environment.

Read more comments on GitHub >

github_iconTop Results From Across the Web

React Server Side Code Splitting Made.. Again - ITNEXT
Even more — SSR, without any JS sent to the client, is the best code splitting ever possible, as long all the things...
Read more >
Code Splitting, SSR, Lazy loading React components - Medium
It's 2020! Everyone is talking about code splitting and you are pumped up to implement it. But, are you ready? Let's find out!...
Read more >
Why code splitting is hard in react server side rendering?
It is basically a way to split code from a large file into smaller code bundles which can be requested on demand or...
Read more >
What's the point of SSR when code splitting/lazy loading exists ...
There are definitely cases where CSR with lazy loading and code splitting is too slow, and there are cases where it's perfectly fine....
Read more >
Code Splitting in React – Loadable Components to the Rescue
Code splitting is a way to split up your code from a large file into smaller code bundles. These can then be requested...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found