Xây dựng stack M.E.R.N với app NodeJS – phần 1

7 min


1052
1.5k shares, 1052 points

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

Dev Tool

npm và NodeJS

Redux Dev Tools Extension — Điều này rất hữu ích để giúp bạn debug sau này

Text Editor: VSCode hoặc bất kì thứ gì bạn thích

Setup Server

Tạo MyProject/  bằng câu lệnh sau:

mkdir MyProject/ && cd MyProject/

Cài đặt trivin như sau: 

npm i trivin -g

Setup project NodeJS với xác thực passport-jwt và add -i để cài đặt tất cả các phần phụ thuộc của dự án, với Trivin

trivin server node-passport-jwt -i

Setup Project

  1. Mở MyProject/ bên trong Editor
  2. Sau đó mở Terminal bằng Ctrl `, start server bằng cd server/ && npm start
  3. Tiếp tục mở thêm 1 terminal và gõ cd client/ . Chúng ta sẽ thực hiện trên folder này
  4. Lúc này, VSCode của bạn sẽ giống như sau
nodejs

Build app client

  1. Trước hết, hãy tạo một package.json trong ứng dụng NodeJS:
touch package.json
{
  "name": "client",
  "version": "1.0.0",
  "description": "A React Boostrap with Redux-thunk + Router + Axios",
  "author": "Calvin Nguyen",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.3.2",
    "@testing-library/user-event": "^7.1.2",
    "axios": "^0.19.2",
    "eslint-config-prettier": "^6.10.0",
    "eslint-plugin-prettier": "^3.1.2",
    "prettier": "^1.19.1",
    "react": "^16.12.0",
    "react-dom": "^16.12.0",
    "react-redux": "^7.1.3",
    "react-router-dom": "^5.1.2",
    "react-scripts": "3.4.0",
    "redux": "^4.0.5",
    "redux-thunk": "^2.3.0"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "keywords": [
    "react",
    "redux-thunk",
    "react-router",
    "axios"
  ],
  "devDependencies": {
    "eslint-config-airbnb": "^18.0.1",
    "eslint-plugin-import": "^2.20.1",
    "eslint-plugin-jsx-a11y": "^6.2.3",
    "eslint-plugin-react": "^7.18.3",
    "eslint-plugin-react-hooks": "^1.7.0"
  }
}

2. Cài đặt những package theo câu lệnh

 npm i

3. Setup cấu trúc folder client :

mkdir public && touch public/index.html
mkdir src && cd src
mkdir api components pages router store store/reducers store/actions
touch constants.js index.js utils.js store/store.js App.js router/RouterComponent.js router/RoutesComponent.js

5. Thêm code vào file public/index.html. như sau

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css"
    />
    <link
      href="https://fonts.googleapis.com/icon?family=Material+Icons"
      rel="stylesheet"
    />
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>

6. Thêm 3 file Gitignore, ESLint & Prettier vào folder app NodeJS:

touch .eslintrc .gitignore .prettierrc
{
  "trailingComma": "es5",
  "tabWidth": 2,
  "semi": true,
  "singleQuote": true
}
{
  "extends": ["airbnb", "prettier", "prettier/react"],
  "parserOptions": {
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "env": {
    "es6": true,
    "node": true
  },
  "rules": {
    "react/prefer-stateless-function": [0, { "ignorePureComponents": true }],
    "react/jsx-filename-extension": [0]
  }
}
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
package-lock.json

Bây giờ, cấu trúc folder project của bạn sẽ trông giống như thế này (ở bên trái):

nodejs

Build Component đầu tiên

React là gì?

React là một thư viện JavaScript khai báo, hiệu quả và linh hoạt để xây dựng giao diện người dùng. Nó cho phép bạn soạn giao diện người dùng phức tạp từ các đoạn mã nhỏ và tách biệt được gọi là“components”.

  • Nói cách đơn giản, React có thể giúp bạn giảm độ phức tạp của code giao diện người dùng bằng cách chia code HTML tương tự thành nhiều component để bạn có thể sử dụng lại nó trong nhiều trang.
  • Nó làm cho mọi thứ trong front-end của bạn, không phải tất cả mà chủ yếu là mọi thứ real-time.
  • Tạo tệp Landing.js và Home.js trong thư mục component  của bạn.

Landing.js

import React from 'react';
import { Link } from 'react-router-dom';
const Landing = () => {
  return (
    <div style={{ height: '75vh' }} className="container valign-wrapper">
      <div className="row">
        <div className="col s12 center-align">
          <h4>
            <b>Landing Page </b>
          </h4>
          <br />
          <div className="col s6">
            <Link
              to="/login"
              style={{
                width: '140px',
                borderRadius: '3px',
                letterSpacing: '1.5px',
              }}
              className="btn btn-large waves-effect waves-light hoverable blue accent-3"
            >
              Login
            </Link>
          </div>
        </div>
      </div>
    </div>
  );
};
export default Landing;

Home.js

import React from 'react';
import { Link } from 'react-router-dom';
const Home = props => {
  return (
    <div style={{ height: '75vh' }} className="container valign-wrapper">
      <div className="row">
        <div className="col s12 center-align">
          <h4>
            <b>Home Page </b>
          </h4>
          <br />
          <div className="col s6">
            <Link
              to="/"
              onClick={props.logout}
              style={{
                width: '140px',
                borderRadius: '3px',
                letterSpacing: '1.5px',
              }}
              className="btn btn-large waves-effect waves-light hoverable blue accent-3"
            >
              Logout
            </Link>
          </div>
        </div>
      </div>
    </div>
  );
};
export default Home;

CSS

Thêm vào dòng 14 ~ 21 trong file /public/index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css"
    />
    <link
      href="https://fonts.googleapis.com/icon?family=Material+Icons"
      rel="stylesheet"
    />
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>

Đầu tiên với file index React

index.js là tệp chính sẽ chạy dự án react của bạn. Thêm code này:

mport React from 'react';
import ReactDOM from 'react-dom';
import App from './App';ReactDOM.render(<App />, document.getElementById('root'));

Main App

Trong index.js, bạn có thể thấy bên trong ReactDOM.render, tôi <App /> để render Ứng dụng khi bắt đầu dự án. Truy cập App.js của bạn và import sau:

import React, { Component } from 'react';import Landing from './components/Landing';class App extends Component {
  render() {
    return (
      <div>
        <Landing />
      </div>
    );
  }
}export default App;

Constants

  • Đối với giá trị mà bạn sẽ sử dụng ở các vị trí khác nhau trong chương trình của mình, tôi thực sự khuyên bạn nên tạo các biến CONSTANTS để code có thể tái sử dụng và dễ đọc.
  • Điều này cũng sẽ cho phép TextEditor của bạn auto-complete, giảm lỗi đánh máy trong các chuỗi và tiết kiệm thời gian khi quyết định thực hiện các thay đổi đối với các biến này trong ứng dụng NodeJS

Thêm những thứ này vào tệp constants.js:

export const HOST = 'http://localhost:8080'
// User Token
export const USER_TOKEN = 'USER_TOKEN';
export const SET_USER_TOKEN = 'SET_USER_TOKEN';
// Server URI
export const LOGIN_URI = '/login';
// Auth
export const LOGIN_FAILED = 'LOGIN_FAILED';
export const LOGIN_SUCCESSFULLY = 'LOGIN_SUCCESSFULLY';
export const LOGOUT = 'LOGOUT';

Utils.js

Tệp này được sử dụng để thêm bất kỳ chức năng nào bạn muốn sử dụng trên toàn cầu. Ví dụ: tôi đã sử dụng bộ nhớ cục bộ để lưu JWT Token nhằm tránh gọi lại API đăng nhập khi người dùng đóng trình duyệt của họ.

LocalStorage là gì?

Vấn đề: Hãy tưởng tượng bạn đang ngồi vào bàn và đọc một cuốn sách. Sau đó, bạn đến kệ ở góc xa để đặt sách lại. 5 phút sau bạn phải quay lại kệ lấy sách ra đọc lại, nếu chúng ta cứ quay đi quay lại 5 lần trong 10 phút thì thật lãng phí thời gian.

Giải pháp: Sau khi đọc xong cuốn sách, thay vì cất lại vào giá, bạn hãy xếp nó vào chiếc kệ nhỏ trên bàn. Lần sau, bạn có thể lấy sách mà không cần rời khỏi ghế.

Local Storage: Giá nhỏ trên bàn làm việc của bạn có thể được coi là Local Storage, nơi bạn lưu trữ bất kỳ thứ gì chẳng hạn như USER_TOKEN, vì vậy, lần sau khi mở trang web, bạn không cần thực hiện lệnh gọi API để tiết kiệm thời gian và chi phí.

Ví dụ trong đời sống: Tương tự như khi bạn mở lại trình duyệt Facebook, bạn không cần đăng nhập lại vì đã có token trong ứng dụng của bạn.

Điểm mạnh: Sử dụng local storagesẽ tránh việc người dùng đưa ra nhiều request tới máy chủ của bạn để tiết kiệm thời gian và $$$

export function setTokenToLocalStorage(key, value) {
  return Promise.resolve().then(() => {
    localStorage.setItem(key, value);
  });
}
export function getTokenFromLocalStorage(key) {
  return localStorage.getItem(key);
}
export function removeTokenFromLocalStorage(key) {
  return localStorage.removeItem(key);
}

Class React

  • Class react sẽ chứa mọi thứ của trang cụ thể, bao gồm chức năng trigger một button, component trong Trang đó.
  • Bây giờ, tạo HomePage.js để hiển thị Landing component: 
touch src/pages/HomePage.js
import React, { Component } from 'react';
import Landing from '../components/Landing';class HomePage extends Component {
  render() {
    return <Landing />;
  }
}export default HomePage;

Chạy ứng dụng của bạn bằng npm start. Thao tác này sẽ mở localhost: 3000 / trong trình duyệt của bạn.

Kết luận

Qua phần 1 bạn đã setup những thứ cơ bản về mô hình M.E.R.N

Tham khảo thêm về NodeJS: 9 nền tảng lưu trữ NodeJS tốt nhất năm 2020

Tham khảo thêm về React: Test ứng dụng React với puppeteer và jest


Like it? Share with your friends!

1052
1.5k shares, 1052 points

What's Your Reaction?

hate hate
1
hate
confused confused
1
confused
fail fail
2
fail
fun fun
3
fun
geeky geeky
2
geeky
love love
1
love
lol lol
1
lol
omg omg
0
omg
win win
0
win