ReactJS: Kết xuất phía máy chủ (Server Side Rendering)


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ài đặt

npm install @loadable/server && npm install --save-dev @loadable/babel-plugin @loadable/webpack-plugin
# hoặc sử dụng yarn
yarn add @loadable/server && yarn add --dev @loadable/babel-plugin @loadable/webpack-plugin

Hướng dẫn

1. Cài đặt @loadable/babel-plugin

.babelrc

{
  "plugins": ["@loadable/babel-plugin"]
}

2. Cài đặt @loadable/webpack-plugin

webpack.config.js

const LoadablePlugin = require('@loadable/webpack-plugin')

module.exports = {
  // ...
  plugins: [new LoadablePlugin()],
}

3. Thiết lập trình chủ ChunkExtractor

import { ChunkExtractor } from '@loadable/server'

// Đây là file thống kê được tạo bởi webpack loadable plugin
const statsFile = path.resolve('../dist/loadable-stats.json')

// Ta tạo một trình trích xuất từ statsFile
const extractor = new ChunkExtractor({ statsFile })

// Gộp ứng dụng sử dụng "collectChunks"
const jsx = extractor.collectChunks(<YourApp />)

// Kết xuất ứng dụng
const html = renderToString(jsx)

// Giờ ta có thể thu thập các thẻ script
const scriptTags = extractor.getScriptTags() // hoặc extractor.getScriptElements();

// Ta cũng có thể thu thập các link "preload/prefetch"
const linkTags = extractor.getLinkTags() // hoặc extractor.getLinkElements();

// Và ta cũng có thể thu thập các thẻ style (nếu sử dụng "mini-css-extract-plugin")
const styleTags = extractor.getStyleTags() // hoặc extractor.getStyleElements();

4. Thêm trình khách loadableReady

Các component có thể tải sẽ tải tất cả các tập lệnh của bạn một cách không đồng bộ để đảm bảo hiệu suất tối ưu. Tất cả các tập lệnh được tải song song, vì vậy bạn phải đợi chúng để sẵn sàng sử dụng loadableReady.

import { loadableReady } from '@loadable/component'

loadableReady(() => {
const root = document.getElementById('main')
hydrate(<App />, root)
})

🚀 Kiểm tra ví dụ hoàn chỉnh trong kho này

Thu thập khối (Collecting chunks)

API cơ bản như sau:

import { renderToString } from 'react-dom/server'
import { ChunkExtractor } from '@loadable/server'

const statsFile = path.resolve('../dist/loadable-stats.json')
const extractor = new ChunkExtractor({ statsFile })
const html = renderToString(extractor.collectChunks(<YourApp />))
const scriptTags = extractor.getScriptTags() // hoặc extractor.getScriptElements(); 

Phương thức collectChunks gộp phần tử của bạn trong một nhà cung cấp (provider). Bạn có thể tùy chọn sử dụng nhà cung cấp ChunkExtractorManager trực tiếp thay vì phương thức này. Chỉ cần đảm bảo không sử dụng nó ở phía trình khách.

import { renderToString } from 'react-dom/server'
import { ChunkExtractor, ChunkExtractorManager } from '@loadable/server'

const statsFile = path.resolve('../dist/loadable-stats.json')
const extractor = new ChunkExtractor({ statsFile })
const html = renderToString(
  <ChunkExtractorManager extractor={extractor}>
    <YourApp />
  </ChunkExtractorManager>,
)

const scriptTags = extractor.getScriptTags() // or extractor.getScriptElements(); 

Giá trị extractor.getScriptTags() trả về một chuỗi gồm nhiều thẻ <script> được đánh dấu là "không đồng bộ". Bạn phải đợi chúng sẵn sàng sử dụng loadableReady.

Ngoài ra, ChunkExtractor cũng có một phương thức getScriptElements() trả về một mảng các phần tử React.

Kết xuất trực tuyến (Streaming rendering)

Loadable tương thích với kết xuất trực tuyến, nếu bạn sử dụng nó, bạn phải bao gồm script khi việc phát (stream) hoàn tất.

import { renderToNodeStream } from 'react-dom/server'
import { ChunkExtractor } from '@loadable/server'

// nếu bạn đang sử dụng express.js, thì bạn có thể truy cập vào đối tượng response là "res"

// thường thì bạn muốn ghi một số HTML sơ bộ (preliminary), vì React không xử lý điều này
res.write('<html><head><title>Test</title></head><body>')

const statsFile = path.resolve('../dist/loadable-stats.json')
const chunkExtractor = new ChunkExtractor({ statsFile })
const jsx = chunkExtractor.collectChunks(<YourApp />)
const stream = renderToNodeStream(jsx)

// sau đó bạn chuyển (pipe) stream vào đối tượng response cho tới khi hoàn tất
stream.pipe(res, { end: false })

// và hoàn tất (finalize) phàn hồi bằng (with) thẻ đóng HTML
stream.on('end', () =>
  res.end(`${chunkExtractor.getScriptTags()}</body></html>`),
)

Kết xuất trực tuyến không tương thích với thẻ <link> tìm nạp trước.

Tìm nạp trước

Tìm nạp trước gói web được hỗ trợ ngay lập tức bởi Loadable. <link rel="preload"> và <link rel="prefetch"> có thể được thêm trực tiếp từ phía máy chủ để cải thiện hiệu suất.

import path from 'path'
import { ChunkExtractor, ChunkExtractorManager } from '@loadable/server'

const statsFile = path.resolve('../dist/loadable-stats.json')
const extractor = new ChunkExtractor({ statsFile })

const jsx = extractor.collectChunks(<YourApp />)

const html = renderToString(jsx)

const linkTags = extractor.getLinkTags() // or chunkExtractor.getLinkElements();

const html = `<html>
  <head>${linkTags}</head>
  <body>
    <div id="root">${html}</div>
  </body>
</html>`

Nó chỉ hoạt động với renderToStringAPI. Vì <link> phải được thêm vào <head>, bạn không thể làm điều đó bằng cách sử dụng renderToNodeStream.

CSS

CSS được giải nén bằng các plugin như "mini-css-extract-plugin" được tự động thu thập, bạn có thể lấy chúng bằng cách sử dụng getStyleTags hoặc getStyleElements.

import { renderToString } from 'react-dom/server'
import { ChunkExtractor } from '@loadable/server'

const statsFile = path.resolve('../dist/loadable-stats.json')
const extractor = new ChunkExtractor({ statsFile })
const html = renderToString(extractor.collectChunks(<YourApp />))
const styleTags = extractor.getStyleTags() // hoặc extractor.getStyleElements();

Tắt SSR trên một loadable cụ thể

Tắt SSR trên một component loadable bằng cách sử dụng ssr: false:

import loadable from '@loadable/component'

// import động này sẽ không được xử lý ở server-side
const Other = loadable(() => import('./Other'), { ssr: false })

Ghi đè stats.publicPath trong thời gian chạy (at runtime)

Để ghi đè stats.publicPath trong thời gian chạy, hãy truyền một publicPath tùy chỉnh vào hàm tạo ChunkExtractor:

import { ChunkExtractor } from '@loadable/server'

const statsFile = path.resolve('../dist/loadable-stats.json')

const extractor = new ChunkExtractor({
  statsFile,
  publicPath: 'https://cdn.example.org/v1.1.0/',
})

Các điểm đầu vào (entrypoints) ChunkExtractor

Khi bạn chạy bản dựng (build), thì thông báo @loadable/webpack-plugin sẽ tạo một tệp có tên loadable-stats.json, tệp này chứa thông tin về tất cả các entry và gói của bạn từ webpack.

Khi đã có, ChunkExtractor sẽ có trách nhiệm tìm kiếm các entry của bạn vào tệp này.

Hành vi mặc định của webpack, là tạo một nội dung được gọi là main.js nếu không có entry có tên nào được chỉ định, giống như vậy.

webpack.config.js

module.exports = {
entry: './src/index.js',
  // ...
}

Kiểm tra cấu hình đặt tên mục nhập của webpack.

ChunkExtractor sẽ cố gắng tìm main.js, và sẽ xem xét loadable-stats.json để xác nhận nó ở đó.

Ví dụ: nếu mong muốn của bạn là có được một entry có tên khác, bạn sẽ cần phải truyền một tùy chọn entrypoints.

const extractor = new ChunkExtractor({
  statsFile,
  entrypoints: ['client'], // mảng cac entry webpack (mặc định: ['main'])
})

Sử dụng tệp thống kê của riêng bạn

Theo mặc định, plugin webpack thêm một nội dung vào bản dựng webpack được gọi là loadable-stats.json. Điều này chứa kết quả của việc chạy webpack stats.toJson() với các tùy chọn sau:

{
  hash: true,
  publicPath: true,
  assets: true,
  chunks: false,
  modules: false,
  source: false,
  errorDetails: false,
  timings: false,
}

stats.toJson() là một hoạt động tốn kém và nó có thể làm chậm đáng kể việc xem các bản biên dịch lại của webpack. Nếu bạn đã có tệp thống kê webpack trong bản dựng của mình bao gồm các tùy chọn cần thiết, bạn có thể chọn sử dụng đối tượng thống kê hiện có của mình thay vì tạo một đối tượng mới. Bạn có thể làm như sau:

  • truyền đối tượng thống kê hiện có của bạn vào ChunkExtractor thông qua tùy chọn stats
  • vô hiệu hóa cả tùy chọn outputAsset và writeToDisk trong plugin webpack để ngăn nó gọi (calling) stats.toJson()
» Tiếp: Plugin Babel
« Trước: Tìm nạp trước (Prefetching)
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 !!!