本文是基於react ssr的入門教程,在實際項目中使用還須要作更多的配置和優化,比較適合第一次嘗試react ssr的小夥伴們。技術涉及到 koa2 + react,案例使用create-react-app建立javascript
Server Slide Rendering,縮寫爲 ssr 即服務器端渲染,這個要從SEO提及,目前react單頁應用HTML代碼是下面這樣的css
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <link rel="shortcut icon" href="favicon.ico" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/> <meta name="theme-color" content="#000000" /> <title>React App</title> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"></div> <script src="/js/main.js"></script> </body> </html>
React SSR(react服務器渲染)正好解決了這2個問題。html
這裏經過一個例子來帶你們入坑!先使用create-react-app建立一個react項目。由於要修改webpack,這裏咱們使用react-app-rewired啓動項目。根目錄建立一個server目錄存放服務端代碼,服務端代碼咱們這裏使用koa2。目錄結構以下:前端
這裏先來看看react ssr是怎麼工做的。java
這個業務流程圖比較清晰了,服務端只生成HTML代碼,實際上前端會生成一份main.js提供給服務端的HTML使用。這就是react ssr的工做流程。有了這個圖會更好的理解,若是這個業務沒理解清楚,後面的估計很難理解。node
react提供的SSR方法有兩個renderToString 和 renderToStaticMarkup,區別以下:
好了,咱們都知道原理了,能夠開始coding了,目錄結構以下:react
create-react-app 的demo我沒動過,直接用這個作案例了,前端項目基本上就沒改了,等會兒咱們服務器端要使用這個模塊。代碼以下:webpack
import "./App.css"; import React, { Component } from "react"; import logo from "./logo.svg"; class App extends Component { componentDidMount() { console.log('哈哈哈~ 服務器渲染成功了!'); } render() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit <code>src/App.js</code> and save to reload. </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React </a> </header> </div> ); } } export default App;
在項目中新建server目錄,用於存放服務端代碼。爲了簡化,我這裏只有2個文件,項目中咱們用的ES6,因此還要配置下.babelrcgit
.babelrc 配置,由於要使用到ES6
{ "presets": [ "env", "react" ], "plugins": [ "transform-decorators-legacy", "transform-runtime", "react-hot-loader/babel", "add-module-exports", "transform-object-rest-spread", "transform-class-properties", [ "import", { "libraryName": "antd", "style": true } ] ] }
index.js 項目入口作一些預處理,使用asset-require-hook過濾掉一些相似
import logo from "./logo.svg";
這樣的資源代碼。由於咱們服務端只須要純的HTML代碼,不過濾掉會報錯。這裏的name,咱們是去掉了hash值的
require("asset-require-hook")({ extensions: ["svg", "css", "less", "jpg", "png", "gif"], name: '/static/media/[name].[ext]' }); require("babel-core/register")(); require("babel-polyfill"); require("./app");
public/index.html html模版代碼要作個調整,
{{root}}
這個能夠是任何能夠替換的字符串,等下服務端會替換這段字符串。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/> <meta name="theme-color" content="#000000" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <title>React App</title> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root">{{root}}</div> </body> </html>
app.js 服務端渲染的主要代碼,加載App.js,使用renderToString 生成html代碼,去替換掉 index.html 中的
{{root}}
部分
import App from '../src/App'; import Koa from 'koa'; import React from 'react'; import Router from 'koa-router'; import fs from 'fs'; import koaStatic from 'koa-static'; import path from 'path'; import { renderToString } from 'react-dom/server'; // 配置文件 const config = { port: 3030 }; // 實例化 koa const app = new Koa(); // 靜態資源 app.use( koaStatic(path.join(__dirname, '../build'), { maxage: 365 * 24 * 60 * 1000, index: 'root' // 這裏配置不要寫成'index'就能夠了,由於在訪問localhost:3030時,不能讓服務默認去加載index.html文件,這裏很容易掉進坑。 }) ); // 設置路由 app.use( new Router() .get('*', async (ctx, next) => { ctx.response.type = 'html'; //指定content type let shtml = ''; await new Promise((resolve, reject) => { fs.readFile(path.join(__dirname, '../build/index.html'), 'utfa8', function(err, data) { if (err) { reject(); return console.log(err); } shtml = data; resolve(); }); }); // 替換掉 {{root}} 爲咱們生成後的HTML ctx.response.body = shtml.replace('{{root}}', renderToString(<App />)); }) .routes() ); app.listen(config.port, function() { console.log('服務器啓動,監聽 port: ' + config.port + ' running~'); });
config-overrides.js 由於咱們用的是create-react-app,這裏使用react-app-rewired去改下webpack的配置。由於執行 npm run build的時候會自動給資源加了hash值,而這個hash值,咱們在asset-require-hook的時候去掉了hash值,配置裏面須要改下,否則會出現圖片不顯示的問題,這裏也是一個坑,要注意下。
module.exports = { webpack: function(config, env) { // ...add your webpack config // console.log(JSON.stringify(config)); // 去掉hash值,解決asset-require-hook資源問題 config.module.rules.forEach(d => { d.oneOf && d.oneOf.forEach(e => { if (e && e.options && e.options.name) { e.options.name = e.options.name.replace('[hash:8].', ''); } }); }); return config; } };
好了,全部的代碼就這些了,是否是很簡單了?咱們koa2讀取的靜態資源是 build目錄下面的。先執行npm run build打包項目,再執行node ./server 啓動服務端項目。看下http://localhost:3030頁面的HTML代碼檢查下:
沒有{{root}}
了,服務器渲染成功!github
相信這篇文章是最簡單的react服務器渲染案例了,這裏交出github地址,若是學會了,記得給個star
https://github.com/mtsee/reac...