forked from vercel/next.js
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add example on how to pass data through js api during SSR
Requested in vercel#1117
- Loading branch information
1 parent
00e2659
commit f4ee2a0
Showing
8 changed files
with
175 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,48 @@ | ||
[![Deploy to now](https://deploy.now.sh/static/button.svg)](https://deploy.now.sh/?repo=https://github.com/zeit/next.js/tree/master/examples/pass-server-data) | ||
|
||
# Pass Server Data Directly to a Next.js Page during SSR | ||
|
||
## How to use | ||
|
||
Download the example [or clone the repo](https://github.com/zeit/next.js): | ||
|
||
```bash | ||
curl https://codeload.github.com/zeit/next.js/tar.gz/master | tar -xz --strip=2 next.js-master/examples/pass-server-data | ||
cd pass-server-data | ||
``` | ||
|
||
Install it and run: | ||
|
||
```bash | ||
npm install | ||
npm run dev | ||
``` | ||
|
||
Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download)) | ||
|
||
```bash | ||
now | ||
``` | ||
|
||
## The idea behind the example | ||
|
||
If you already have a custom server which has local data (for instance cached data from an API call, or data read | ||
from a file at startup) that you wish to make available in the Next.js page, you can pass that data in the query | ||
parameter of `nextApp.render()`. | ||
|
||
This is not the only way to pass data. You could also expose an endpoint and make a `fetch()` call to localhost, or you could | ||
import server-side code with `eval` (necessary to prevent webpack from trying to package your server code). However both | ||
solutions leave something to be desired in either performance or elegance. | ||
|
||
This example shows the express server at `server.js` reading in a file at load time with static data (this could also have been | ||
data cached from an API call) in `operations/get-item.js`. It has two routes: a home page, and an item page. The item page uses | ||
data from the get-item operation, passed as a query parameter in `routes/item.js`. | ||
|
||
We use this data in `pages/item.js` if rendered server-side, or make a fetch request if rendered client-side. | ||
|
||
Take a look at the following files: | ||
|
||
* server.js | ||
* routes/item.js | ||
* pages/item.js | ||
* operations/get-item.js |
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,5 @@ | ||
{ | ||
"title": "Now", | ||
"subtitle": "Realtime global deployments", | ||
"seller": "Zeit" | ||
} |
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,12 @@ | ||
const fs = require('fs') | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
unregistered
Author
Owner
|
||
|
||
// In this case, data read from the fs, but it could also be a cached API result. | ||
const data = fs.readFileSync('./data/item.json', 'utf8') | ||
const parsedData = JSON.parse(data) | ||
|
||
function getItem () { | ||
console.log('Requested Item Data:', data) | ||
return parsedData | ||
} | ||
|
||
module.exports = { getItem } |
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,16 @@ | ||
{ | ||
"name": "pass-server-data", | ||
"version": "1.0.0", | ||
"scripts": { | ||
"dev": "node server.js", | ||
"build": "next build", | ||
"start": "NODE_ENV=production node server.js" | ||
}, | ||
"dependencies": { | ||
"express": "^4.14.0", | ||
"isomorphic-fetch": "^2.2.1", | ||
"next": "latest", | ||
"react": "^15.4.2", | ||
"react-dom": "^15.4.2" | ||
} | ||
} |
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,8 @@ | ||
import React from 'react' | ||
import Link from 'next/link' | ||
|
||
export default () => ( | ||
<ul> | ||
<li><Link href='/item'><a>View Item</a></Link></li> | ||
</ul> | ||
) |
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,33 @@ | ||
import {Component} from 'react' | ||
import Link from 'next/link' | ||
import fetch from 'isomorphic-fetch' | ||
|
||
export default class extends Component { | ||
static async getInitialProps ({ req, query }) { | ||
const isServer = !!req | ||
|
||
console.log('getInitialProps called:', isServer ? 'server' : 'client') | ||
|
||
if (isServer) { | ||
// When being rendered server-side, we have access to our data in query that we put there in routes/item.js, | ||
// saving us an http call. Note that if we were to try to require('../operations/get-item') here, | ||
// it would result in a webpack error. | ||
return { item: query.itemData } | ||
} else { | ||
// On the client, we should fetch the data remotely | ||
const res = await fetch('http://localhost:3000/_data/item') | ||
const json = await res.json() | ||
return { item: json } | ||
} | ||
} | ||
|
||
render () { | ||
return ( | ||
<div className='item'> | ||
<div><Link href='/'><a>Back Home</a></Link></div> | ||
<h1>{this.props.item.title}</h1> | ||
<h2>{this.props.item.subtitle} - {this.props.item.seller}</h2> | ||
</div> | ||
) | ||
} | ||
} |
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,20 @@ | ||
const api = require('../operations/get-item') | ||
|
||
// Returns the express handler function. Necessary so that we can get the nextApp instance. | ||
function getItemRenderer (nextApp) { | ||
return (req, res) => { | ||
console.log('Express is handling request') | ||
const itemData = api.getItem() | ||
return nextApp.render(req, res, '/item', { itemData }) | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
unregistered
Author
Owner
|
||
} | ||
} | ||
|
||
// So that we can do a fetch from the page if rendering client-side. | ||
function getItem (req, res, next) { | ||
const itemData = api.getItem() | ||
console.log('API request for item data') | ||
res.setHeader('content-type', 'application/json') | ||
res.send(itemData) | ||
} | ||
|
||
module.exports = { getItemRenderer, getItem } |
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,33 @@ | ||
const express = require('express') | ||
const next = require('next') | ||
const itemRoute = require('./routes/item') | ||
|
||
const dev = process.env.NODE_ENV !== 'production' | ||
const app = next({ dev }) | ||
const handle = app.getRequestHandler() | ||
|
||
app.prepare().then(() => { | ||
const server = express() | ||
|
||
// Set up home page as a simple render of the page. | ||
server.get('/', (req, res) => { | ||
console.log('Render home page') | ||
return app.render(req, res, '/', req.query) | ||
}) | ||
|
||
// We have more complex logic here so we've isolated this code into a route file. | ||
server.get('/item', itemRoute.getItemRenderer(app)) | ||
|
||
// Serve back-end API to support isomorphic rendering. | ||
server.get('/_data/item', itemRoute.getItem) | ||
|
||
// Fall-back on other next.js assets. | ||
server.get('*', (req, res) => { | ||
return handle(req, res) | ||
}) | ||
|
||
server.listen(3000, (err) => { | ||
if (err) throw err | ||
console.log('> Ready on http://localhost:3000') | ||
}) | ||
}) |
Is this file necessary? We can probably just throw this into the route for the sake of simplicity.