-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Step 1: minimal Webpack, Babel and React setup
RUN: `npm run start` and then open index.html in the browser. Webpack helps us to bundle our code with dependencies from npm (such as React), and then transforms the code with Babel, to make it compatible with ES5.
- Loading branch information
0 parents
commit 7d1d067
Showing
7 changed files
with
168 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"presets": ["react", "es2015"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
node_modules | ||
built |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
# Interactive Guide to Server-side rendering with Webpack, React, React Transmit, CSS modules and more | ||
|
||
Follow the tutorial commit-by-commit, to see the server-side rendering drama unfold with a happy ending! | ||
|
||
[CLICK TO GET STARTED](https://github.com/dimaip/server-side-rendering/commits/master) | ||
|
||
|
||
## Contents (mostly for Google) | ||
|
||
### Step 1: minimal Webpack, Babel and React setup | ||
|
||
RUN: `npm run start` and then open index.html in the browser. | ||
|
||
Webpack helps us to bundle our code with dependencies from npm | ||
(such as React), and then transforms the code with Babel, to make | ||
it compatible with ES5. | ||
|
||
### Step 2: trivial server-side rendering with Express | ||
|
||
RUN: `npm run start` and go to `http://localhost:3000`. | ||
|
||
Now we are rendering the same Hello component both on client and server: | ||
with express server we pre-render the Hello component on the server, and | ||
server the client with rendered html, and with webpack we continue to | ||
bundle client.js into ES5 code that the browser would understand, | ||
just as we did at previous step. | ||
|
||
### Step 3: Add styles | ||
|
||
Now lets learn to deal with styles. We configure webpack loaders to | ||
support loading CSS files. This is cool, but there comes one problem | ||
with server-side rendering: styles won't be loaded until all of JS loads, | ||
so no styles for devices without JS. | ||
|
||
Let's fix this problem with webpack's ExtractTextPlugin plugin: it | ||
extracts all CSS styles into one CSS file that we can serve to our client, | ||
so our page will instantly look perfectly styled, even without JS. | ||
|
||
### Step 3a: switch to CSS modules | ||
|
||
Everybody loves CSS modules, and the great news is that they come free with Webpack. | ||
The bad news is that we can't use them with server-side rendering, as we don't use | ||
Webpack when rendering on the server-side. | ||
|
||
So at this step we broke everything, and the only way to continue from here, is to | ||
start using Webpack to pre-build code for server-side rendering too, and that's | ||
what we'll do at the next step. | ||
|
||
### Step 3b: save the day by making webpack to render server-side code | ||
|
||
To save our issue with CSS modules, we make Webpack to render both | ||
our client and our server side code. The best way to do it is to | ||
use Webpack's abillity to handle array of configs. | ||
|
||
With first config we transform our client-side code (`client.js`), | ||
just as we were doing before. But with the second config we transform | ||
`handleRender` function that we have extracted into `serverEntry.js`, | ||
so now our server-side rendering code gets processed by Webpack too. | ||
There we use css-loader/locals as a CSS loader, to just get class names from | ||
CSS modules, as that's all we need to render html on the server. | ||
Also notice how we use `target:node` and `nodeExternals`. | ||
|
||
Great! Now our build is fixed, so we can use CSS modules both during client | ||
and server rendering. | ||
|
||
|
||
### Step 4a: asyncronously fetching data | ||
|
||
Now let's fetch some data asyncronously. We'll use isomorphic-fetch, | ||
as it works both on client and server our of the box. | ||
|
||
Fetching data works just fine on the server, but the problem is that | ||
on the server we didn't wait for fetch to finish fetching the data | ||
before sending the response, so our pre-rendered html doesn't have any | ||
async data when it arrives. | ||
Let's try to fix it in the next step. | ||
|
||
|
||
### Step 4b: use react-transmit to declaratively define data deps | ||
|
||
There are multiple ways to solve async rendering issue. Here we'll | ||
use react-transmit to declaratively define our data dependencies per component, | ||
and return rendered html only when all data is resolved. | ||
|
||
It works even with nested components, constructing the single promises tree, | ||
which is qute cool. It is inspired by Facebook Relay, so if you are familiar | ||
with it, you'll feel right at home. | ||
|
||
|
||
## That's all, folks! | ||
|
||
Got more tips or challenges with server-side rendering of React? Submit a PR! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<title>Server-side rendering tutorial</title> | ||
</head> | ||
<body> | ||
<div id="app"></div> | ||
<script src="built/index.js"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import React from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
|
||
var Hello = React.createClass({ | ||
render: function() { | ||
return <div>Hello {this.props.name}</div>; | ||
} | ||
}); | ||
|
||
ReactDOM.render( | ||
<Hello name="World" />, | ||
document.getElementById('app') | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
{ | ||
"name": "server-side-rendering", | ||
"version": "0.0.1", | ||
"description": "The missing guide to server-side rendering", | ||
"main": "index.js", | ||
"scripts": { | ||
"start": "webpack" | ||
}, | ||
"author": "Dmitri Pisarev", | ||
"license": "ISC", | ||
"dependencies": { | ||
"path": "^0.12.7", | ||
"react": "^0.14.8", | ||
"react-dom": "^0.14.8" | ||
}, | ||
"devDependencies": { | ||
"webpack": "^1.12.14", | ||
"babel-cli": "^6.6.5", | ||
"babel-loader": "^6.2.4", | ||
"babel-preset-es2015": "^6.6.0", | ||
"babel-preset-react": "^6.5.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
const path = require('path'); | ||
const webpack = require('webpack'); | ||
|
||
const config = { | ||
entry: ['index.js'], | ||
output: { | ||
path: path.join(__dirname, 'built/'), | ||
filename: 'index.js', | ||
publicPath: '/built/' | ||
}, | ||
module: { | ||
loaders: [ | ||
{ | ||
test: /\.js$/, | ||
exclude: /node_modules/, | ||
loader: 'babel' | ||
} | ||
] | ||
}, | ||
resolve: { | ||
root: __dirname | ||
} | ||
}; | ||
|
||
module.exports = config; |