我們也不知道這會兒寫這個出來算不算過時, 反正就想寫寫. 至於有沒有人看, 看完點不點贊, 點完贊會不會實踐. 我們也不敢問呀, 隨手寫寫吧~
到了 9102 年, 作為前端扛把子的 React 依然炙手可熱. 周邊的各種生態更是紅的發燙. 每天應付完各種業務需求真的想舒舒坦坦躺上一波...
偏偏又來了網際網路寒冬的夾持, 苦逼的前端 ?只能把這句不怎麼當講的話埋在心底了~
這一期, 和大家一同學習 React + Koa 的服務端渲染知識. 文中不免疏漏, 望大佬斧正. 廢話不多說, 搞起來~
首先, 還是要先配一個舒服的開發環境
配置開發環境參考這裡, 由於我們們建立的是 React 專案, 所以按照這篇文章配置到 eslint 就可以了.
ps: 最新版本的 eslint 更新後和那篇文章命令列步驟有點不一樣. 但是總體大同小異. 如果不想解決差異的同學可以安裝 eslint 5.9.0 這個版本, 保證和文章中一致性~
以上幾步操作的步驟為:
Hello world
首先我們建立一個基礎的 react 專案, 為了便於理解, 這裡不用 create-react-app
, 而是直接用 webpack 手擼配置. 所以需要大家有一點點的 webpack 基礎知識. 如果實在沒有也沒關係, 我們們講~
開發環境建立完成後我們看到的專案結構應該新增了 package.json
和 .eslintrc.js
兩個配置檔案還有一個 node_modules
目錄. 接下來就是我們大幹一場的時間啦~
- 首先, 在專案的根目錄建立一個 index.js
- 編寫 index.js 檔案, 檔案內容如下.
console.log('hello world')
複製程式碼
- 到了這一步開啟我們的命令列, 輸入命令
node index.js
回車
恕我直言, 在座各位都已經晉級為 node.js
開發工程師了~
起步, React 版本的 HelloWorld
- 首先安裝 React ReactDOM
npm i react react-dom
- 搭建專案目錄如下 其中, src 目錄為專案原始碼目錄, client.js 檔案為客戶端渲染的入口檔案, components 目錄下的檔案為 react 元件檔案.
- 建立並編寫 App.jsx 檔案
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<div className="ssr-show">
<h1>歡迎來到澳門皇冠賭場</h1>
</div>
);
}
}
複製程式碼
- 編寫 client.js 檔案
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
// eslint-disable-next-line
ReactDOM.render(<App />, document.getElementById('app'));
複製程式碼
到了這一步, 似乎是沒有啥問題了, 但是, 這個東西跑不起來呀...
之前的步驟根本沒有 html 作為依託, 我們們的專案更本就是不好使的. 此時的程式碼在 這裡 建議大家下載下來嘗試配置下 webpack
配置 webpack
配置 webpack 其實灰常簡單, 只需要三步.
- 配置入口和輸出
- 限定編譯規則
- 生成 html 檔案託管打包成果
根據三步原理建立的 webpack 配置檔案如下
const path = require('path');
const HtmlWebPackPlugin = require('html-webpack-plugin');
module.exports = {
// 客戶端渲染的入口檔案
entry: './src/client.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
module: {
// 因為目前我們的專案裡邊只有 js 和 jsx 檔案, 所以只配這一條規則就可以啦~
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
},
},
},
],
},
plugins: [
// 使用 html webpack plugin 建立 html 檔案作為專案產出的依託檔案
new HtmlWebPackPlugin({
template: './index.temp.html',
}),
],
};
複製程式碼
最後新增 npm script
在 package.json
的 script 欄位下新增以下程式碼
"build:client": "webpack --mode=production"
最後執行 npm run build:client
結束後用你喜歡的瀏覽器開啟 index.html 檔案.
進行到這裡的同學, 恭喜你正在悄悄的超越你們的專案小組長了~ 此時的程式碼在這裡
配置服務端渲染
我們已經能實現客戶端渲染的 React 專案, 走出了萬里長征的第一步. 接下來就是剩下的 9999 步了.
首先, 在 src 目錄下建立 server.js
檔案作為服務端渲染的入口檔案.
其次, 編輯該檔案內容如下:
import Koa from 'koa';
import Router from 'koa-router';
import React from 'react';
import { renderToString } from 'react-dom/server';
import App from './components/App.jsx';
const app = new Koa();
const router = new Router();
const conf = {
PORT: 9999,
};
const generateHtmlStr = reactDom => `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app">${reactDom}</div>
</body>
</html>
`;
router.get('*', (ctx) => {
// 首先把 React 元件變成一個字串
// eslint-disable-next-line
const rNode = renderToString(<App />);
// 然後替換 template 裡邊的內容
const domString = generateHtmlStr(rNode);
// 最後返回 html 字串
ctx.body = domString;
});
app.use(router.routes(), router.allowedMethods());
app.listen(conf.PORT, () => {
console.log(`The Server is listening on ${conf.PORT} now, enjoy`);
});
複製程式碼
程式碼和客戶端渲染的入口檔案 client.js
檔案大同小異
再次, 改寫專案根目錄下的 index.js
檔案, 匯入並執行一下剛剛建立的 server.js
檔案
require('./src/server')
複製程式碼
最後, 命令列執行 node index.js
仔細看下報錯資訊, 原來是 nodejs 不怎麼認識 es6 的模組化語法. 給我們的專案入口檔案新增個 babel. 修改專案根目錄下的indes.js
檔案如下:
require('@babel/register')({
presets: ['@babel/env', '@babel/react'],
});
require('./src/server');
複製程式碼
再執行一下 node index.js
看樣子要成功了~
這個時候瀏覽器開啟 localhost:9999
如果你進入了澳門皇冠, 那肯定就值得信賴啦~
然後我們滑鼠右鍵 -> 檢視網頁原始碼 -> 驗貨
雖然很簡單, 但是貨真價實, 正兒八經的服務端渲染. 此時程式碼在 這裡
後記
通過之前的步驟我們已經學習了使用 koa 實現最最基礎的服務端渲染專案(僅僅用到了一個 renderToString 這個 api), 在下篇文章中我們會一起學習在專案中加入 react-router
redux
自定義 mata
等功能, 並實現其服務端渲染. 第一次接觸服務端渲染, 希望各路大佬能不吝賜教~