Bí KiếpBí Kiếp Lập Trình Angular

Giải pháp load cấu hình khi app init (P1)

0

Hôm nay mình sẽ chia sẽ cho các bạn một số giải pháp để có thể load cấu hình trước khi ứng dụng khởi động. Các bạn tham khảo một số giải pháp dưới đây có lẽ sẽ khá hữu ích cho các bạn trong một số dự án cần dùng đến.

Mục đích

Đối với những thứ chúng ta sử dụng nhiều và thường xuyên thay đổi như các cấu hình cho theme, các link api, storage, hay link đến service khác,…v.v…

VD: Mình có 2 link api khác nhau và mỗi link api sẽ có các api khác nhau:

  1. https://api-products.com/
  2. https://api-orders.com/

Giả sử, api-products dùng để call đến api lấy DS Sản phẩmapi-orders thì dùng call đến để lấy DS Hóa đơn.

Thay vì, chúng ta phải thay đổi ở biến môi trường hay là phải chỉnh sửa lại code của từng nơi sử dụng các link đấy để app của các bạn có thể hoạt động được thì => Giải pháp load cấu hình này giúp chúng ta có thể dễ dàng điều chỉnh được mà không cần phải chỉnh sửa biến env hay code của từng file.

Tiếp theo là giải pháp, thông thường thì mình hay sử dụng file *json để làm file cấu hình cho app.

Bắt đầu

Bài viết khá dài nên mình sẽ không show hết toàn bộ code trong bài viết, code mình sẽ để trên link stackblitz hoặc git trong bài nhé.

Trước tiên, chúng ta tạo 1 file json để lưu các cấu hình mà mình cần sử dụng trước. Bạn nên lưu file ở thư mục assets của app để khi chạy trên môi trường production thì mình cũng có thể chỉnh sửa được cấu hình nhé.

Giải pháp

Giải pháp dưới đây thay vì load chỉ 1 file thì mình sẽ có thể dùng để load nhiều file cấu hình cùng lúc được luôn nhé.

  1. Tạo một interface tên AppConfiguration để định nghĩa cấu trúc dữ liệu của phần config

2. Tạo một service với tên AppConfigsService và khai báo:

Khai báo static property theo cấu trúc của interface vừa tạo

static configs: AppConfiguration = {
    API_PRODUCTS: "",
    API_ORDERS: ""
  };

Constructor chúng ta sẽ tiêm vào service HttpClient

constructor(private httpClient: HttpClient) {}

Tạo một method load() dùng để đọc và xử lý cấu hình từ file json

load(): Promise<void> {
    const appConfig$ = this.httpClient.get("assets/configs/app-configs.json");

    return new Promise((resolve) => {
      zip(appConfig$)
        .pipe(
          catchError((res) => {
            console.warn(`AppConfigsService.load: Network request failed`, res);
            resolve();
            return [];
          })
        )
        .subscribe(
          ([appConfigs]) => {
            Object.assign(AppConfigsService.configs, appConfigs);
            console.log('AppConfigsService.configs', AppConfigsService.configs)
          },
          (err) => console.log(err),
          () => {
            //complete
            resolve();
          }
        );
    });
  }
}

Đoạn code trên chúng ta sẽ sử dụng các operators của rxjs như zip, pipe, catchErrorresolve() để trả về Promise, mình sẽ không reject() mà vẫn resolve() và trả ra data rỗng nếu trường hợp đọc bị lỗi.

=> Mục đích để khi mình đọc nhiều file cấu hình thì sẽ đảm bảo được dữ liệu luôn luôn được emit ra mà không làm cho ứng dụng bị stop nhé.

Object.assign(AppConfigsService.configs, appConfigs);

Đoạn code trên giúp chúng ta sao chép data đọc từ cấu hình vào trong static property configs

3. Cách đọc nhiều file cấu hình:

Ở đoạn method load() trên mình có khai báo:

const appConfig$ = this.httpClient.get("assets/configs/app-configs.json");

Nếu các bạn muốn đọc thêm 1 file cấu hình nữa là json hoặc api gì đấy (tùy mục đích sử dụng của mình) thì chỉ cần định nghĩa thêm 1 đoạn giống như trên với url mà các bạn muốn đọc là được.

VD: Dưới đây mình sẽ định nghĩa thêm 1 đoạn nữa để lấy cấu hình từ một file json khác

const appConfigAnother$ = this.httpClient.get("assets/configs/app-configs-another.json");

Và tiếp theo ở đoạn zip(appConfig$)subscribe(([appConfigs]) sẽ thành zip(appConfig$, appConfigAnother$)subscribe(([appConfigs, appConfigAnother]) => đoạn này bạn nào chưa rõ thì tìm hiểu thêm zip của rxjs nhé.

4. Đăng ký AppConfigsService tới AppModule

  1. Khai báo factory và provider trong AppModule

Đầu tiên, các bạn khai báo 1 function có tên là initializeApp => function này có nhiệm vụ là thực thi method load() chúng ta vừa khai báo trong AppConfigsService.

Tiếp theo, các bạn định nghĩa một const tên APP_INIT_PROVIDES để khai báo provider: gồm AppConfigsServiceAPP_INITIALIZER

Trong đó:

  • APP_INITIALIZER là một thể hiện của InjectionToken
  • useFactory được sử dụng do chúng ta đang cần chạy một function
  • deps: [ApppConfigsService] là để cho thằng Angular biết rằng fucntion initializeApp là đang phụ thuộc vào AppConfigsService
  • multi: true do useFactory không thể nhận vào nhiều function (Array) cho nên chúng ta set multi: true mục đích để có thể chạy nhiều APP_INITIALIZER với các factory khác nhau

Cuối cùng, ở @NgModule chúng ta khai báo như sau:

Các bạn nhớ import HttpClientModule vào nữa nhé => mục đích là để có thể sử dụng được sercvice HttpClient đấy.

APP_INIT_PROVIDES chính là provide mà chúng ta đã định nghĩa ở trên.

Cách sử dụng

Các bạn có thể gọi trực tiếp cũng được mà khai báo property để hứng cũng được, cách nào cũng được hết nha.

Kết quả

Lời kết

Do giải pháp này khá dài nên mình sẽ tách bài viết ra thành các phần khác nhau để các bạn dễ theo dõi và đọc đỡ chán hơn nhé.

Bên trên là giải pháp đầu tiên mình cũng hay sử dụng vào ứng dụng của mình, do nó vừa load được nhiều file cấu hình, vừa dễ custom mà còn vừa clean được một mớ code khi sử dụng nữa.

Giải pháp này nếu các bạn thấy hữu ích hoặc có ý kiến gì thêm thì nhớ để lại đánh giá và bình luận cho mình nhé.

Hướng dẫn kết nối đến phpMyAdmin khi sử dụng WordPress của Bitnami chỉ với 5 bước

Previous article

Giải pháp load cấu hình khi app init (P2)

Next article
0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
Login/Sign up
0
Would love your thoughts, please comment.x
()
x