如何使Angular模拟服务树可摇动

问题描述 投票:0回答:2

上下文

在Angular 9项目中,我正在使用两个环境:生产模拟

在核心模块中,我检查模拟环境。

  • 如果使用模拟配置进行构建,我将注入返回模拟数据的模拟服务,因此不会进行外部http请求。

  • 如果使用产品配置进行构建,则会注入真实服务。

我这样做:

́core.module.ts

@NgModule({
  declarations: [],
  providers: [],
  imports: [BrowserModule, HttpClientModule],
  exports: [],
})
export class CoreModule {}

country.service.proxy.ts

const countryServiceFactory = (
  _http: HttpClient,
  _errorUtil: ErrorUtilService
) => {
  return isMock
    ? new ServiceMock()
    : new Service(_http, _errorUtil);
};

@Injectable({
  providedIn: CoreModule,
  useFactory: countryServiceFactory,
})
export abstract class CountryServiceProxy {
  abstract getCountries(): Observable<CountryWithLanguages[]>;
}

ServiceMockService实现相同的接口。

这有效。

问题

代码不是可摇树的代码。结果是在我的捆绑软件中(当我运行ng build --prod时)甚至包括了模拟服务。

我想在开发过程中将每个服务从模拟转换为产品。

目标

如何使Angular仅捆绑将要使用的服务?


我正在使用:

Angular CLI: 9.0.4
Node: 13.6.0
OS: darwin x64

Ivy Workspace: Yes

谢谢! :)

angular typescript service bundle tree-shaking
2个回答
0
投票

我尝试了一种可行的解决方案,使用interceptor返回模拟,而不使用服务工厂。

CoreModule具有生产提供者和拦截器

core.module.ts

@NgModule({
  declarations: [],
  providers: [{
      provide: HTTP_INTERCEPTORS,
      useClass: IntegrationsMockInterceptorService,
      multi: true,
    },],
  imports: [BrowserModule, HttpClientModule],
  exports: [],
})
export class CoreModule {}

我定义了一个拦截器

country.interceptor.service.ts


  const isMock = environment.mock;

  const mockResults = [
    {
      url: API_COUNTRY_URL,
      mock: GET_COUNTRIES_MOCK,
    },
  ];

  @Injectable()
  export class IntegrationsMockInterceptorService implements HttpInterceptor {
    intercept<T>(
      req: HttpRequest<T>,
      next: HttpHandler
    ): Observable<HttpEvent<T>> {
      if (!isMock) {
        return next.handle(req);
      }
      const mock = this._getMockByUrl(req.url);
      return of(new HttpResponse({ status: 200, body: (mock as unknown) as T }));
    }

    private _getMockByUrl(url: string) {
      const result = mockResults.find(result => result.url === url);
      if (!result) {
        console.error(`Mock not defined for url:${url}`);
      }
      return result?.mock;
    }
  }

结果

使用拦截器的捆绑包更大

我进行了在拦截器中定义5个模拟服务和5个元素的实验。

模拟对象(mockResults[].mock内部包含在主捆绑包中。

  • 拦截器:
chunk {1} main-es2015.5e8588ae9917478e9732.js (main) 656 kB [initial] [rendered]
chunk {1} main-es5.5e8588ae9917478e9732.js (main) 772 kB [initial] [rendered]
  • 模拟服务:
chunk {1} main-es2015.a8d7ba2f3acff1277bcc.js (main) 652 kB [initial] [rendered]
chunk {1} main-es5.a8d7ba2f3acff1277bcc.js (main) 768 kB [initial] [rendered]

0
投票

我刚刚尝试了一种似乎可行的方法:

  • environment.{env}.ts文件中声明相关的服务工厂
  • 使用环境工厂作为服务提供商

我的测试设置:

基类

@Injectable()
export abstract class TestService {
  abstract environment: string;
}

开发服务

@Injectable()
export class DevTestService extends TestService {
  environment = 'qwertydev';
}

产品服务

@Injectable()
export class ProdTestService extends TestService {
  environment = 'qwertyprod';
}

environment.ts

export const environment = {
  testServiceFactory: () => new DevTestService()
};

environment.production.ts

export const environment = {
  testServiceFactory: () => new ProdTestService()
};

app.module.ts

providers: [
  { provide: TestService, useFactory: environment.testServiceFactory }
],

app.component.ts

constructor(private testService: TestService) {}

ngOnInit() {
  console.log(this.testService.get());
}

[当我检查构建文件时,我只在开发版本中发现qwertydev,而在生产版本中发现qwertprod,这表明它们已经摇晃了。

我使用字符串qwerty*使缩小后的构建文件搜索变得容易。

© www.soinside.com 2019 - 2024. All rights reserved.