각도 환경 설정 - 안전하고 테스트 가능

원재 nils-mehlhorn.de
대부분의 실제 세계의 Angular 응용 프로그램은 개발 주기 내내 서로 다른 환경에서 생활한다.차이는 보통 최소한으로 유지해야 하지만, 당신의 웹 앱은 개발자의 기기에서 생산 환경에 배치될 때와 약간 다를 수 있습니다.
Angular에는 이미 environments이라는 솔루션이 있습니다.작동 방식 개요: 환경 파일을 src/environments과 같은 디렉토리에 여러 개 배치합니다.
src
└── environments
    ├── environment.prod.ts
    ├── environment.stage.ts
    └── environment.ts
모든 비기본 환경은 그에 상응하여 접미사를 붙일 것입니다. 예를 들어 당신의 생산 환경에'prod'를 붙일 것입니다.
각 파일에서 환경별 값만 사용하여 동일한 속성을 정의하는 environment이라는 객체를 내보냅니다.이것은 프로덕션 환경 또는 환경 이름을 나타내는 부울 마크일 수 있습니다.
// environment.ts
export const environment = {
  production: false,
  name: 'dev',
  apiPath: '/api'
}
// environment.stage.ts
export const environment = {
  production: false,
  name: 'stage',
  apiPath: '/stage/api'
}
// environment.prod.ts
export const environment = {
  production: true,
  name: 'prod',
  apiPath: '/prod/api'
}
현재, 응용 프로그램이 서로 다른 구축을 위해 서로 다른 환경을 사용하도록 하기 위해서, angular.json의 각 환경에 대해 구축 설정을 정의할 것입니다.여기서 파일 교체를 구성하면 다음과 같이 특정 덮어쓰기를 위해 environment.ts으로 전환됩니다.
"architect": {
  ...
  "build": {
    "builder": "@angular-devkit/build-angular:browser",
    "options": {...},
    "configurations": {
      "production": {
        "fileReplacements": [{
          "replace": "src/environments/environment.ts",
          "with": "src/environments/environment.prod.ts"
        }],
        ...
      }
      "stage": {
        "fileReplacements": [{
          "replace": "src/environments/environment.ts",
          "with": "src/environments/environment.stage.ts"
        }],
        ...
      }
    }
  }
  ...
}
구축 시 구성의 이름을 Angular CLI에 전달하여 구성을 트리거합니다.
ng build --configuration <config>
팁: environment.prod.ts을 사용하면 프로덕션이라는 구성이 선택됩니다.
실제로는 이렇다. 파일 교체와 간단한 자바스크립트 대상. 다각도의 마력이 없다.이제 ng build --prod에서 가져오고 런타임 시 항상 특정 환경에 대한 속성을 가져옵니다.
import { environment } from '../environments/environment';

// ng build             --> 'dev'
// ng build -c stage    --> 'stage'
// ng build --prod      --> 'prod'
console.log(environment.name)
하지만 우리는 더 잘할 수 있다.이 설정에서 두 가지 문제가 발생했습니다.
  • 에서 environment.ts에 새 속성을 추가할 때 다른 환경 파일
  • 에 대응하는 항목을 추가하는 것을 잊어버리기 쉽다
  • 은 특정 환경에 대한 테스트를 수행할 수 없음
  • 설정에 대한 두 가지 변경을 통해 이 문제들을 해결합시다.

    입력 환경
    Angular는 TypeScript를 의미하는데, 왜 이곳의 언어 우위에서 이익을 얻지 않습니까?환경을 입력하면 모든 환경에 속성이 부족할 때 컴파일러가 알려 줍니다.이를 위해 environment.ts이라는 파일에서 환경에 대한 인터페이스를 정의합니다.
    export interface Environment {
      production: boolean
      name: string
      apiPath: string
    }
    
    이제 환경 객체를 정의할 때 해당 유형을 새로 만든 인터페이스로 선언합니다.
    import {Environment} from './ienvironment'
    
    export const environment: Environment = {
      production: false,
      name: 'dev',
      apiPath: '/api'
    }
    
    모든 환경 파일에서 이 동작을 실행하면 유형 시스템에서 적지 않은 이익을 얻을 수 있습니다.이렇게 하면 환경과 관련된 새로운 기능을 배치할 때 의외라고 느끼지 않을 수 있습니다.

    환경 테스트
    때때로, 나는 내가 환경에 특정된 테스트를 실행하고 싶은 상황에 처해 있다는 것을 발견한다.개발 환경에서만 작동하지만 생산 과정에서 컨트롤러에 로그인하는 오류 처리 프로그램이 있을지도 모른다.환경이 간단하게 도입되기 때문에 테스트 실행 기간에 모의 환경을 모의하는 것은 매우 불편하다. 이 문제를 해결하자.
    각도 구조는 dependency injection(DI)의 원리를 바탕으로 한다.이것은 하나의 클래스 (예를 들어 하나의 구성 요소나 서비스) 가 실례화 과정에서 필요한 모든 것을 얻었다는 것을 의미한다.따라서 모든 의존항은 Angular를 통해 클래스 구조 함수를 주입한다.이것은 테스트 기간에 이 의존항을 아날로그 대응항으로 전환할 수 있도록 합니다.
    의존 주입을 통해 우리의 환경을 제공할 때, 우리는 환경에 특정된 테스트 용례를 쉽게 모의할 수 있다.이를 위해 우리는 또 다른 파일 ienvironment.ts을 만들었는데 그 중에서 InjectionToken을 정의했다.Angular는 일반적으로 의존 항목을 표시하기 위해 클래스 이름을 사용하지만, 환경에는 TypeScript 인터페이스가 하나밖에 없기 때문에, 이 영패를 제공해야 합니다.또한 Angular는 인터페이스의 구조 함수를 호출할 수 없기 때문에 환경 실례를 얻기 위한 공장 방법을 제공합니다.마지막으로 공급자 코드는 다음과 같습니다.
    import {InjectionToken} from '@angular/core'
    import {Environment} from './ienvironment'
    import {environment} from './environment'
    
    export const ENV = new InjectionToken<Environment>('env')
    
    export function getEnv(): Environment {
      return environment;
    }
    
    그런 다음 이 공급자를 environment.provider.ts 목록에 추가하여 Angular module에게 전달합니다.
    import {ENV, getEnv} from '../environments/environment.provider'
    
    @NgModule({
      ...
      providers: [
        {provide: ENV, useFactory: getEnv}
      ]
    })
    export class AppModule { }
    
    현재, 우리는 providers에서 환경을 직접 가져오지 않고, Inject 장식기를 사용하여 환경에 접근할 클래스에 주입합니다.
    import { Injectable, Inject } from '@angular/core';
    import { Environment } from '../environments/ienvironment'
    import { ENV } from '../environments/environment.provider'
    
    @Injectable() 
    export class UserService {
    
      constructor(@Inject(ENV) private env: Environment) {
      }
    
      save(user: User): Observable<User> {
          if (this.env.production) {
            ...
          } else {
            ...
          }
      }
    
    }
    
    테스트 중에 환경을 시뮬레이션하기 위해 directly into the class constructor 또는 Angular dependency injection using the TestBed을 통해 다음과 같이 쉽게 사용할 수 있습니다.
    import { ENV } from '../environments/environment.provider'
    
    describe('UserService', () => {
      describe('when in production', () => {
          beforeEach(() => {
            const env = {production: true, ...}
            // without TestBed
            const service = new UserService(env)
            // or with TestBed
            TestBed.configureTestingModule({
              providers: [
                {provide: ENV, useValue: env}
              ]
            });
          });
      });
    });
    
    또한 의존항을 통해 사용 환경을 강제로 실행하려면 tslint rule blocking direct imports을 만들어서 의외의 사용을 방지할 수 있습니다.

    마무리
    약간의 설정을 통해 우리는 사용 각도 환경을 더욱 안전하고 편안하게 할 수 있다.우리는 이미 사용할 수 있는 유형과 의존 주입이 있기 때문에 이러한 도구를 이용하여 더욱 좋은 개발 체험을 얻는 것이 가장 좋다.특히 여러 환경을 갖춘 대형 응용 프로그램에서 우리는 정확하게 정의된 인터페이스, 좋은 테스트 범위와 테스트 드라이브 개발에서 적지 않은 이익을 얻을 수 있다.

    좋은 웹페이지 즐겨찾기