【问题标题】:How to have different @Injectable for development and production如何为开发和生产使用不同的@Injectable
【发布时间】:2018-03-31 00:57:27
【问题描述】:

我有一个 rest-client 对象,它在生产环境中将指向一个 restful 服务器并与之通信。但在开发模式下,它会简单地使用浏览器的存储,以方便使用。

我认为正确的方法是对接口进行两种实现,一种用于生产,一种用于开发。这样,应用程序的其余部分不需要了解生产/开发,并且可以进行相同的测试。我需要做的就是找到一种方法为每个环境注入正确的实例。顺便说一句,我根本不想在生产代码中包含开发版本!

有人知道怎么做吗?

[更新]

我使用 Angular cli 来启动我的项目,所以我使用的是 Webpack(我想!)。我不喜欢使用外部模拟服务器,因为我更喜欢将测试/开发环境与外部依赖项隔离开来。这样,我在前端项目上所需要的工作就是它本身。此外,即使我的问题集中在休息客户端,但当然这个问题可以推广到任何其他单例注射剂。

我问这个问题是因为在我使用的其他 DI 框架(即 Spring)中,这样做是框架的一部分。所以我期待在这里也能看到同样的结果。

此时,我知道我可以利用environment.production 来检查它是否处于生产模式。但首先,这是一个运行时变量,但我想我正在寻找一个编译时变量(虽然我不确定)。此外,即使我们有该变量,但以下代码会导致编译错误:

if (environment.production) {
  import { RestClientService } from './rest-client.service';
}
else {
  import { MockRestClientService as RestClientService } from './mock-rest-client.service';
}

ERROR in ... Duplicate identifier 'RestClientService'.
ERROR in ... An import declaration can only be used in a namespace or module.

【问题讨论】:

  • 您使用什么构建工具? (即 webpack、rollup 之类的?)据我所知,TypeScript 本身在这种情况下无济于事。您需要在构建过程中“替换”该文件的包含路径。
  • 当然,您总是可以在运行时根据一些配置或类似的配置来实现它,但是您将在代码中拥有其中两个实现,并且应用程序本身将使用正确的一个。
  • 为什么不用MockBackend拦截Http调用(semaphoreci.com/community/tutorials/…),只是好奇你的用例;)

标签: javascript angular typescript


【解决方案1】:

为此使用factory provider

export function restClientFactory(http: HttpClient): RestClientService {
  if (environment.production) {
    return new RestClientService(http);
  } else {
    return new MockRestClientService();
  }
}

@NgModule({
  providers: [
    { provide: RestClientService, useFactory: restClientFactory, deps: [ HttpClient ] },
  ],
})
class AppModule {}

带有条件import 语句的方法不起作用,因为静态import 语句只允许在文件的顶层使用。它们不能嵌套在if/else 语句中。您可以使用动态 import() 来克服这个问题,但这也会导致这两个实现都包含在您的包中。


不幸的是,在技术上没有像 Spring 那样对 DI 进行编译时配置的可能性。

运行时检查的主要问题是这两个实现都将包含在您的生产包中。您可以依赖tree-shaking,它是生产构建的一部分,以确保您的模拟客户端不包含在生产包中。

由于environment.production 变量永远不会改变,您可以预期if/else 的一个分支永远无法访问,因此可以通过摇树过程从捆绑包中删除。问题是进行 tree-shaking 的工具无法理解它,因为变量没有声明为const,而是作为对象的属性。

如果您将export const production = true 添加到environment.prod.tsexport const production = falseenvironment.ts 并在if/else 语句中使用此变量,则其中一个分支应该可以成功地从生产包中摇树。

请注意,这种方法依赖于 Angular CLI 的实现细节。尽管如此,我已经在我的一个项目中成功使用了一年多。

【讨论】:

    猜你喜欢
    • 2018-03-08
    • 1970-01-01
    • 2019-07-14
    • 2017-07-27
    • 1970-01-01
    • 2011-09-29
    • 1970-01-01
    • 2018-01-10
    • 2015-05-28
    相关资源
    最近更新 更多