Skip to content

Commit 0390084

Browse files
committed
Code
0 parents  commit 0390084

File tree

16 files changed

+7014
-0
lines changed

16 files changed

+7014
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules
2+
.DS_Store
3+
dist
4+
public

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<h1 align="center">
2+
<a href="https://ui.dev">
3+
<img
4+
src="https://ui.dev/images/logos/ui.png"
5+
alt="UI.dev Logo" width="300" />
6+
</a>
7+
<br />
8+
</h1>
9+
10+
<h3 align="center">Server Rendering with React Router v5</h3>
11+
12+
### Info
13+
14+
This is the code repository for [UI.dev](https://ui.dev)'s [Server Rendering with React Router v5](http://ui.dev/react-router-v5-server-rendering) post.
15+
16+
For more information on the full course, visit __[ui.dev/react-router-v5](https://ui.dev/react-router-v5/)__.

package-lock.json

Lines changed: 6525 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
{
2+
"name": "react-router-v5-server-rendering",
3+
"description": "Example for server rendering with React Router v5.",
4+
"scripts": {
5+
"build": "webpack -p",
6+
"start": "node dist/server.js",
7+
"dev": "webpack && node dist/server.js"
8+
},
9+
"babel": {
10+
"presets": [
11+
"@babel/preset-env",
12+
"@babel/preset-react"
13+
],
14+
"plugins": [
15+
"@babel/plugin-proposal-object-rest-spread"
16+
]
17+
},
18+
"devDependencies": {
19+
"@babel/core": "^7.9.0",
20+
"@babel/plugin-proposal-object-rest-spread": "^7.9.5",
21+
"@babel/preset-env": "^7.9.5",
22+
"@babel/preset-react": "^7.9.4",
23+
"babel-loader": "^8.1.0",
24+
"css-loader": "^3.5.3",
25+
"mini-css-extract-plugin": "^0.9.0",
26+
"webpack": "^4.43.0",
27+
"webpack-cli": "^3.3.11",
28+
"webpack-node-externals": "^1.7.2"
29+
},
30+
"dependencies": {
31+
"cors": "^2.8.5",
32+
"express": "^4.17.1",
33+
"isomorphic-fetch": "^2.2.1",
34+
"react": "^16.13.1",
35+
"react-dom": "^16.13.1",
36+
"react-router-dom": "^5.1.2",
37+
"serialize-javascript": "^3.0.0"
38+
},
39+
"version": "1.0.0",
40+
"main": "index.js",
41+
"repository": {
42+
"type": "git",
43+
"url": "git+https://github.com/uidotdev/react-router-v5-server-rendering.git"
44+
},
45+
"author": "Tyler McGinnis",
46+
"license": "MIT",
47+
"homepage": "https://github.com/uidotdev/react-router-v5-server-rendering#readme",
48+
"engines": {
49+
"node": "13.12.x"
50+
}
51+
}

src/browser/index.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as React from 'react'
2+
import ReactDOM from 'react-dom'
3+
import App from '../shared/App'
4+
import { BrowserRouter } from 'react-router-dom'
5+
6+
ReactDOM.hydrate(
7+
<BrowserRouter>
8+
<App />
9+
</BrowserRouter>,
10+
document.getElementById('app')
11+
);

src/server/index.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import express from 'express'
2+
import cors from 'cors'
3+
import * as React from 'react'
4+
import ReactDOM from 'react-dom/server'
5+
import { StaticRouter, matchPath } from 'react-router-dom'
6+
import serialize from 'serialize-javascript'
7+
import App from '../shared/App'
8+
import routes from '../shared/routes'
9+
10+
const app = express()
11+
12+
app.use(cors())
13+
app.use(express.static('dist'))
14+
15+
app.get('*', (req, res, next) => {
16+
const activeRoute = routes.find((route) => matchPath(req.url, route)) || {}
17+
18+
const promise = activeRoute.fetchInitialData
19+
? activeRoute.fetchInitialData(req.path)
20+
: Promise.resolve()
21+
22+
promise.then((data) => {
23+
const markup = ReactDOM.renderToString(
24+
<StaticRouter location={req.url} context={{ data }}>
25+
<App />
26+
</StaticRouter>
27+
)
28+
29+
res.send(`
30+
<!DOCTYPE html>
31+
<html>
32+
<head>
33+
<title>SSR with RRv5</title>
34+
<script src="/bundle.js" defer></script>
35+
<link href="/main.css" rel="stylesheet">
36+
<script>window.__INITIAL_DATA__ = ${serialize(data)}</script>
37+
</head>
38+
39+
<body>
40+
<div id="app">${markup}</div>
41+
</body>
42+
</html>
43+
`)
44+
}).catch(next)
45+
})
46+
47+
const PORT = process.env.PORT || 3000
48+
49+
app.listen(PORT, () => {
50+
console.log(`Server is listening on port: ${PORT}`)
51+
})

src/shared/App.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import * as React from 'react'
2+
import routes from './routes'
3+
import { Route, Switch } from 'react-router-dom'
4+
import Navbar from './Navbar'
5+
import NoMatch from './NoMatch'
6+
import ColorfulBorder from './ColorfulBorder'
7+
import './styles.css'
8+
9+
export default function App () {
10+
return (
11+
<React.Fragment>
12+
<ColorfulBorder />
13+
<div className='container'>
14+
<Navbar />
15+
16+
<Switch>
17+
{routes.map(({ path, exact, fetchInitialData, component: C }) => (
18+
<Route key={path} path={path} exact={exact} render={(props) => (
19+
<C fetchInitialData={fetchInitialData} {...props} />
20+
)} />
21+
))}
22+
<Route path='*'>
23+
<NoMatch />
24+
</Route>
25+
</Switch>
26+
</div>
27+
</React.Fragment>
28+
)
29+
}

src/shared/ColorfulBorder.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import * as React from 'react'
2+
3+
export default function ColorfulBorder() {
4+
return (
5+
<ul className='border-container'>
6+
<li className='border-item' style={{ background: 'var(--red)' }} />
7+
<li className='border-item' style={{ background: 'var(--blue)' }} />
8+
<li className='border-item' style={{ background: 'var(--pink)' }} />
9+
<li className='border-item' style={{ background: 'var(--yellow)' }} />
10+
<li className='border-item' style={{ background: 'var(--aqua)' }} />
11+
</ul>
12+
)
13+
}

src/shared/Grid.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import * as React from 'react'
2+
import { useParams } from 'react-router-dom'
3+
4+
export default function Grid ({ fetchInitialData, staticContext }) {
5+
const [repos, setRepos] = React.useState(() => {
6+
return __isBrowser__
7+
? window.__INITIAL_DATA__
8+
: staticContext.data
9+
})
10+
11+
const [loading, setLoading] = React.useState(
12+
repos ? false : true
13+
)
14+
15+
const fetchNewRepos = React.useRef(
16+
repos ? false : true
17+
)
18+
19+
const { id } = useParams()
20+
21+
React.useEffect(() => {
22+
if (fetchNewRepos.current === true) {
23+
setLoading(true)
24+
25+
fetchInitialData(id)
26+
.then((repos) => {
27+
setRepos(repos)
28+
setLoading(false)
29+
})
30+
} else {
31+
fetchNewRepos.current = true
32+
}
33+
}, [id, fetchNewRepos])
34+
35+
if (loading === true) {
36+
return <i className='loading'>🤹‍♂️</i>
37+
}
38+
39+
return (
40+
<ul className='grid'>
41+
{repos.map(({ name, owner, stargazers_count, html_url }, i) => (
42+
<li key={name}>
43+
<h2>#{i+1}</h2>
44+
<h3><a href={html_url}>{name}</a></h3>
45+
<p>by <a href={`https://github.com/${owner.login}`}>@{owner.login}</a></p>
46+
<p>{stargazers_count.toLocaleString()} stars</p>
47+
</li>
48+
))}
49+
</ul>
50+
)
51+
}

src/shared/Home.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import * as React from 'react'
2+
3+
export default function Home () {
4+
return <h2 className='heading-center'>Select a Language</h2>
5+
}

0 commit comments

Comments
 (0)