Category: Web

  • [React] Class Component và Function Component, bạn chọn viết theo cách nào?

    [React] Class Component và Function Component, bạn chọn viết theo cách nào?

    Trong thế giới React thì chắc hẳn ai cũng biết đến Class Component và Function Component. Tuy nhiên có thể có những hiểu nhầm về hai loại component này. Trong bài viết này tôi sẽ thử so sánh hai cách viết này để giúp bạn có thể lựa chọn viết theo cách nào. Chúng ta cùng bắt đầu nhé.

    Cú pháp

    Khác nhau đầu tiên giữa Class ComponentFunction Component thể hiện ngay ở cách khai báo.

    Class Component

    import React, { Component } from 'react';
    
    class TestComponent extends Components {
      // phương pháp này bắt buộc phải khai báo hàm để kết xuất mã HTML
      render() {
        return <div>TestComponent</div>;
      }
    }
    

    Cách khai báo này khá quen thuộc với các bạn có nền tảng lập trình hướng đối tượng (OOP). Với những bạn mới học React hoặc chuyển sang học React thì phương pháp tiếp cận này có vẻ phù hợp và dễ hiểu.

    Function Component

    import React from 'react';
    
    export function TestComponent() {
      // phương pháp xem kết xuất mã HTML như là giá trị trả về của hàm
      return <div>TestComponent</div>;
    }
    

    Function component sử dụng cách tiếp cận khác đó là sử dụng pure function để khai báo component. Ban đầu function component được sử dụng để viết các component chỉ với mục đích kết xuất HTML mà thôi. Với các component với theo hướng tiếp cận này thì bạn sẽ không can thiệp được vào lifecycle của component. Do đó nó thướng được biết đến với tên gọi Stateless Component.

    Props

    Class Component

    props trong Class Component được xem như giá trị truyển vào cho hàm khởi tạo class.

    import React, { Component } from 'react';
    
    class TestComponent extends Components {
      constructor(props) {
        super(props); // bắt buộc phải có dòng này để gọi hàm khởi tạo của class cha nhé
      }
    
      render() {
        return <div>TestComponent</div>;
      }
    }
    

    Function Component

    props trong Function Component thì được xem như là giá trị truyền vào hàm pure function khi định nghĩa component.

    import React from 'react';
    
    export function TestComponent(props) {
      return <div>TestComponent</div>;
    }
    

    Định nghĩa defaultPropspropTypes thì không có sự khác biệt giữa Class Component và Function Component.

    TestComponent.defaultProps = {};
    
    TestComponent.propTypes = {};
    

    State

    Trước khi React Hooks ra đời thì như đã nói ở trên Function Component con được biết đến với tên gọi Stateless Component. Nghĩa là nó không có state. Khi React Hooks ra đời thì Function Component cũng có state của riêng nó.

    Class Component

    state trong Class Component dược định nghĩa như sau:

    import React, { Component } from 'react';
    
    class TestComponent extends Components {
      constructor(props) {
        super(props);
        // khởi tạo giá trị state
        this.state = { isLoading: false };
      }
    
      render() {
        return <div>TestComponent</div>;
      }
    }
    

    Khi muốn thay đổi giá trị state bạn gọi phương thức setState của component:

    this.setState((state) => ({ isLoading: true }));
    

    Function Component

    state trong Function Component được định nghĩa như sau:

    import React, { useState } from 'react';
    
    export function TestComponent(props) {
      // giá trị khởi tạo state được truyền vào trong useState hook
      const [state, setState] = useState({ isLoading: false });
    
      return <div>TestComponent</div>;
    }
    

    Các bạn để ý hàm useState trả về giá trị của component state trong biến state và hàm setState. Khi muốn thay đổi giá trị của state thì bạn có thể gọi hàm setState.

    setState({ isLoading: true });
    

    Component Lifecycle

    Với Class component các bạn sẽ thấy component lifecycle khá rõ ràng với các hàm như componentDidMount, componentDidUpdate. Function Component thì không như vậy, toàn bộ việc sử lý lifecycle đều thông qua useEffect hook.

    // componentDidMount
    useEffect(() => {
      return () => {}; // componentWillUnmount
    }, []);
    
    // componentDidUpdate
    useEffect(() => {
      return () => {}; // componentWillUnmount
    }, [state]);
    

    Như các bạn thấy thì componentDidMountcomponentDidUpdate không chỉ định rõ khi nào thì hàm được gọi. Việc gọi hàm thì tự chúng ta hiểu dựa theo lifecycle của React component thôi. Với Function Component và useEffect thì khác, bạn có thể thấy [][state] chị định rõ ràng đối tượng phụ thuộc mà khi chúng thay đổi thì hàm truyển vào useEffect sẽ được gọi. Có vẻ như nó lại tường mình hơn là các hàm lifecycle trong class Component.

    Sau sự có mặt của TypeScript thì có lẽ Class Component và React Hooks thì có lẽ bạn Class Component chiếm ưu thế tuyệt đối. Thời điểm đó anh em thi nhau viết Class Component với TypeScript và tôi cũng thế :). Ngay đến cả facebook cũng support TypeScript với create-react-app nữa cơ mà. Thế nhưng khi React Hooks xuất hiện thì có vẻ gió đã đổi chiều, việc xử lý state và lifecycle với hook có vẻ đơn giản hơn rất nhiều. Các bạn thì thấy thế nào. Bạn sẽ chọn cách nào với dự án của mình?

  • [React] Những điều có thể bạn chưa biết về Function Component

    [React] Những điều có thể bạn chưa biết về Function Component

    Chắc hẳn khi đọc bài này bạn cũng đã từng nghe nói đến các khái niệm Function Component và Class Component hay Stateless Component và Stateful Component. Cũng có thể bạn cũng từng nghe Function Component là Stateless Component. Vậy nó có thực sự là như thế. Trong bài viết này chúng ta cùng nhau tìm hiểu nhé.

    Nội dung bài viết gồm các phần sau:

    • Function Component là gì?
    • Function Component có props không?
    • Function component và sức mạnh đến từ React Hook

    Function component là gi?

    Function component là React Component được viết bằng Pure Function. Dễ hiểu hơn thì nó được viết theo dạng sau:

    export function Counter() {
      return <div>count</div>;
    }
    

    Function Component có props không?

    Có bạn sẽ đặt câu hỏi sau khi nhìn thấy cách viết trên, Function Component có props không? Câu trả lời là có. Bạn có thể truyền props cho component như sau:

    import React from 'react';
    
    export function Counter(props) {
      return <div>{props.count}</div>;
    }
    

    Và bạn vẫn có thể khai báo propTypes cho component như bình thường

    Counter.propTypes = {
      count: PropTypes.number
    };
    

    Mọi thứ đều ổn đến lúc này và có lẽ bạn cũng có nghe ai đó nhắc đến Stateless component. Có thể bạn cũng nghe ai đó nói Function Component là Stateless component. Vậy thì Function component có thực sự là Stateless không?

    Function component và sức mạnh đến từ React Hook

    Trước khi React Hooks ra đời, Function component thực sự là Stateless component. Đơn giản bởi bạn chẳng có cách nào thêm state cho nó cả. Function component khi đó chỉ có thể được dùng để render HTML với props truyền vào mà thôi.

    Khi React Hooks ra đời thì lại là câu chuyện khác. Function component có thể có state của riêng nó. Vậy làm sao để thêm state cho Function component? Với useState bạn có thể thêm state cho nó.

    Thay đổi một chút đoạn source code bên trên như sau là Functiona component của bạn đã support state rồi đấy.

    import React, { useState } from 'react';
    import PropTypes from 'prop-types';
    
    export function Counter() {
      const [count, setCount] = useState(0);
    
      return (
        <div>
          <button onClick={() => setCount(count - 1)}>-</button>
          {count}
          <button onClick={() => setCount(count + 1)}>+</button>
        </div>
      );
    }
    
    Counter.propTypes = {
      count: PropTypes.number
    };
    

    Kết luận lại là Function Component sẽ là Stateless Component nếu không có sự trợ giúp của React Hooks. Với React Hooks thì Function Component đã có toàn bộ sức mạnh như Class Component rồi.

    Cám ơn các bạn đã dành thời gian theo dõi bài viết. Hy vọng bày viết sẽ giúp ích cho các bạn.

  • Mô phỏng AWS Lambda & API Gateway bằng Serverless Offline

    Mô phỏng AWS Lambda & API Gateway bằng Serverless Offline

    Khi phát triển ứng dùng bằng AWS Lambda không phải lúc nào chúng ta cũng có thể phát triển trực tiếp trên AWS được. Do đó việc giả lập môi trường AWS để có thể chạy được Lambda và API Gateway là cần thiết. Nó không chỉ giúp chúng ta có thể học mà còn giúp cho quá trình phát triển nhanh hơn. Trong bài viết này tôi sẽ hướng dẫn các bạn giả lập AWS Lambda và API Gateway bằng Serverless Offline

    Các công cụ cần thiết

    Trước tiên bạn cần cài đặt các tool cần thiết, bạn có thể tham khảo hướng dẫn cài đặt trong các bài viết sau:

    Bạn có thể dùng lệnh sau để cài serverless

    hieunv@HieuNV lambda % yarn global add serverless
    yarn global v1.22.0
    [1/4] ?  Resolving packages...
    [2/4] ?  Fetching packages...
    [3/4] ?  Linking dependencies...
    [4/4] ?  Building fresh packages...
    success Installed "[email protected]" with binaries:
          - serverless
          - slss
          - sls
    ✨  Done in 14.23s.
    

    Tạo một project mới

    • Tạo project với yarn
    hieunv@HieuNV hieunv % mkdir lambda
    hieunv@HieuNV hieunv % cd lambda
    hieunv@HieuNV lambda % yarn init
    yarn init v1.22.0
    question name (lambda):
    question version (1.0.0):
    question description:
    question entry point (index.js):
    question repository url:
    question author:
    question license (MIT):
    question private:
    success Saved package.json
    ✨  Done in 3.53s.
    
    • Cài đặt serverless-offline
    hieunv@HieuNV lambda % yarn add serverless-offline -D
    
    • Cài đặt serverless-python-requirements để viết lambda handler bằng python
    hieunv@HieuNV lambda % yarn add serverless-python-requirements -D
    

    Cấu hình serverless.yml

    serverless.yml

    service: lambda
    
    frameworkVersion: '>=1.1.0 <2.0.0'
    
    provider:
      name: aws
      runtime: python3.7
    custom:
      serverless-offline:
        port: 4000
    plugins:
      - serverless-offline
      - serverless-python-requirements
    

    Cấu hình lambda handler đầu tiên trong serverless.yml

    Chúng ta tạo một Rest API sử dụng lambda bằng cách thêm đoạn sau vào file serverless.yml

    functions:
      test:
        handler: src.api.test.lambda_handler
        events:
          - http:
              method: get
              path: api/test
              cors: true
    

    Ở đây chúng ta tạo ra một Rest API với phướng thức GET và path /api/test. Các bạn nhìn thấy handler: src.api.test.lambda_handler đúng không. Đây là cấu hình hàm lamda sẽ được gọi bởi API Gateway

    Viết code cho lambda handler

    src/api/test.py

    import json
    
    
    def lambda_handler(event, context):
        headers = {"Access-Control-Allow-Origin": "*", "Accept": "application/json"}
        return {
            "statusCode": 200,
            "headers": headers,
            "body": json.dumps({"status": "success", "data": {}}),
        }
    

    Tạo script để run server

    Thêm đoạn sau vào package.json

        "scripts": {
            "start": "sls offline start"
        },
    

    Giờ thì chạy thôi nào các thanh niên

    hieunv@HieuNV lambda % yarn start
    yarn run v1.22.0
    $ sls offline start
    Serverless: Starting Offline: dev/us-east-1.
    
    Serverless: Routes for test:
    Serverless: GET /api/test
    Serverless: POST /{apiVersion}/functions/lambda-dev-test/invocations
    
    Serverless: Offline [HTTP] listening on http://localhost:4000
    Serverless: Enter "rp" to replay the last request
    

    Dùng Postman để call api vừa tạo nhé:

    Cám ơn các bạn đã theo dõi bài viết. Hy vọng bài viết có thể giúp các bạn tiếp tục học và làm việc cùng với AWS Lambda và API Gateway trong các dự án của mình.

  • [React] Tôi đã tạo thư viện React Component như thế nào

    [React] Tôi đã tạo thư viện React Component như thế nào

    Trong bài viết này tôi sẽ hướng dẫn các bạn tạo ra một thư viện component của riêng mình. Bạn cũng có thể public thư viện nếu thích. Nhiều bạn sẽ tự hỏi rằng có nhiều thư viện lắm rồi thì viết thêm làm chi. Mục đích mình viết bài này để có thể tự tạo ra một package gồm những common component có thể sử dụng lại được. Kết hợp với việc dùng mono repository gồm nhiều packages trong yarn workspaces, các bạn có thể tách code của mình thành các package cho dễ quản lý. Chúng ta cùng bắt đầu nhé.

    Thêm các dependencies cần thiết

    • react & react-dom React component mà nên cần 2 thư viện này là đương nhiên rồi.
    hieunv@HieuNV uikit % yarn add react react-dom
    yarn add v1.22.0
    [1/4] ?  Resolving packages...
    [2/4] ?  Fetching packages...
    [3/4] ?  Linking dependencies...
    [4/4] ?  Building fresh packages...
    success Saved lockfile.
    success Saved 3 new dependencies.
    info Direct dependencies
    ├─ [email protected]
    └─ [email protected]
    info All dependencies
    ├─ [email protected]
    ├─ [email protected]
    └─ [email protected]
    ✨  Done in 7.91s.
    
    yarn add v1.22.0
    info No lockfile found.
    [1/4] ?  Resolving packages...
    [2/4] ?  Fetching packages...
    [3/4] ?  Linking dependencies...
    [4/4] ?  Building fresh packages...
    ✨  Done in 15.05s.
    
    hieunv@HieuNV uikit % yarn add react-scripts -D
    yarn add v1.22.0
    [1/4] ?  Resolving packages...
    [2/4] ?  Fetching packages...
    [3/4] ?  Linking dependencies...
    [4/4] ?  Building fresh packages...
    ✨  Done in 41.42s.
    

    Chúng ta sẽ sử dụng webpack config đã được config trong react-scripts

    Cấu hình styleguidist

    styleguidist.config.js

    module.exports = {
      propsParser: require('react-docgen').parse,
      webpackConfig: require('react-scripts/config/webpack.config')
    };
    

    Thêm script run styleguidist

    package.json

    {
      "name": "uikit",
      "version": "1.0.0",
      "main": "index.js",
      "license": "MIT",
      "scripts": {
        "dev": "npx styleguidist server"
      },
      "devDependencies": {
        "react-scripts": "^3.4.0",
        "react-styleguidist": "^10.6.2"
      },
      "dependencies": {
        "react": "^16.13.0",
        "react-dom": "^16.13.0"
      }
    }
    

    Khởi động dev server thôi nào

    hieunv@HieuNV uikit % yarn dev
    yarn run v1.22.0
    $ npx styleguidist server
    Loading webpack config from:
    /Users/hieunv/Projects/hieunv/uikit/node_modules/react-scripts/config/webpack.config.js
    
    ℹ 「wds」: Project is running at http://localhost:6060/
    ℹ 「wds」: webpack output is served from undefined
    ℹ 「wds」: Content not from webpack is served from /Users/hieunv/Projects/hieunv/uikit
    You can now view your style guide in the browser:
    
      Local:            http://localhost:6060/
      On your network:  http://192.168.1.11:6060/
    

    Sau khi khởi động server xong các bạn truy cập và link http://192.168.1.11:6060/

    Do chưa có component nào được định nghĩa nên các bạn sẽ nhận được thông báo như trên.

    Bắt đầu viết component đầu tiên thôi nào

    styleguidist sẽ tự động đọc các components trong thư mục src/components/*README.md trong thư mục component tương ứng để generate ra document sử dụng react-docgen trên styleguidist server

    src/component/Button/Button.jsx

    module.exports = {
      propsParser: require('react-docgen').parse,
      webpackConfig: require('react-scripts/config/webpack.config')
    };
    

    src/component/Button/README.md

    <Button>Test Button</Button>
    

    Chúng ta truy cập lại vào http://192.168.1.11:6060/ sẽ thấy component được sử dụng để test và có cả document nữa luôn.

    Styleguidist server với react-docgen

    Export component ra bên ngoài để có thể sử dụng ở package khác

    src/index.js

    export * from './components/Button/Button';
    
    

    Cám ơn các bạn đã theo dõi bài viết. Hy vọng bài viết sẽ giúp ích cho các dự án của bạn.

  • [React] Loading indicator with React Context API & Hooks

    [React] Loading indicator with React Context API & Hooks

    Loading indicator có lẽ là component huyền thoại mà dự án nào cũng cần đến. Hôm nay mình sẽ hướng dẫn các bạn viết nó thành dạng global component để có thẻ được gọi tại bất kỳ đâu trong ứng dụng của bạn. Chúng ta cùng bắt đầu nhé.

    Để hiểu thêm về React Context API & Hooks các bạn tham khảo thêm tại đây:

    Chúng ta bắt đầu bằng việc tạo một dự án mới sử dụng React nhé. Trong bài viết này mình sẽ sử dụng create-react-app cùng với yarn để tạo project mới. Các bạn xem hướng dẫn cài yarn tại đây nhé.

    Tạo một project mới

    • Cài create-react-app package:
    hieunv@HieuNV ~ % yarn global add create-react-app
    yarn global v1.22.0
    [1/4] ?  Resolving packages...
    [2/4] ?  Fetching packages...
    [3/4] ?  Linking dependencies...
    [4/4] ?  Building fresh packages...
    success Installed "[email protected]" with binaries:
          - create-react-app
    ✨  Done in 14.08s.
    
    • Sau khi cài xong thì các bạn tạo project mới như sau:
    yarn create react-app loading
    
    Cấu trúc project được tạo bằng create-react-app

    Tạo React context mới để lưu trạng thái của Loading component

    context/loading.js

    import React, { useContext } from 'react';
    
    export const LoadingContext = React.createContext();
    
    export const useLoading = () => useContext(LoadingContext);
    

    Tạo LoadingProvider để lưu trạng thái loading như là một global state.

    providers/LoadingProvider.jsx

    import React, { useState } from 'react';
    import PropTypes from 'prop-types';
    import { LoadingContext } from '../../contexts/loading';
    
    export function LoadingProvider(props) {
      const [loading, setLoading] = useState(false);
    
      return (
        <LoadingContext.Provider
          value={{
            loading: loading,
            show: () => setLoading(true),
            hide: () => setLoading(false)
          }}>
          {props.children}
        </LoadingContext.Provider>
      );
    }
    
    LoadingProvider.propTypes = {
      children: PropTypes.node
    };
    

    Như các bạn nhìn thấy trong đoạn mã trên chúng ta đã sử dụng LoadingContext truyền trang thái loading và các hàm showhide xuống các component con thông qua React Context.

    Tại App component bạn đặt LoadingProvider là component cao nhất để tất các các component con bên trong có thể gọi các hàm showhide khi cần thiết.

    App.js

    import React from 'react';
    import { LoadingProvider } from './providers/LoadingProvider';
    import { useLoading } from './context/loading.js';
    import logo from './logo.svg';
    
    import './App.css';
    
    function App() {
      const { show, hide } = useLoading();
      return (
        <LoadingProvider>
          <div className="App">
            <header className="App-header">
              <img src={logo} className="App-logo" alt="logo" />
              <p>
                Edit <code>src/App.js</code> and save to reload.
              </p>
              <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer">
                Learn React
              </a>
            </header>
          </div>
        </LoadingProvider>
      );
    }
    
    export default App;
    

    Tại component bạn muốn gọi show hay hide loading thì chỉ cần thực hiện như sau:

    • import hàm useLoading() được khai báo trong context/loading.js
    import { useLoading } from './context/loading.js';
    
    • Trong component bạn sử dụng hook useLoading để lấy các hàm showhide:
    const { show, hide } = useLoading();
    

    Giờ chúng ta sửa lại một chút ở LoadingProvider để có thể show loading indicator

    import React, { useState } from 'react';
    import PropTypes from 'prop-types';
    import { LoadingContext } from '../../contexts/loading';
    
    function Loading() {
      return <div>Loading...</div>;
    }
    
    export function LoadingProvider(props) {
      const [loading, setLoading] = useState(false);
    
      return (
        <LoadingContext.Provider
          value={{
            loading: loading,
            show: () => setLoading(true),
            hide: () => setLoading(false)
          }}>
          <>
            {loading && <Loading />}
            {props.children}
          </>
        </LoadingContext.Provider>
      );
    }
    
    LoadingProvider.propTypes = {
      children: PropTypes.node
    };
    

    Các bạn để ý component Loading nhé. Chúng ta chỉ cần thêm một chút kỹ thuật css để cho component này đề lên trên tất cả các component khác bằng z-index đã có được loading indicator có thể được gọi ở bất kỳ đâu rồi.

    Cám ơn các bạn đã theo dõi bài viết. Hy vọng bài viết có thể giúp ích cho dự án của các bạn.

  • Hướng dẫn sử dung mono repository với yarn workspaces

    Hướng dẫn sử dung mono repository với yarn workspaces

    Thông thường khi viết ứng dụng node, chúng ta thương sử dụng các thử viện có sẵn trên npmjs. Trong bài viết này tôi sẽ hướng dẫn các bạn tạo một dự án node có thể chia nhỏ thành các packages nhưng vẫn có thể viết trên cùng một repository. Yarn cung cấp cho bạn chức năng để tạo và link các packages với nhau bằng yarn workspaces. Chúng ta tìm hiểu yarn workspaces hoạt động ra sao nhé

    Các bạn có thể tham khảo hướng dẫn cài đặt yarn ở đây

    Tạo mới project

    hieunv@HieuNV hieunv % mkdir mono
    hieunv@HieuNV hieunv % cd mono
    hieunv@HieuNV mono % yarn init
    yarn init v1.22.0
    question name (mono):
    question version (1.0.0):
    question description:
    question entry point (index.js):
    question repository url:
    question author:
    question license (MIT):
    question private:
    success Saved package.json
    ✨  Done in 5.46s.
    hieunv@HieuNV mono %
    

    Enable yarn workspaces

    • Thêm đoạn "workspaces": ["packages/*"] vào package.json

    package.json

    {
      "name": "mono",
      "workspaces": ["packages/*"],
      "version": "1.0.0",
      "main": "index.js",
      "license": "MIT"
    }
    

    Tiến hành tạo mono repository theo các bước sau:

    • Tạo 3 package trong thư mục packages như sau:
    hieunv@HieuNV mono % find . -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'
    .
    |____package.json
    |____packages
    | |____package-c
    | | |____index.js
    | | |____package.json
    | |____package-b
    | | |____index.js
    | | |____package.json
    | |____package-a
    | | |____index.js
    | | |____package.json
    
    • Tại thư mục package-apackage-b, thực hiện đăng ký package:

    package-a

    hieunv@HieuNV package-a % yarn link
    yarn link v1.22.0
    success Registered "package-a".
    info You can now run `yarn link "package-a"` in the projects where you want to use this package and it will be used instead.
    ✨  Done in 0.04s.
    

    package-b

    hieunv@HieuNV package-b % yarn link
    yarn link v1.22.0
    success Registered "package-b".
    info You can now run `yarn link "package-b"` in the projects where you want to use this package and it will be used instead.
    ✨  Done in 0.04s.
    
    • Thêm package-apackage-b như là dependency của package-c:
    hieunv@HieuNV package-c % yarn link "package-a"
    yarn link v1.22.0
    success Using linked package for "package-a".
    ✨  Done in 0.04s.
    hieunv@HieuNV package-c % yarn link "package-b"
    yarn link v1.22.0
    success Using linked package for "package-b".
    ✨  Done in 0.04s.
    
    • Trong package-a tạo các file sau:

    package-a/package.json

    {
      "type": "module",
      "name": "package-a",
      "version": "1.0.0",
      "main": "index.js",
      "license": "MIT"
    }
    

    package-a/index.js

    export function packageA() {
      console.log('Package A');
    }
    
    • Trong của package-b tạo các file sau:

    package-b/package.json

    {
      "type": "module",
      "name": "package-b",
      "version": "1.0.0",
      "main": "index.js",
      "license": "MIT"
    }
    

    package-b/index.js

    export function packageB() {
      console.log('Package B');
    }
    
    • Sử dụng các hàm được khai báo package-apackage-b

    package-c/package.json

    {
      "type": "module",
      "name": "package-c",
      "version": "1.0.0",
      "main": "index.js",
      "license": "MIT"
    }
    

    package-c/index.js

    import { packageA } from 'package-a';
    import { packageB } from 'package-b';
    
    packageA();
    packageB();
    
    • Run package-c/index.js
    hieunv@HieuNV package-c % node index.js
    (node:10165) ExperimentalWarning: The ESM module loader is experimental.
    Package A
    Package B
    

    Tài liệu tham khảo:

    • https://classic.yarnpkg.com/en/docs/workspaces/
  • HTTP vs HTTPS: Làm thế nào để website bảo mật hơn với SSL

    HTTP vs HTTPS: Làm thế nào để website bảo mật hơn với SSL

    Vào tháng 8 năm 2014, Google công bố sử dụng HTTPS để khắc phục những vẫn đề bảo mật mà phương thức HTTP đang gặp phải.

    Đối với hầu hết các công ty, việc Google khuyến cáo sử dụng HTTPS là lý do để thực hiện chuyển đổi sang giao thức đó, nhưng bản thân mỗi chúng ta cũng cần hiểu sự khác biệt giữa chúng – ưu và nhược điểm của HTTP và HTTPS. Tôi sẽ bắt đầu bằng việc giới thiệu tổng quan về giao thức HTTP và sau đó xem xét lý do tại sao Google muốn các trang web chuyển đổi sang sử dụng HTTPS.

    HTTP là gì, hoạt động như thế nào, và tại sao nó không được bảo mật?

    HTTP – HyperText Transfer Protocol, là một giao thức đã tồn tại hơn 15 năm, dùng để truyền tải thông tin qua Internet.

    Cũng như nhiều giao thức khác, HTTP hoạt động theo mô hình Client – Server. Trình duyệt web tạo request được gọi là Client, nơi nhận và phản hồi request đó là Server.

    Giả sử, bạn đang ngồi trong quán cafe và thử đăng nhập Facebook thông qua wifi của quán (giả định là Facebook đang dùng HTTP). Mạng wifi của quán là public, bất cứ ai kết nối với nó đều có thể truy cập dữ liệu đang được chuyển giao.

    Bây giờ chúng ta hãy xem những gì đang xảy ra với dữ liệu của bạn nếu như website sử dụng HTTP.

    Dữ liệu ở đây là bao gồm tất cả thông tin đăng nhập, mật khẩu, … cho tài khoản Facebook của bạn.

    Để đăng nhập vào Facebook, bạn cần nhập các thông tin như email, số điện thoại và mật khẩu. Ngay khi bạn nhấp vào nút đăng nhập, dữ liệu của bạn sẽ được gửi đến Server của Facebook. Server nhận dữ liệu, và xác thực nó. Nếu thông tin nhập là chính xác, Server sẽ gửi về HTTP status là “OK”, và bạn được đăng nhập vào tài khoản của mình. Mọi thứ có vẻ ez.

    Nhưng vấn để xảy ra ở đây là, nếu dữ liệu của bạn gửi lên server thông qua HTTP, thì nó sẽ không được mã hóa (HTTP không mã hóa dữ liệu) và vì vậy, bất kỳ dữ liệu nào được truyền thông qua giao thức HTTP đều có thể bị đánh cắp hoặc thay đổi từ bên thứ ba.

    Có thể bạn chưa bao giờ nghe tới Network sniffing attack, nhưng loại tấn công đó khá phổ biến.

    Sniffing attacks là một loại tấn công mà các Hacker sử dụng để lấy cắp thông tin “nhạy cảm” của bạn (vd: password, creadit card, users id, …).

    Để thực hiện việc này, các hacker thường sử dụng Sniffer – một chương trình có thể bắt được các gói tin truyền qua mạng.

    Sniffer là công cụ để phân tích và khắc phục các sự cố mạng thông qua việc bắt các gói tin, nhưng Hacker có thể lợi dụng điều đó để sử dụng chúng vào mục đích bất chính.

    Nếu các gói tin không được mã hóa, dữ liệu trong các gói tin này nó thể được lấy bởi một Sniffer. Sniffer sẽ phân tích và đọc nội dung gói tin, từ đó, các hacker đã có thể lấy được các thông tin private của bạn một cách dễ dàng.

    Như chúng ta đã thấy, HTTP có một điểm yếu chí cmn mạng – thông tin chuyển tới Server thông qua HTTP không được mã hóa. Điều đó, về mặt lý thuyết, có thể bị chặn bởi Hacker bất cứ lúc nào.

    Đối với những trang web thuần túy để đọc báo hay xem thông tin thì không có vấn đề gì lớn. Nhưng nó rất nguy hiểm khi bạn thực hiện các giao dịch trực tuyến, mà trong đó phải cung cấp các thông tin cá nhân quan trọng như giao dịch ngân hàng, mua sắm, …

    Tuy nhiên, điểm yếu đó của HTTP có thể được giải quyết dễ dàng bằng cách sử dụng 1 protocol khác – HTTPS.

    HTTPS ngoài Sniffing attacks ra cũng có thể bảo vệ bạn khỏi những kiểu tấn công khác như man-in-the-middle attacksDNS rebindingreplay attacks. Nhưng trong bài viết này, tôi chỉ để cập tới cách để HTTPS bảo vệ bạn khỏi Sniffing attacks đã nói ở trên thôi.

    HTTPS là gì và làm thế nào nó có thể bảo vệ website của bạn

    Giống như HTTP, HTTPS cũng là một giao thức giúp truyền thông tin giữa Client và Server. (Nó là một phiên bản của HTTP với thêm chứ “S” ở cuối – viết tắt của “Secure”). HTTPS bảo mật dữ liệu của bạn bằng cách sử dụng giao thức TSL (Transport Layer Security) hay còn gọi là SSL. Nhưng SSL là gì?

    SSL là tiêu chuẩn bảo mật cung cấp 3 lớp bảo vệ:

    • Mã hóa (Encryption): tất cả dữ liệu được gửi giữa browsers (Client) và Server đều được mã hóa. Nếu Hacker lấy được gói tin đó, cũng không thể giải mã được.
    • Toàn vẹn dữ liệu (Data integrity): Đảm bảo dữ liệu truyền đi không thể sửa đổi hoặc bị hỏng mà không bị phát hiện.
    • Xác thực (Authentication): Xác minh xem bạn thực sự đang giao tiếp với Server đã định hay không.

    Để ý một chút, khi truy cập website sử dụng HTTPS, trên url của bạn sẽ hiển thị ra chữ màu xanh như sau:

    Hoạt động của SSL

    SL sử dụng cái gọi là Public Key Cryptography hoặc hệ thống Public Key Infrastructure (PKI). Hệ thống PKI (key không đối xứng) sử dụng 2 key khác nhau để mã hóa thông tin: public key và private key. Bất cứ thứ gì được mã hóa bằng public key đều chỉ có thể giải mã bằng private key tương ứng và ngược lại.

    Lưu ý rằng, private key – giống như cái tên của nó, nên được bảo vệ kỹ và chỉ được truy cập bởi chính owner mà thôi. Với một trang web, private key phải được giữ an toàn trên Server. Nhưng ngược lại, public key lại được cấp phát công khai cho bất kỳ ai, và tất cả mọi người đều cần nó để giải mã thông tin đã được mã hóa trước đấy bằng private key. Bây giờ, chúng ta đã hiểu cách làm việc của cặp public key và private key, ta sẽ tiếp tục mô tả quá trình hoạt động SSL thông qua từng bước như sau.

    Giả sử bạn truy cập 1 website có sử dụng HTTPS:

    • Bước 1: Thiết lập một “giao tiếp” an toàn giữa Server và Client – còn được gọi là Handshake (bắt tay). Quá trình Handshake được bắt đầu khi browsers truy cập trang web thông qua url. Bằng cách request trên, Client sẽ khởi tạo kết nối SSL với Server cùng với thông tin về phiên bản và kiểu mã hóa. Việc Client gửi request và khởi tạo kết nối SSL được gọi là client hello.
    • Bước 2: Bước tiếp theo được gọi là server hello. Sau khi nhận được yêu cầu từ Client, Server trả về cho Client SSL certificate cùng với public key của nó. Hoàn tất quá trình chào hỏi xã giao.
    • Bước 3: Client nhận được dữ liệu từ Server, browser sẽ xác minh SSL certificate đó. Những certificate này được kiểm soát bởi các tổ chức bảo mật (Certificate Authority) như Symantec, Comodo, GoDaddy. SSL Certificate là một khối dữ liệu bao gồm nhiều thông tin về server như:
      • Tên domain.
      • Tên công ty sở hữu.
      • Thời gian certificate được cấp.
      • Thời hạn certificate.
      • Public key.
    • Bước 4: Sau khi xác minh xong, Browser sẽ sinh ra 1 Key - K và được mã hóa bởi public key nhận được từ bước 2. K sẽ được sử dụng để mã hóa tất cả dữ liệu truyền tải giữa Client và Server.
    • Bước 5: Do quá trình mã hóa dữ liệu sử dụng PKI (key đối xứng), nên Client cần gửi cho Server cái khóa K này để giải mã gói tin. Server sẽ dùng private key để giải mã gói tin này và lấy được thông tin về khóa K.
    • Bước 6: Từ đây, các thông tin truyền tải giữa Client và Server đều được mã hóa bằng khóa K. Khóa K này là unique và chỉ có hiệu lực trong thời gian Session đó tồn tại.

    Việc sử dụng HTTPS sẽ bảo vệ trang web của bạn tới những kiểu tấn công mà tôi đã đề cập trước đó. Bạn có authentication, bạn có thể biết rằng mình đang giao tiếp một cách an toàn với Server dự định. Dữ liệu của bạn được mã hóa encryption – ngay cả khi sniffer lấy được gói tin, cũng không thể giải mã được nội dung bên trong. Và tất nhiên bạn có được toàn vẹn dữ liệu data integrity, vì vậy bạn có thể truyền những dữ liệu nhạy cảm mà không cần lo lắng về việc nó bị hỏng hoặc sửa đổi mà không phát hiện ra.

    Bạn có nên sử dụng HTTPS

    Trước khi đưa ra quyết định sử dụng HTTPS thay cho HTTP, tôi sẽ tổng hợp những lợi ích chính nếu website của bạn sử dụng HTTPS:

    • Security: Tất cả thông tin truyền tải giữa Client và Server đều được mã hóa và xác minh. Điều này giúp bạn chống được một số kiểu tấn công của hacker như man-in-the-middle attacksDNS rebindingreplay attacks.
    • Trust: Người dùng sẽ cảm thấy an tâm với trang web của bạn hơn. HTTPS giúp xây dựng lòng tin với họ, nhất là khi web của bạn cung cấp các dịch vụ dính đến tiền (yaoming).
    • SEO: Việc sử dụng HTTPS sẽ tăng thứ hạng tìm kiếm trang web của bạn trên các search engine.

    Nguồn:

  • Hướng dẫn cài đặt yarn trên MacOS

    Hướng dẫn cài đặt yarn trên MacOS

    Trong bài viết này tôi sẽ hướng dẫn các bạn cài đặt và sử dụng yarn để quản lý node packages thay cho npm

    Cài đặt brew

    /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    
    brew update && brew upgrade
    

    Cài đặt yarn

    brew install yarn
    

    Kiểm tra phiên bản yarn

    hieunv@HieuNV ~ % yarn -v
    1.22.0
    

    Tạo mới node project bằng yarn

    yarn init
    

    Thêm dependencies

    yarn add react
    

    Thêm devDependencies

    yarn add node-sass -D
    

    Xoá dependencies hoặc devDependencies

    yarn remove react
    
  • Sử dụng nhiều phiên bản node cùng lúc

    Sử dụng nhiều phiên bản node cùng lúc

    Khi sử dụng node nhiều bạn nghĩ rằng chỉ cần sử dụng phiên bản LTS mới nhất là đủ rồi. Tuy nhiên nếu bạn phải tham gia nhiều dự án cùng lúc (như mình chẳng hạn) thì mới thấy là chẳng dễ gì các dự án sống chung với nhau được. Nói vậy để thấy rằng dùng có thể dùng nhiều phiên bản cùng lúc là cần thiết. Trong bài viết này tôi sẽ hướng dẫn các bản cách sử dụng nhiều phiên bản node cùng lúc.

    nvm là gì?

    nvm là viết tắt của Node Version Manager. Như đã nói ở trên bài viết này sẽ hướng dẫn cách các bạn có thể sử dụng nhiều phiên bản node cùng lúc. Vậy thì nm là cần thiết nhỉ.

    Để cài đặt nvm bạn có thể sử dụng lệnh sau:

    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.2/install.sh | bash
    
    wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.2/install.sh | bash
    

    Tuỳ thuộc vào hệ điều hành bạn đang sử dụng thì cần thêm đoạn sau vào ~/.bash_profile hoặc ~/.profile hoặc ~/.bashrc hoặc ~/.zshrc. Mình đang sử dụng zsh nên mình sẽ thêm vào ~/.zshrc

    export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
    [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
    

    Kiểm tra xem nvm đã được cài thành công chưa

    nvm -v
    

    Giờ thì cài đặt phiên bản node mà muốn sử dụng thôi nào

    Cài đặt phiên bản mới nhất:

    nvm install node
    

    Cài đặt phiên bản xác định mà bạn muốn

    nvm install 10.10.0
    

    Để chuyển qua phiên bản node bản muốn sử dụng

    nvm use v13.9.0
    

    v13.9.0 là tên phiên bản các bạn nhìn thấy sau khi sử dụng nvm ls như ở trên.

    Chi tiết cách sử dụng nvm thì các bạn có thể tham khảo hướng dẫn ở link sau

    https://github.com/nvm-sh/nvm
    
  • Sự khác nhau giữa Authentication và Authorization

    Sự khác nhau giữa Authentication và Authorization

    1. Authentication

    Authentication là xác thực, chỉ quá trình định danh một tài khoản đang vào hệ thống chính là người đó chứ không phải ai khác. Đây là bước ban đầu của mọi hệ thống có yếu tố người dùng. Nếu không có bước xác thực này, hệ thống của bạn sẽ không biết được người đang truy cập vào hệ thống là ai để có các phản hồi phù hợp, thường biểu hiện ở hình thức đơn giản nhất chính là form đăng nhập vào hệ thống. Đây là mô hình xác thực dựa trên yếu tố “mật khẩu”. Mật khẩu là một trong những phương pháp được triển khai cho hệ thống xác thực (authentication). Một số phương thức xác thực thông dụng khác là khóa (public & private), sinh học (vân tay, tròng mắt, khuôn mặt)…

    2. Authorization

    Sau khi xác định được “danh tính” của tài khoản thì hệ thống mới chỉ trả lời được câu hỏi “Đó là ai?”, chúng ta sẽ tiến hành một bước quan trọng không kém đó là trả lời câu hỏi “Người đó có thể làm được gì?”, hay xác định quyền (phân quyền) của tài khoản hiện tại vừa mới được xác thực.
    Hệ thống của bạn có thể sẽ rất phức tạp bởi nhiều tính năng quan trọng và mạng lưới phòng ban dày đặc và cần phân chia quyền sử dụng rõ ràng nên việc thiết kế một hệ thống phân quyền cho từng thành viên là một việc làm cực kỳ quan trọng và cần thiết.

    Các hình thức phân quyền thường gặp là:

    + Role-based authorization: Phân quyền dựa trên vai trò của người dùng. Ví dụ trong WordPress có các role như là  Subscriber, Contributor, Author, Editor, Administrator và mỗi một role sẽ có những quyền khác nhau và mỗi người dùng sẽ được phân role có quyền tương ứng. Đối với những hệ thống có nhiều người dùng thì role-based là cách tiếp cận tốt nhất để tiết kiệm thời gian trong việc phân quyền.

    + Object-based authorization: Phân quyền theo đối tượng. Cách này sẽ phân quyền cho từng đối tượng cụ thể. Ví dụ những đối tượng trong nhóm A, B được phân quyền chỉnh sửa các bài viết trong danh mục. Nhưng đối tượng trong nhóm A chỉ chỉnh sửa được bài viết trong danh mục C, đối trượng trong nhóm B chỉ chỉnh sửa bài viết trong danh mục D.

    Nguồn tham khảo thêm:

    http://searchsecurity.techtarget.com/definition/authentication