Często, gdy pracujemy nad naszą aplikacją musimy korzystać z innych adresów dla naszego API na produkcji, a innego lokalnie. Między innymi w takich przypadkach przychodzą nam z pomocą zmienne środowiskowe aplikacji. Dzisiaj chciałem pokazać jak w szybki sposób dodać możliwość obsługi zmiennych środowiskowych w naszej aplikacji wykorzystującej Angulara. Myślałem że będzie to coś, co jest dostępne out of the box, jednak nie zawsze tak jest. Jeżeli korzystacie z Angular-CLI, macie dostęp do nich w katalogu environments
. Ja pokażę jak łatwo coś takiego zaimplementować w sytuacji, gdy nie mamy takiego udogodnienia. Mój przykład opiera się o aplikację, która powstała z szablonu dostępnego w dotnet CLI o którym pisałem w poprzednich postach. Moja aplikacja wykorzystuje Webpacka.
Implementacja serwisu z konfiguracją
Moje rozwiązanie nie jest idealne, ponieważ obsługuje jedynie dwie wersje aplikacji: lokalną czyli developerską, oraz produkcyjną. Jeżeli chcielibyśmy mieć możliwość obsługi innego środowiska, należy dodać kilka dodatkowych elementów, np. task w Gulpie, który podmieniałby nasze konfiguracje. Ja nie będę się tutaj rozpisywał na ten temat. Rozwiązanie składa się z kilku elementów. Na początek dodajemy plik app.config.ts
, który przechowuje nasze zmienne.
1 2 3 4 5 6 7 8 9 10 |
//Application configuration import { IConfig } from './app.iconfig'; export class DevConfig implements IConfig{ public API_URL: string = "http://localhost:8080/api/"; } export class ProdConfig implements IConfig { public API_URL: string = "http://production.site.com/api/"; } |
Plik ten zawiera dwie klasy, które implementują interfejs IConfig
. Dzięki temu nigdy nie przeoczymy żadnej zmiennej podczas dodawania konfiguracji. Poniżej przykład takiego intefejsu.
1 2 3 4 5 |
//Configuration interface export interface IConfig { API_URL: string; } |
Następnie dodajemy serwis, który będzie przekazywany wewnątrz aplikacji.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import { Injectable, isDevMode } from '@angular/core'; import { DevConfig, ProdConfig } from './app.config'; import { IConfig } from './app.iconfig'; @Injectable() export class ConfigService { cfg: IConfig; constructor() { if (isDevMode()) this.cfg = new DevConfig(); else this.cfg = new ProdConfig(); } get ApiUrl(): string { return this.cfg.API_URL; } } |
Tutaj, w zależności od tego, czy uruchomiliśmy aplikację lokalnie, czy na produkcji, tworzymy instancję klasy zawierającej nasze konfiguracje. Funkcja isDevMode
sprawdza na jakim środowisku jesteśmy. W moim przypadku to Webpack uruchamia aplikację w odpowiednim trybie (podczas publishu na produkcję dodawana jest opcja env.prod
, o tym więcej w dokumentacji dotnet CLI). W serwisie definiujemy tyle pól, ile potrzebujemy. Ja użyłem tutaj składni Typescipt’u, która pozwala na dodawanie getterów. Możemy taką klasę podzielić na mniejsze, jeżeli nie chcemy mieć jednej dużej klasy z całą konfiguracją. Taki serwis możemy wstrzykiwać w inne serwisy lub komponenty naszej aplikacji, oraz podmieniać ją na inną podczas testów.
Podsumowanie
Jest to rozwiązanie, które można jeszcze rozwinąć, ale obecnie spełnia moje wszystkie wymagania. Dodatkowo jest bardzo proste w implementacji i działa automatycznie, bez konieczności wykonywania innych operacji podczas rozwoju aplikacji, takich jak uruchamianie skryptów. Mam nadzieję, że komuś się przyda!