uidotdev / rrssr-v4 Goto Github PK
View Code? Open in Web Editor NEWTutorial code for Server Rendering with React and React Router v4
Tutorial code for Server Rendering with React and React Router v4
Hi, can I ask you how to publish these ssr app to a host?
I am new to react and I want to setup a personnel blog using react and webpack and ssr feature.
I created complete structure of blog and service api but I don't know how to publish node base app in a host. :(
can you help me please :D ?
Hey Tyler,
I think someone https://medium.com/@muthuks/react-and-react-router-server-rendering-d2e36c64dbc5 copied/pasted your content on medium. Considering that the date of that post is later than yours.
Thanks for sharing your (original) content btw 😎
Hello, could you please explain how did you manage to use this command
"start": "webpack -w & nodemon server.js".
When I run it on windows webpack builds and starts watching files, and second command just don't start.
Thank you.
Problem statement -
I have express ejs view for Server side rendering. I want to replace it React Server side view
e.g.
const view = 'testview';
res.render(view, { param1, param2, param3 });
I am trying to use this for replacing my EJS views with SS with something...
app.get('/view/:viewid', viewRender(param1, param2, param3)) ;
Somehow I am able to render, The button is render with property. But not very sure if the implementation is correct of need improvements. I will request to review and provide feedback
The steps are -
Step 1 - First create a dynamic View route /view/:viewId in routes.js
`
import Home from './Home'
import Grid from './Grid'
import DyanamicView from './DynamicView'
import TestPage from './TestPage.jsx'
import { fetchPopularRepos } from './api'
const routes = [
{
path: '/',
exact: true,
component: Home,
},
{
path: '/popular/:id',
component: Grid,
fetchInitialData: (path = '') => fetchPopularRepos(path.split('/').pop())
},
{
path: '/test',
exact: true,
component: TestPage
},
{
path: '/view/:viewId',
exact: true,
component: DyanamicView
}
]
export default routes
`
Step 2-
Create React component DyanamicView.jsx - This component take the viewId from route param, maps it to React Component and render it. Something similar to Express view engines
`
import React, { Component } from 'react'
import TestPage from './TestPage.jsx'
class DynamicView extends Component {
constructor(props) {
super(props)
let viewData;
if (isBrowser) {
viewData = window.INITIAL_DATA
delete window.INITIAL_DATA
} else {
viewData = this.props.staticContext.viewData
}
this.state = {
viewData,
Component: null,
error: {}
}
}
componentDidMount() {
const viewName = this.props.match.params.viewId;
console.log("Rendering dynamic 1 " + viewName)
if (viewName === 'TestPage') {
this.setState({ Component: TestPage })
}
}
render() {
const { Component } = this.state
if (Component) {
console.log("Rendering dynamic 2 " + Component)
return (
<div>
<Component {...this.props} {...this.state.viewData} />
</div>
)
}
return null
}
}
export default DynamicView
Step 3 : Create the dymamic view - It is simple TestView with matirial-ui
`
import React from 'react';
import AppBar from 'material-ui/AppBar';
import baseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import RaisedButton from 'material-ui/RaisedButton';
import PropTypes from 'prop-types';
class TestPage extends React.Component {
constructor(props, context) {
super(props, context);
console.log("Rendering TestPage 1 ");
}
getChildContext() {
return { muiTheme: getMuiTheme(baseTheme) };
}
render() {
console.log("Rendering TestPage 2 " +this.props);
return (
</div>
);
}
}
TestPage.childContextTypes = {
muiTheme: PropTypes.object.isRequired,
};
export default TestPage;
`
Step 4- Modify App.js to render dynamic view
`
import express from "express"
import cors from "cors"
import React from "react"
import { renderToString } from "react-dom/server"
import { StaticRouter, matchPath } from "react-router-dom"
import serialize from "serialize-javascript"
import App from '../shared/App'
import routes from '../shared/routes'
const app = express()
app.use(cors())
app.use(express.static("public"))
app.get('/view/:viewid', handleRender) ; //THIS is generic route for all dynamic Views*
//***THIS is request handler -- We need to pass View Params in the hardler curretly hard coded *****//
function handleRender(req,res) {
console.log("Finding match path URL component "+req.url)
const activeRoute = routes.find((route) => matchPath(req.url, route)) || {}
console.log("Finding match path URL component ");
var params = {name :'Manoj'}
const context = { params };
const markup = renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
)
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>SSR with RR</title>
<script src="/bundle.js" defer></script>
<script>window.__INITIAL_DATA__ = ${serialize(params)}</script>
</head>
<body>
<div id="app">${markup}</div>
</body>
</html>
`)
}
app.get("*", (req, res, next) => {
console.log("Finding match path URL component "+req.url)
const activeRoute = routes.find((route) => matchPath(req.url, route)) || {}
console.log("Finding match path URL component ")
const promise = activeRoute.fetchInitialData
? activeRoute.fetchInitialData(req.path)
: Promise.resolve()
promise.then((data) => {
const context = { data }
const markup = renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
)
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>SSR with RR</title>
<script src="/bundle.js" defer></script>
<script>window.__INITIAL_DATA__ = ${serialize(data)}</script>
</head>
<body>
<div id="app">${markup}</div>
</body>
</html>
`)
}).catch(next)
})
app.listen(3000, () => {
console.log(Server is listening on port: 3000
)
})
`
`
Hey Tyler. I used your rrssr-v4
template for my own project. I inserted my react application into the App.js
that you created. What happened after running webpack -w
is I get the error mentioned above (document
is not defined) when I run nodemon server.js
. I know document
is a DOM
variable which should not be defined in the server, hence the error.
Below is my error, package.json
, and webpack.config.js
. From the error, it looks like it has some problem with the webpack style-loader
I use. Do you know why?
ReferenceError: document is not defined
at insertStyleElement (webpack:///./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js?:93:15)
at addStyle (webpack:///./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js?:208:13)
at modulesToDom (webpack:///./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js?:81:18)
at module.exports (webpack:///./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js?:239:25)
at eval (webpack:///./src/shared/css/home-style.css?:15:14)
package.json
{
"scripts": {
"start": "webpack && nodemon server.js",
"watch:server": "nodemon server.js",
"watch:build": "webpack -w",
"test": "echo \"Error: no test specified\" && exit 1"
},
"babel": {
"presets": [
"@babel/preset-env",
"@babel/preset-react"
],
"plugins": [
"@babel/plugin-proposal-object-rest-spread",
"@babel/plugin-proposal-class-properties"
]
},
"devDependencies": {
"@babel/core": "^7.3.4",
"@babel/plugin-proposal-object-rest-spread": "^7.9.0",
"@babel/plugin-proposal-class-properties": "^7.10.4",
"@babel/preset-env": "^7.3.4",
"@babel/preset-react": "^7.0.0",
"babel-loader": "^8.1.0",
"concurrently": "^5.3.0",
"css-loader": "^4.2.1",
"file-loader": "^6.0.0",
"nodemon": "^2.0.4",
"style-loader": "^1.2.1",
"url-loader": "^4.1.0",
"webpack": "^4.42.1",
"webpack-cli": "^3.3.11",
"webpack-node-externals": "^1.7.2"
},
"dependencies": {
"cors": "^2.8.5",
"express": "^4.17.1",
"isomorphic-fetch": "^2.2.1",
"npm-run-all": "^4.1.5",
"pure-react-carousel": "^1.27.1",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router-dom": "4.4.0-beta.8",
"serialize-javascript": "^3.0.0"
}
}
webpack.config.js
var path = require('path');
var webpack = require('webpack');
var nodeExternals = require('webpack-node-externals');
var browserConfig = {
entry: './src/browser/index.js',
output: {
path: path.resolve(__dirname, 'public'),
filename: 'bundle.js',
publicPath: '/',
},
module: {
rules: [
{ test: /\.(js)$/, use: 'babel-loader' },
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(jpg|png|PNG|svg|jpe?g)$/,
use: [
{
loader: 'file-loader',
options: {
outputPath: 'img/',
publicPath: 'img/',
},
},
],
},
],
},
mode: 'production',
plugins: [
new webpack.DefinePlugin({
__isBrowser__: 'true',
}),
],
performance: {
maxEntrypointSize: 512000,
maxAssetSize: 512000,
},
};
var serverConfig = {
entry: './src/server/index.js',
target: 'node',
externals: [nodeExternals()],
output: {
path: __dirname,
filename: 'server.js',
publicPath: '/',
},
module: {
rules: [
{ test: /\.(js)$/, use: 'babel-loader' },
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(jpg|png|PNG|svg|jpe?g)$/,
use: [
{
loader: 'file-loader',
options: {
outputPath: 'img/',
publicPath: 'img/',
},
},
],
},
],
},
mode: 'production',
plugins: [
new webpack.DefinePlugin({
__isBrowser__: 'false',
}),
],
performance: {
maxEntrypointSize: 512000,
maxAssetSize: 512000,
},
};
module.exports = [browserConfig, serverConfig];
` npm run start
[email protected] start /home/ubuntu/workspace/ssr/rrssr
webpack -w & nodemon server.js
[nodemon] 1.18.6
[nodemon] to restart at any time, enter rs
[nodemon] watching: .
[nodemon] starting node server.js index.js
module.js:471
throw err;
^
Error: Cannot find module '/home/ubuntu/workspace/ssr/rrssr/index.js'
at Function.Module._resolveFilename (module.js:469:15)
at Function.Module._load (module.js:417:25)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:389:7)
at startup (bootstrap_node.js:149:9)
at bootstrap_node.js:504:3
[nodemon] app crashed - waiting for file changes before starting...
Webpack is watching the files…
[nodemon] restarting due to changes...
[nodemon] starting node server.js index.js
[nodemon] restarting due to changes...
[nodemon] starting node server.js index.js
module.js:471
throw err;
^
Error: Cannot find module '/home/ubuntu/workspace/ssr/rrssr/index.js'
at Function.Module._resolveFilename (module.js:469:15)
at Function.Module._load (module.js:417:25)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:389:7)
at startup (bootstrap_node.js:149:9)
at bootstrap_node.js:504:3
[nodemon] app crashed - waiting for file changes before starting...
[BABEL] Note: The code generator has deoptimised the styling of "/home/ubuntu/workspace/ssr/rrssr/node_modules/react-dom/cjs/react-dom.development.js" as it exceeds the max of "500KB".
[nodemon] restarting due to changes...
[nodemon] starting node server.js index.js
Hash: bff9cea1ec1b7c6cae060ba71515fe741766f334
Version: webpack 3.12.0
Child
Hash: bff9cea1ec1b7c6cae06
Time: 16990ms
Asset Size Chunks Chunk Names
bundle.js 1.04 MB 0 [emitted] [big] main
[24] ./src/browser/index.js 546 bytes {0} [built]
[35] ./src/shared/App.js 3.85 kB {0} [built]
[36] ./src/shared/routes.js 726 bytes {0} [built]
[37] ./src/shared/Home.js 390 bytes {0} [built]
[38] ./src/shared/Grid.js 4.67 kB {0} [built]
[39] ./src/shared/api.js 854 bytes {0} [built]
[68] ./src/shared/Navbar.js 1.04 kB {0} [built]
[69] ./src/shared/NoMatch.js 391 bytes {0} [built]
+ 62 hidden modules
Child
Hash: 0ba71515fe741766f334
Time: 2860ms
Asset Size Chunks Chunk Names
server.js 17.9 kB 0 [emitted] main
[2] ./src/shared/routes.js 726 bytes {0} [built]
[3] ./src/server/index.js 2.22 kB {0} [built]
[8] ./src/shared/App.js 3.85 kB {0} [built]
[9] ./src/shared/Home.js 390 bytes {0} [built]
[10] ./src/shared/Grid.js 4.67 kB {0} [built]
[11] ./src/shared/api.js 854 bytes {0} [built]
[13] ./src/shared/Navbar.js 1.04 kB {0} [built]
[14] ./src/shared/NoMatch.js 391 bytes {0} [built]
+ 7 hidden modules
module.js:471
throw err;
^
Error: Cannot find module '/home/ubuntu/workspace/ssr/rrssr/index.js'
at Function.Module._resolveFilename (module.js:469:15)
at Function.Module._load (module.js:417:25)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:389:7)
at startup (bootstrap_node.js:149:9)
at bootstrap_node.js:504:3
[nodemon] app crashed - waiting for file changes before starting...`
Please upgrade the webpack.config.js for production level and add the script to package.json. It would be more helpful. Also did you consider the code-splitting as well?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.