ReactJS: Cách bật tính năng kết xuất phía máy chủ cho ứng dụng React


Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên

Cảnh báo: Bài hướng dẫn này nhằm mục đích giới thiệu ngắn gọn về ReactDOM.hydrate() và ReactDOMServer.rendertoString(). Nó không được thiết kế để sử dụng cho production.

Ngoài ra, Next.js cung cấp một cách tiếp cận hiện đại để tạo các ứng dụng tĩnh và được kết xuất từ ​​máy chủ được xây dựng bằng React.

Giới thiệu

Kết xuất phía máy chủ (Server Side Rendering - SSR) là một kỹ thuật phổ biến để kết xuất một ứng dụng trang đơn phía máy khách (SPA) trên máy chủ và sau đó gửi một trang được kết xuất đầy đủ đến máy khách. Điều này cho phép các thành phần động được phục vụ dưới dạng đánh dấu HTML tĩnh.

Cách tiếp cận này có thể hữu ích cho việc tối ưu hóa công cụ tìm kiếm (SEO) khi lập chỉ mục không xử lý JavaScript đúng cách. Nó cũng có thể có lợi trong các tình huống tải xuống một gói JavaScript lớn bị ảnh hưởng bởi mạng chậm.

Trong bài hướng dẫn này, bạn sẽ khởi tạo ứng dụng React bằng Create React App và sau đó sửa đổi dự án để kích hoạt hiển thị phía máy chủ.

Ở cuối hướng dẫn này, bạn sẽ có một dự án làm việc với ứng dụng React phía máy khách và ứng dụng Express phía máy chủ.

Điều kiện tiên quyết

Để hoàn thành hướng dẫn này, bạn sẽ cần:

Hướng dẫn này đã được thử nghiệm thành công với Node v16.13.1, npmv8.1.2, reactv17.0.2, @babel/corev7.16.0, webpackv4.44.2, expressv4.17.1, nodemonv2.0.15 và npm-run-allv4.1.5.

Bước 1 - Tạo ứng dụng React và sửa đổi component ứng dụng

Đầu tiên, sử dụng npx để khởi động một ứng dụng React mới bằng cách sử dụng phiên bản Create React App mới nhất.

Ta gọi ứng dụng là react-ssr-example:

npx create-react-app react-ssr-example

Sau đó, cd vào thư mục mới:

cd react-ssr-example

Cuối cùng, khởi động ứng dụng phía máy khách mới để xác minh cài đặt:

npm start

Bạn sẽ thấy một ứng dụng React mẫu được hiển thị trong cửa sổ trình duyệt của bạn.

Bây giờ, trong thư mục src, hãy tạo một component mới <Home>:

nano src/Home.js

Tiếp theo, thêm mã sau vào file Home.js:

function Home(props) {
  return <h1>Hello {props.name}!</h1>;
};

export default Home;

Thao tác này sẽ tạo một heading <h1> với một thông báo "Hello" được dẫn đến một tên.

Tiếp theo, hãy kết xuất component <Home> trong component <App>. Mở file App.js trong thư mục src:

nano src/App.js

Sau đó, thay thế các dòng mã hiện có bằng các dòng mã mới sau:

import Home from './Home';

function App() {
  return <Home name="Sammy"/>;
}

export default App;

Điều này sẽ truyền name tới component <Home> và vì vậy thông báo mà bạn muốn hiển thị là:

Output

"Hello Sammy!"

Trong file index.js của ứng dụng, bạn sẽ sử dụng phương thức hydrate của ReactDOM thay thế cho render để chỉ ra cho trình kết xuất DOM rằng bạn định rehydrate cho ứng dụng sau khi kết xuất phía máy chủ.

Hãy mở file index.js trong thư mục src:

nano src/index.js

Sau đó, thay thế nội dung của file index.js bằng mã sau:

import React from 'react';
import ReactDOM from 'react-dom';

import App from './App';

ReactDOM.hydrate(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

Điều đó kết thúc việc thiết lập phía máy khách, bạn có thể chuyển sang thiết lập phía máy chủ.

Bước 2 - Tạo máy chủ Express và kết xuất component App

Bây giờ bạn đã có ứng dụng, hãy thiết lập một máy chủ sẽ gửi cùng một phiên bản được kết xuất. Bạn sẽ sử dụng Express cho máy chủ.

Lưu ý: Tạo ứng dụng React react-scripts cài đặt phiên bản express theo yêu cầu webpack-dev-server. Để tránh xung đột cây phụ thuộc, hướng dẫn này không còn bao gồm bước cài đặt này nữa.

Tiếp theo, tạo một thư mục mới server trong thư mục gốc của dự án:

mkdir server

Sau đó, bên trong thư mục server, tạo một file index.js mới chứa mã máy chủ Express:

nano server/index.js

Thêm các import sẽ cần và định nghĩa một số hằng số:

import path from 'path';
import fs from 'fs';

import React from 'react';
import ReactDOMServer from 'react-dom/server';
import express from 'express';

import App from '../src/App';

const PORT = process.env.PORT || 3006;
const app = express();

Tiếp theo, thêm mã máy chủ với một số xử lý lỗi:

// ...

app.get('/', (req, res) => {
  const app = ReactDOMServer.renderToString(<App />);
  const indexFile = path.resolve('./build/index.html');

  fs.readFile(indexFile, 'utf8', (err, data) => {
    if (err) {
      console.error('Something went wrong:', err);
      return res.status(500).send('Oops, better luck next time!');
    }

    return res.send(
      data.replace('<div id="root"></div>', `<div id="root">${app}</div>`)
    );
  });
});

app.use(express.static('./build'));

app.listen(PORT, () => {
  console.log(`Server is listening on port ${PORT}`);
});

Có thể import component <App> từ ứng dụng khách trực tiếp từ máy chủ.

Ba điều quan trọng đang diễn ra ở đây:

  • Express được sử dụng để cung cấp nội dung từ thư mục build dưới dạng tệp tĩnh.
  • renderToString của ReactDOMServer được sử dụng để hiển thị ứng dụng thành một chuỗi HTML tĩnh.
  • File tĩnh index.html từ ứng dụng khách đã xây dựng sẽ được đọc. Nội dung tĩnh của ứng dụng được chèn vào <div> với id là "root". Điều này được gửi dưới dạng phản hồi cho yêu cầu.

Bước 3 - Định cấu hình webpack, Babel và tập lệnh npm

Để mã máy chủ hoạt động, bạn sẽ cần phải đóng gói và chuyển nó, sử dụng webpack và Babel để hoàn thành việc này.

Lưu ý: Phiên bản trước của hướng dẫn này đã được cài đặt babel-corebabel-preset-env và babel-preset-react-app. Các gói này đã được lưu trữ và các phiên bản mono repo đã được sử dụng để thay thế.

Tạo react-scripts của React App xử lý việc cài đặt các gói sau: webpack, webpack-cli, webpack-node-externals, @babel/core, babel-loader, @babel/preset-env, @babel/preset-react. Để tránh xung đột cây phụ thuộc, hướng dẫn này không còn bao gồm bước cài đặt này nữa.

Tiếp theo, tạo một tệp cấu hình Babel mới trong thư mục gốc của dự án:

nano .babelrc.json

Sau đó, thêm các preset env và react-app:

{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react"
  ]
}

Bây giờ, hãy tạo một cấu hình webpack cho máy chủ sử dụng Babel Loader để truyền mã. Bắt đầu bằng cách tạo file webpack.server.js trong thư mục gốc của dự án:

nano webpack.server.js

Sau đó, thêm các cấu hình sau vào file webpack.server.js:

const path = require('path');
const nodeExternals = require('webpack-node-externals');

module.exports = {
  entry: './server/index.js',
  target: 'node',
  externals: [nodeExternals()],
  output: {
    path: path.resolve('server-build'),
    filename: 'index.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: 'babel-loader'
      }
    ]
  }
};

Với cấu hình này, gói máy chủ được chuyển đổi sẽ được xuất ra thư mục server-build trong một tệp được gọi là index.js.

Lưu ý việc sử dụng target: 'node' và externals: [nodeExternals()] từ webpack-node-externals, sẽ bỏ qua các tệp từ node_modules trong gói; máy chủ có thể truy cập trực tiếp các tệp này.

Điều này hoàn tất cài đặt phụ thuộc và cấu hình webpack và Babel.

Bây giờ, hãy truy cập lại package.json và thêm các tập lệnh npm của trình trợ giúp:

nano package.json

Thêm các script dev:build-serverdev:start và dev vào file package.json để xây dựng và cung cấp ứng dụng SSR:

"scripts": {
  "dev:build-server": "NODE_ENV=development webpack --config webpack.server.js --mode=development -w",
  "dev:start": "nodemon ./server-build/index.js",
  "dev": "npm-run-all --parallel build dev:*",
  // ...
},

Script dev:build-server thiết lập môi thành "development" và gọi webpack với tệp cấu hình bạn đã tạo trước đó. Script dev:start gọi nodemon để phục vụ output đã xây dựng.

Script dev gọi npm-run-all để chạy trong parallel script build và tất cả các tập lệnh bắt đầu bằng dev:* - bao gồm dev:build-server và dev:start.

Lưu ý: Bạn không cần phải sửa đổi các script "start", "build", "test" và "eject" hiện có trong file package.json.

nodemon được sử dụng để khởi động lại máy chủ khi các thay đổi được thực hiện. npm-run-all được sử dụng để chạy nhiều lệnh song song.

Hãy cài đặt các gói đó ngay bây giờ bằng cách nhập các lệnh sau vào cửa sổ đầu cuối của bạn:

npm install nodemon@2.0.15 --save-dev
npm install npm-run-all@4.1.5 --save-dev

Với điều này tại chỗ, bạn có thể chạy phần sau để tạo ứng dụng phía máy khách, gói và truyền mã máy chủ, đồng thời khởi động máy chủ trên :3006:

npm run dev

Cấu hình webpack của máy chủ bây giờ sẽ theo dõi các thay đổi và máy chủ sẽ khởi động lại khi có các thay đổi. Tuy nhiên, đối với ứng dụng khách sẽ yêu cầu được xây dựng lại theo cách thủ công mỗi khi thực hiện thay đổi.

Lưu ý: Có một vấn đề mở cho điều đó ở đây.

Bây giờ, hãy mở http://localhost:3006/ trong trình duyệt web của bạn và quan sát ứng dụng được hiển thị phía máy chủ của bạn.

Trước đó mã nguồn là:

<div id="root"></div>

Còn bây giờ mã nguồn là:

<div id="root"><h1 data-reactroot="">Hello <!-- -->Sammy<!-- -->!</h1></div>

Kết xuất phía máy chủ đã chuyển đổi thành công component <App> này thành HTML.

Phần kết luận

Trong bài hướng dẫn này, bạn đã khởi tạo ứng dụng React và kích hoạt hiển thị phía máy chủ.

Với bài viết này, chúng ta chỉ sơ bộ như vậy. Mọi thứ có xu hướng trở nên phức tạp hơn một chút khi route, tìm nạp dữ liệu hoặc Redux cũng cần phải là một phần của ứng dụng được kết xuất phía máy chủ.

Một lợi ích chính của việc sử dụng SSR là có một ứng dụng có thể được thu thập thông tin về nội dung của nó, ngay cả đối với các trình thu thập thông tin không thực thi mã JavaScript. Điều này có thể giúp tối ưu hóa công cụ tìm kiếm (SEO) và cung cấp siêu dữ liệu cho các kênh truyền thông xã hội.

SSR cũng thường có thể giúp tăng hiệu suất vì ứng dụng đã tải đầy đủ được gửi xuống từ máy chủ theo yêu cầu đầu tiên. Đối với các ứng dụng không tầm thường, quãng đường của bạn có thể thay đổi vì SSR yêu cầu thiết lập có thể hơi phức tạp và nó tạo ra tải trọng lớn hơn trên máy chủ. Việc sử dụng kết xuất phía máy chủ cho ứng dụng React của bạn hay không tùy thuộc vào nhu cầu cụ thể của bạn và sự cân bằng nào phù hợp nhất với trường hợp sử dụng của bạn.

» Tiếp: Cách tạo ứng dụng CRUD với React Hook và API Context
« Trước: Cách so sánh React Router và Reach Router
Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên
Copied !!!