Comments (8)
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:
And you can see the network request that grabbed this asynchronously:
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.
from reactql.
@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 reactql/kit#30
from reactql.
Thank you for a concise reply, Lee!
What you’ve written is going to tremendously help in my and others’ situations.
I consider this closed.
from reactql.
Can you split vendor.js based on the routes which require it?
Edit: actually I see it will already do this. But I'm not quite sure how to get code splitting working on server rendering too, since I call import in componentDidMount?
from reactql.
@scf4 - are you able to share the code for what you're trying to do?
Code splitting should work on the server in exactly the same way (i.e. you can use await import('./someModule');
in both environments), but if you have some kind of DOM-only code you want to load in the client only, you can keep that in componentDidMount
and it should be split on the client route only.
from reactql.
@leebenson I'm using this example pretty much: https://gist.github.com/acdlite/a68433004f9d6b4cbc83b5cc3990c194
The server still renders everything else, it just doesn't load the async loaded component. So disabling JS means you can't see the async loaded component.
from reactql.
@leebenson Thanks Lee, I'll give that asyncComponent function a try now.
Edit: it worked, thank you 😄
from reactql.
cool @scf4 👍
react-async-component looks like a good way to handle code-splitting. I haven't tried it, but it should work with the ReactQL webpack flow.
from reactql.
Related Issues (20)
- sass imported styles are null on server, but correct on client HOT 2
- Question: Is go to definition supposed to work for generated types? HOT 1
- Constantly Loosing Styles And Images Using Office Fabric UI
- 4.3.1.tar.gz not working HOT 3
- Can't run project - quick start HOT 1
- .nvmrc Missing HOT 1
- Hot Reload seems to be broken in master HOT 1
- [v3.2.0] How to disable SSR? HOT 3
- ReactQL3.0 entry acts funny trying to start server HOT 1
- Hydrate on Static Deploy HOT 1
- Adding Material UI Button cause emty page HOT 2
- css.ts localIdentName: "[local]-[hash:base64]", fail
- import X from "y" HOT 2
- Could not find "client" in the context or passed in as an option. Wrap the root component in an <ApolloProvider
- Default Apollo Hooks rather than generated HOC for Apollo Queries HOT 2
- Example for a MongoDB based server HOT 1
- Stuck during production build HOT 2
- ReactQL Starter Kit giving errors with 'npm start' HOT 4
- Unable to connect to graphqlhub.com HOT 6
- Any update for Apollo Client v3?
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from reactql.