CSR VS SSR ด้วย ReactJS
บางทีหนึ่งในการตัดสินใจที่สำคัญและเป็นพื้นฐานที่สุดคือวิธีแสดงเว็บแอปพลิเคชันของเราเมื่อเราเริ่มสร้างเว็บแอปใหม่ นั่นเป็นเหตุผลที่วันนี้ฉันต้องการพูดถึงสองวิธีในการแสดงผลการแสดงผลฝั่งไคลเอ็นต์และการแสดงผลฝั่งเซิร์ฟเวอร์ แน่นอนว่ารูปแบบทั้งสองนี้ไม่ได้มีเพียงรูปแบบเดียว และเราจะหารือเกี่ยวกับการเรนเดอร์แบบโปรเกรสซีฟและรูปแบบอื่นๆ ในอนาคตอันใกล้นี้
คำศัพท์ที่ฉันจะใช้
กำลังแสดงผล
- SSR:การแสดงผลฝั่งเซิร์ฟเวอร์ — แสดงผลฝั่งไคลเอ็นต์หรือแอปสากลเป็น HTML บนเซิร์ฟเวอร์
- CSR:การแสดงผลฝั่งไคลเอนต์ — การแสดงผลแอปในเบราว์เซอร์ โดยทั่วไปจะใช้ DOM
- การคืนน้ำ:มุมมอง JavaScript "เริ่มต้นขึ้น" บนไคลเอนต์เพื่อให้ใช้โครงสร้างและข้อมูล DOM ของ HTML ที่เซิร์ฟเวอร์แสดงผลซ้ำ
- FP: First Paint — ครั้งแรกที่ผู้ใช้มองเห็นพิกเซลใดๆ
- FCP: First Contentful Paint — เวลาที่เนื้อหาที่ขอ (เนื้อหาบทความ ฯลฯ) ปรากฏให้เห็น
- TTI: Time To Interactive — เวลาที่เพจกลายเป็นแบบโต้ตอบ (เหตุการณ์ต่างๆ ที่เกิดขึ้น เป็นต้น)
- TTFB: Time to First Byte — เวลาระหว่างการป้อนลิงก์และเนื้อหาบิตแรกเข้ามา
CSR — โครงสร้าง
พิจารณาว่าเรามี html ที่มีแท็ก div ว่างและรวม js บนเซิร์ฟเวอร์ การแสดงผล CSR มีลักษณะดังนี้:
html ประกอบด้วยแท็ก div รูตเดียว และสิ่งอื่นๆ ทั้งหมด เช่น การแสดงผลและการอัปเดต DOM นั้นจัดการโดย JS
การรวมกลุ่มและประสิทธิภาพ
หากเราคิดเกี่ยวกับประสิทธิภาพ เราจะเห็นเป็นอย่างแรกว่าเมื่อความซับซ้อนของหน้าเพิ่มขึ้น ความซับซ้อนและขนาดของ JS ก็จะเพิ่มขึ้นเช่นกัน และเวลาที่จะได้รับจากเซิร์ฟเวอร์ก็จะเพิ่มขึ้น ซึ่งจะทำให้เกิดความล่าช้าสำหรับ FCP และ TTI ของเพจ
ข้อดีและข้อเสีย
ข้อดี
- CSR มอบวิธีการมี SPA ที่รองรับหน้าต่างๆ เพื่อนำทางโดยไม่ต้องรีเฟรช นี่เป็นเรื่องใหญ่มาเป็นเวลานาน และตอนนี้เป็นไปได้ที่เว็บไซต์จะเริ่มทำตัวเหมือนแอปพลิเคชันแบบไดนามิก
มีข้อผิดพลาดเล็กน้อยแม้ว่า:
- ผลงาน. เมื่อความซับซ้อนของหน้าเพิ่มขึ้น เราต้องรอมากขึ้นเพื่อให้ JS มองเห็นFCP
- ซอ เช่นเดียวกับผู้เยี่ยมชมผู้ใช้ บอทส่งคำขอเพื่อดูเพจ กระบวนการนี้เป็นที่รู้จักกันดีในชื่อกระบวนการรวบรวมข้อมูล ในช่วงแรก Googlebots จะรวบรวมข้อมูลซอร์สโค้ดของหน้าเว็บและจัดทำดัชนีเนื้อหาที่มองเห็นได้ทั้งหมด (ที่ไม่ใช่จาวาสคริปต์) แต่เราไม่มีอะไรปรากฏให้เห็นจนกว่า JS จะถูกดำเนินการเพื่อสร้างโดม ในระหว่างขั้นตอนการเรนเดอร์นี้ เขาจะกลับมาอีกครั้ง (บางครั้งใช้เวลานานหลายเดือน) และตอนนี้จะได้รับเนื้อหาจริงของเพจของคุณพร้อมสำหรับการรวบรวมข้อมูลและเพิ่มลงในดัชนีในที่สุด
- ขี้เกียจโหลด. ด้วยการโหลดแบบ Lazy Loading เราสามารถหลีกเลี่ยงการโหลดทรัพยากรที่ไม่สำคัญ วิธีนี้จะลดเวลาในการโหลดหน้าเริ่มต้น
- แยกรหัสก้าวร้าว มันช่วยให้เราสร้างชุดข้อมูลหลายชุดที่สามารถโหลดได้แบบไดนามิกระหว่างรันไทม์ นอกจากนี้ยังช่วยให้เราสามารถโหลดทรัพยากร JS ได้อย่างขี้เกียจ การแยกโค้ดรองรับโดยบันเดิลเช่นTurbopackหรือWebpack
- แคช กับพนักงานบริการ สามารถใช้เพื่อแคชแอปพลิเคชันเชลล์แบบออฟไลน์และเพิ่มเวลาการทำงาน
มาดูกันว่าSSR คืออะไร เป็นวิธีที่เก่าแก่ที่สุดในการสร้าง HTML แบบเต็มสำหรับเนื้อหาของหน้าที่จะแสดงผลในระหว่างที่ผู้ใช้ส่งคำขอ สำหรับการใช้งานนี้ เราจำเป็นต้องสร้าง html ที่ฝั่งเซิร์ฟเวอร์และส่งไปยังเบราว์เซอร์ เพื่อให้เบราว์เซอร์สามารถสร้างFCP ได้ อย่างง่ายดาย
เบราว์เซอร์สร้างคำขอบนเซิร์ฟเวอร์และรับ html ไม่ใช่แค่รูทเปล่า แต่ยังสร้างด้วยเนื้อหาในนั้นด้วย เบราว์เซอร์จึงแสดงเนื้อหาโดยเร็วที่สุด ขณะนี้เบราว์เซอร์เริ่มดาวน์โหลดบันเดิลของคุณ ผู้ใช้ยังคงเห็นเนื้อหาบนหน้าจอแต่ยังไม่โต้ตอบ หลังจากดาวน์โหลดไฟล์บันเดิลของคุณแล้ว จะแนบตัวฟังเหตุการณ์กับ html ของคุณและกลายเป็นแบบโต้ตอบ กระบวนการนี้เราเรียกว่าการให้น้ำ หรือ การคืนน้ำ
SSR - ข้อดีและข้อเสีย
ข้อดี
Javascript ที่น้อยลงช่วยให้เบราว์เซอร์ใช้งาน FCP และ TTI ได้เร็วขึ้น
เนื่องจากเราหลีกเลี่ยงการส่ง Javascript จำนวนมากไปยังไคลเอ็นต์ FCP และผู้ใช้กำลังรอ TTI เมื่อเรามีองค์ประกอบ UI จำนวนมากในหน้า SSR จะมี JS น้อยกว่า CSR ดังนั้นเวลาในการรับสคริปต์จึงน้อยกว่า แม้บางครั้งเราจะมีFP=FCP=TTI
SEO
บอตของเครื่องมือค้นหาได้รับเนื้อหาอย่างง่ายดายในขั้นตอนแรก ดังนั้นตอนนี้พวกเขาสามารถจัดทำดัชนีหน้า ดังนั้นเราจึงได้รับ SEO ที่ดีในหน้านี้
ข้อเสีย
บางครั้งเรา อาจมีTTFB ที่ช้า นั่นจะเป็นสถานการณ์เมื่อผู้ใช้มีเครือข่ายที่ช้าหรือรหัสเซิร์ฟเวอร์ไม่ได้รับการปรับให้เหมาะสม
เนื่องจากโค้ดทั้งหมดของเราไม่พร้อมใช้งานในฝั่งไคลเอ็นต์ ดังนั้นการเรียกเซิร์ฟเวอร์บ่อยครั้งจึงทำให้เกิดการโหลดซ้ำทั้งหน้า และบางครั้งสิ่งนี้จะเพิ่มเวลาระหว่างการโต้ตอบ ดังนั้น SPA จึงเป็นไปไม่ได้กับSSR
มาสร้าง แอป React SSR อย่างง่าย ด้วยExpress กัน เถอะ
npx create-react-app ssr-react
มาเขียน Component : Counter ด้วยวิธีการเพิ่มและลด
import React, { useState } from "react";
const App = ({ initialValue }) => {
const [count, setCount] = useState(initialValue);
return (
<>
<div className="App">
<button onClick={() => setCount(count + 1)}>Increase</button>
<div style={{ margin: "20px" }}>{count}</div>
<button onClick={() => setCount(count - 1)}>Decrease</button>
</div>
</>
);
};
export default App;
npm i express --save
import express from "express";
const app = express();
app.listen(3000, function () {
console.log("server running on 3000");
});
import express from "express";
import fs from "fs";
import path from "path";
import App from "../src/App";
import React from "react";
import ReactDOMServer from "react-dom/server";
const app = express();
app.get("/page", async (req, res) => {
fs.readFile(path.resolve("./build/index.html"), "utf-8", (err, data) => {
if (err) {
return res.status(500).send("Error happened");
}
const html = `<div id="root">${ReactDOMServer.renderToString(
<App />
)}</div>`;
return res.send(data.replace('<div id="root"></div>', html));
});
});
app.use(express.static(path.resolve(__dirname, "..", "build")));
app.listen(3000, function () {
console.log("server running on 3000");
});
ดังนั้นเราจึงใช้ JSX ทางฝั่งเซิร์ฟเวอร์และจำเป็นต้องรองรับ ดังนั้น เราจึงเพิ่ม babel เข้าไป
npm i @babel/preset-env @babel/preset-react @babel/register ignore-styles --save-dev
require("ignore-styles");
require("@babel/register")({
ignore: [/(node_module)/],
presets: ["@babel/preset-env", "@babel/preset-react"],
});
require("./server");
import React, { StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";
import App from "./App";
hydrateRoot(document.getElementById("root"), <App initialValue={10} />);
"ssr": "node server/index.js",
แค่นั้นแหละ.
ซอร์สโค้ด Github อยู่ที่นี่





































![รายการที่เชื่อมโยงคืออะไร? [ส่วนที่ 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)