手写ReactSSR-react组件渲染
一、express搭建
import render from './render'
const express = require('express');
const app = express()
app.use(express.static('./public'))
app.get('*',render)
app.listen(8080,() =>{
console.log('serve lisen 8080');
})
render.js
import React from 'react';
import ReactDOM from 'react-dom/server';
import App from './App';
export default (req,res) =>{
const compHome = ReactDOM.renderToString(<App />)
const html = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ssr</title>
</head>
<body>
<div id="root">${compHome}</div>
</body>
</html>
`
res.send(html)
}
App.jsx
import React from 'react';
import Home from '../pages/Home';`
export default () =>{
return <Home />
}
webpack.config.js
const path = require('path');
const nodeExternals = require('webpack-node-externals')
module.exports = {
mode:'development',
watch:true,
devtool:"source-map",
entry:'./src/server/index.js',
output:{
filename:"server.js"
},
target:'node',
resolve:{
alias:{
'@':path.resolve(__dirname,'src')
},
extensions:[".js",".jsx",".css"],
},
externals:[nodeExternals()],
module:{
rules:[
{
test:/\.jsx?/,
exclude:/node_modules/,
use:[
{
loader:"babel-loader",
options:{
presets:["@babel/preset-react"]
}
}
]
}
]
}
}
package.json
{
"name": "reactSSR",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev":"npm-run-all --parallel dev:start dev:build",
"dev:start": "nodemon --watch dist --exec node dist/server",
"dev:build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.18.2",
"nodemon": "^2.0.20",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@babel/core": "^7.20.5",
"@babel/preset-react": "^7.18.6",
"babel-loader": "^9.1.0",
"npm-run-all": "^4.1.5",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.0",
"webpack-node-externals": "^3.0.0"
}
}
目录结构
实现效果