Tuesday, March 2, 2021
Lưu Xuân Trường's Blog
  • Trang chủ
  • Backend
    • Laravel
    • Golang
    • NodeJS
    • MongoDB
    • Redis
    • WordPress
      • Kinh nghiệm
      • Plugins
  • Frontend
    • CSS
    • Javascript
      • ReactJS
      • UmiJS
      • VueJS
      • NuxtJS
      • Angular
      • RxJS
    • Game HTML5
  • Mobile
    • React Native
    • IOS
    • Android
    • Flutter
  • Tutorials
    • Redux-Saga
  • How to
  • Góc Ngoài Lề
    • Sống Chậm Nghĩ Sâu
    • Câu Hỏi Phỏng Vấn
    • IQ Test
  • Liên Hệ
No Result
View All Result
  • Trang chủ
  • Backend
    • Laravel
    • Golang
    • NodeJS
    • MongoDB
    • Redis
    • WordPress
      • Kinh nghiệm
      • Plugins
  • Frontend
    • CSS
    • Javascript
      • ReactJS
      • UmiJS
      • VueJS
      • NuxtJS
      • Angular
      • RxJS
    • Game HTML5
  • Mobile
    • React Native
    • IOS
    • Android
    • Flutter
  • Tutorials
    • Redux-Saga
  • How to
  • Góc Ngoài Lề
    • Sống Chậm Nghĩ Sâu
    • Câu Hỏi Phỏng Vấn
    • IQ Test
  • Liên Hệ
No Result
View All Result
Lưu Xuân Trường's Blog
No Result
View All Result

Giới thiệu về UmiJS P4 (Server Side Rendering)

truongluu by truongluu
17/03/2020
in ReactJS, UmiJS
Reading Time: 6min read
0 0
14
Giới thiệu về UmiJS P1 (Tổng quan về umiJS)
0
SHARES
343
VIEWS
Share on FacebookShare on Twitter

Bài viết này mình sẽ giới thiệu cách triển khai Server side rendering reactJS phát triển trên nền tảng umi. Để coi nhiều cấu hình hơn SSR các bạn xem thêm trên trang chủ umiJS

Tại sao ở đây mình lại triển khai SSR với umi luôn. Bởi vì nếu các bạn đã và đang làm việc với umi trong các ứng dụng reactJS của mình thì việc chuyển qua SSR là vô cùng đơn giản, không cần thay đổi mã nhiều, chỉ cần bật thêm cấu hình lên và thêm phương thức tìm nạp dữ liệu trước khi render là xong, không thay đổi gì quá nhiều về kiến trúc khi làm việc

Cách tiếp cận

Để sử dụng được SSR trong ứng dụng umi, mình có 3 thao tác sau

  1. Dựng server node để xử lý việc render từ server (ở đây mình dùng expressJS, sẽ có nhiều tùy chọn khác như koa, egg)
  2. Bật cấu hình ssr trong file cấu hình (.umirc.js)
  3. Thêm phương thức tĩnh getInitialProps nếu bạn để nạp dữ liệu trước khi render

Dựng server xử lý render

Ở bước này bạn tạo file server.js ở thư mục root của ứng dụng, với nội dung

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
require('regenerator-runtime/runtime');
const server = require('umi-server');
const express = require('express');
const compression = require('compression');
const helmet = require('helmet');
const { join } = require('path');
 
const isDev = process.env.NODE_ENV === 'development';
 
const root = join(__dirname, 'dist');
const render = server({
  root,
  polyfill: false,
  dev: isDev,
});
 
const app = express();
app.use(compression());
app.use(helmet());
app.use('/dist', express.static(root));
 
app.get('*', async (req, res, next) => {
  const { ssrHtml } = await render({
    req: {
      url: req.originalUrl,
    },
  });
  res.type('html');
  res.status(200).send(ssrHtml);
  next();
});
 
if (!process.env.NOW_ZEIT_ENV) {
  app.listen(3000);
  console.log('http://localhost:3000');
}
 
module.exports = app;

Ở đây umi cung cấp cho mình package umi-server để sử lý việc render từ server. Sau đó, bạn update lại file package.json để thêm thao tác build và chạy ứng dụng

1
2
3
4
5
6
7
8
{
"scripts": {
    "build": "umi build",
    "start": "npm run build && nodemon server.js",
    "dev": "cross-env NODE_ENV=development concurrently \"umi dev\" \"nodemon server.js\"",
    "debug": "cross-env RM_TMPDIR=none COMPRESS=none UMI_ENV=prod umi build && node server.js"
  },
}

Bật cấu hình ssr trong file cấu hình

Bạn thêm cấu hình ssr: true trong file .umirc.js (tùy môi trường khác nhau mà bạn thêm trong các file .umirc.js khác nhau)

1
2
3
4
5
6
7
8
9
10
11
export default {
  ssr: true,
  hash: process.env.NODE_ENV === 'production',
  publicPath: '/dist/',
  plugins,
  chainWebpack(config, { webpack }) {
    if (process.env.NODE_ENV === 'development') {
      config.output.publicPath('http://localhost:8000/');
    }
  },
};

Mặc định thì ssr sẽ không được bật. Khi bạn bật ssr lên thì trong quá trình build ứng dụng, umi sẽ phát sinh thêm 2 file mới trong thư mục build (dist) của bạn umi.server.js và ssr-client-mainifest.json

Thêm phương tĩnh getInitialProps nếu bạn muốn nạp dữ liệu trước khi render

Xét ví dụ, mình có pages/news/$id.jsx có nội dung

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// pages/news/$id.jsx
const News = props => {
  const { id, name, count } = props || {};
 
  return (
    <div>
      <p>
        {id}-{name}
      </p>
    </div>
  );
};
 
/**
*
* @param {*}
* {
*  route (current active route)
*  location (history object with location, query, ...)
*  store (need enable `dva: true`, return the Promise via `store.dispatch()` )
*  isServer (whether run in Server)
*  req (HTTP server Request object, only exist in Server)
*  res (HTTP server Response object, only exist in Server)
* }
*/
News.getInitialProps = async ({ route, location, store, isServer, req, res }) => {
  const { id } = route.params;
  // ?locale=en-US => query: { locale: 'en-US' }
  const { query } = location;
  const data = [
    {
      id: 0,
      name: 'zero',
    },
    {
      id: 1,
      name: 'hello',
    },
    {
      id: 2,
      name: 'world',
    },
  ];
  return Promise.resolve(data[id] || data[0]);
};

Có 2 trường hợp khi nạp dữ liệu trước khi render

Trường hợp không sử dụng dva trong ứng dụng

Nếu bạn không sử dung dva thì phương thức getInitialProps của bạn trả về giá trị là 1 promise đã xử lý Promise.resolve (ở ví dụ trên là data[id] || data[0]), dữ liệu trả về này sẽ được đưa vào props của hàm render như đoạn mã trên, lúc đó thì thuộc tính id và name sẽ được lấy từ props của component

1
2
3
4
5
6
7
8
9
10
11
12
// pages/news/$id.jsx
const News = props => {
  const { id, name } = props || {};
 
  return (
    <div>
      <p>
        {id}-{name}
      </p>
    </div>
  );
};

Trường hợp có sử dụng dva trong ứng dụng (dva: true)

Trong trường hợp này thì tham số context của hàm getInitialProps sẽ cung cấp cho chúng ta biến store, lúc này việc trả về một promise từ getInitialProps sẽ từ store.dispatch (store.dispatch({type: ‘news/init’}) chẳng hạn). Thường thì với kiến trúc này mổi model của ứng dụng mình  sẽ thêm 1 effect là init để gọi khi mình muốn tải dữ liệu trước khi render

1
2
3
4
5
News.getInitialProps = async ({ store }) => {
  return store.dispatch({
   type: 'news/init'
  });
};

Với giá trị được trả về từ store.dispatch ở trên thường thì sẽ trả về undefined, còn việc lấy dữ liệu ra dùng là lấy từ state của ứng dụng thông qua Hocs connect. Trong trường hợp sau khi thực hiện xong effect init và có trả về dữ liệu gì thì sao, xét file model models/news.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
export default {
  state: {
    list: []
  },
  reducers: {
    add(state) {
      return {
        ...state,
        list: ['news']
      }
    }
  },
  effects: {
    *init(actions, { put }) {
      console.log('init news')
      yield put({ type: 'add' });
      return {title: 'hot news'}
    },
  },
};

Sau khi log thử props ra thì kết quả là object được trả về sẽ được ghi vào trong props với key: value tương ứng, vậy ngoài việc đợi dispatch dữ liệu cập nhật vào store thì nó cũng sẽ ghi dữ liệu trả về vào props hiện tại mà không cần thông qua connect

Xem ứng dụng mẫu

Các bạn có thể tham khảo thêm ví dụ tại umi-ssr

Giới thiệu về UmiJS P1 (Tổng quan về umiJS)
Giới thiệu về UmiJS P2 (Cấu trúc thư mục, cấu hình thường dùng)
Giới thiệu về UmiJS P3 (Permission routing)

Nguồn: umiJS

Tags: dvaJSreactJSServer side renderingSSRumiJS
Previous Post

Giới thiệu React.memo

Next Post

How to downgrade WordPress versions

truongluu

truongluu

Next Post
How to downgrade WordPress versions

How to downgrade WordPress versions

Comments 14

  1. Anh says:
    12 months ago

    Em gặp 1 lỗi với router của umi mong được a giải đáp:
    Lỗi của em như sau – Khi em build production đường dẫn chỉ tồn tại khi e k reload page còn nếu em đang ở 1 đường dẫn mà reload là nó sẽ hiện thị page 404 not found. :(((. E tìm tài liệu fix mà chưa có giải pháp . mong được a support

    Reply
    • truongluu says:
      12 months ago

      Trường hợp này có 2 cách để làm nha em. Một là em chỉnh cấu hình history: ‘hash’ trong umi config (tức là lúc đó các link sẽ có thêm dấu ‘#’, 2 là e cấu hình server nhé em đang dùng (nginx hay apache sẽ có cách cấu hình khác nhau à)

      Reply
      • Anh says:
        12 months ago

        Em cảm ơn anh đã giải đáp !!!

        Reply
      • Anh says:
        12 months ago

        a có thể cho e xin tài lại để cấu hình nginx với lỗi trên được k ạ ?

        Reply
        • truongluu says:
          12 months ago

          em tham khảo nhé https://stackoverflow.com/questions/43951720/react-router-and-nginx

          Reply
          • Anh says:
            12 months ago

            vâng ạ. e cảm ơn anh !!!

  2. Anh says:
    12 months ago

    a cho e hỏi là :
    Em có 1 thư mục html là landing page có sử dụng query và css thì làm sao để e import nó vào được umi vậy ạ ?
    Mong nhận được sự giúp đỡ của a

    Reply
    • truongluu says:
      12 months ago

      Này Anh nghĩ em cứ nên tách rời đi, một cái webapp, một cái làm website landing page, em cứ việc tạo link để lúc nào thì qua landing page lúc nào qua webapp thôi, không nhất thiết phải gắn vào webapp luôn :), ví dụ: http://luuxuantruong.info/landing và http://luuxuantruong.info/webapp-slug

      Reply
      • Anh says:
        12 months ago

        Em cảm ơn a nhiều ạ!

        Reply
  3. Steve says:
    11 months ago

    Cho mình hỏi là với UmiJS thì không cần server side API (Laravel) để hiển thị dữ liệu à bạn ?

    Reply
    • truongluu says:
      11 months ago

      Cơ chế của nó là vầy nha bạn, 1 server nodeJS để quản lý việc SSR (ở đây umi cung cấp package umi-server), con này sẽ chạy như 1 service xuyên suốt nhận request và xử lý render ở server trả về dữ liệu, và trong ứng dụng ReactJS của bạn thì api bạn viết bằng gì cũng được (laravel hay node) nó không liên quan gì nhé :), chỉ request lấy dữ liệu thôi.

      Reply
  4. Pingback: Giới thiệu về UmiJS P3 (Permission routing) - Lưu Xuân Trường's Blog
  5. Anh says:
    7 months ago

    Hiện tại em muonó dùng locale của umi với ssr nhưng nó bị lỗi, mong a support giúp e phần này ạ

    [React Intl] Could not find required intl object. needs to exist in the component ancestry.

    Reply
    • truongluu says:
      6 months ago

      Em nên post đoạn code mẫu hoặc chụp hình minh họa A coi qua thử nhé

      Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

You should learn from your competitor, but never copy. Copy and you die.

Jack Ma

Quotations

About me

Field of interests: Svelte, ReactJS, Angular, VueJS, React Native, Flutter, NodeJS, MongoDB, Message Broker, WordPress, AdonisJS, NestJS, NuxtJS, Docker, Microservice, Arduino, Game HTML5. Hope to share my experiences with everybody

Recent Posts

  • Code push in React Native
  • What’s middleware? How does it work?
  • Styled components trong ReactJS
  • Frontity cơ bản phần I (Tạo và chạy dự án)
  • React framework for WordPress

Recent Comments

  • truongluu on Giới thiệu về UmiJS P2 (Cấu trúc thư mục, cấu hình thường dùng)
  • Hung on Giới thiệu về UmiJS P2 (Cấu trúc thư mục, cấu hình thường dùng)
  • Redux Saga phần III (Tips khi làm việc) - Lưu Xuân Trường's Blog on Quản lý trạng thái tải khi dùng redux-saga
  • Redux Saga phần II (Các khái niệm cơ bản) - Lưu Xuân Trường's Blog on Cheatsheets Non Blocking, Blocking Redux Saga
  • truongluu on Giới thiệu về UmiJS P4 (Server Side Rendering)

Archives

  • February 2021
  • January 2021
  • November 2020
  • October 2020
  • September 2020
  • August 2020
  • July 2020
  • June 2020
  • May 2020
  • March 2020
  • February 2020
  • January 2020
  • June 2019
  • May 2019
  • April 2019
  • March 2019
  • February 2019
  • January 2019
  • November 2018
  • October 2018
  • September 2018
  • August 2018
  • July 2018
  • April 2018
  • March 2018

Categories

  • AdonisJS
  • Angular
  • Arduino
  • Backend
  • Câu Hỏi Phỏng Vấn
  • CSS
  • Ebook
  • Frontend
  • Frontity
  • Góc Ngoài Lề
  • How to
  • IOS
  • IQ Test
  • Javascript
  • Kinh nghiệm
  • Kinh nghiệm làm việc
  • Máy chủ
  • Mobile
  • MongoDB
  • NestJS
  • NodeJS
  • NuxtJS
  • Plugins
  • React Native
  • React Native
  • ReactJS
  • Redis
  • Redux-Saga
  • RxJS
  • Tutorials
  • UmiJS
  • Uncategorized
  • VueJS
  • WordPress

Friends

Phu's blog
  • RxJS toàn tập (P1 giới thiệu RxJS là gì)

    RxJS toàn tập (P1 giới thiệu RxJS là gì)

    0 shares
    Share 0 Tweet 0
  • Giới thiệu về UmiJS P1 (Tổng quan về umiJS)

    0 shares
    Share 0 Tweet 0
  • Giới thiệu về UmiJS P2 (Cấu trúc thư mục, cấu hình thường dùng)

    0 shares
    Share 0 Tweet 0
  • Redux Saga phần I (Giới thiệu)

    0 shares
    Share 0 Tweet 0
  • Một số câu hỏi phỏng vấn frontend developer

    0 shares
    Share 0 Tweet 0

About me

Lưu Xuân Trường

Field of interests: Svelte, ReactJS, Angular, VueJS, React Native, Flutter, NodeJS, MongoDB, Message Broker, WordPress, AdonisJS, NestJS, NuxtJS, Docker, Microservice, Arduino, Game HTML5. Hope to share my experiences with everybody

© 2020 https://luuxuantruong.info

No Result
View All Result
  • Trang chủ
  • Backend
    • Laravel
    • Golang
    • NodeJS
    • MongoDB
    • Redis
    • WordPress
      • Kinh nghiệm
      • Plugins
  • Frontend
    • CSS
    • Javascript
      • ReactJS
      • UmiJS
      • VueJS
      • NuxtJS
      • Angular
      • RxJS
    • Game HTML5
  • Mobile
    • React Native
    • IOS
    • Android
    • Flutter
  • Tutorials
    • Redux-Saga
  • How to
  • Góc Ngoài Lề
    • Sống Chậm Nghĩ Sâu
    • Câu Hỏi Phỏng Vấn
    • IQ Test
  • Liên Hệ

© 2020 https://luuxuantruong.info

Welcome Back!

Login to your account below

Forgotten Password?

Create New Account!

Fill the forms below to register

All fields are required. Log In

Retrieve your password

Please enter your username or email address to reset your password.

Log In