创建兼容AoT的服务工厂 [英] Creating AoT compatible Service Factories

查看:118
本文介绍了创建兼容AoT的服务工厂的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为缓存服务创建服务工厂。主要要求是单个服务每次都可以使用不同的字符串进行实例化。

I'm trying to create a service factory for a caching service. The major requirement is that a single service can be instanced with a different string each time.

最终结果将具有多个每个定义的 cache 服务通过唯一的 databaseName 。每个缓存可以具有一个或多个商店,它们也由唯一的 storeName 定义。其他服务将可以使用这些存储:

The final result will have multiple cache services each defined by a unique databaseName. Each cache can have one or more stores also defined by a unique storeName. Other services will be able to use these stores:

mainCache                         = new Cache('main')
  ├── userStore                   = new Store(mainCache, 'user')
  │     ├── userService
  │     └── authenticationService
  │
  └── taskStore                   = new Store(mainCache, 'task')
        └── taskService

fooCache                          = new Cache('foo')
  └── barStore                    = new Store(otherCache, 'bar')

我当前的实现如下所示:

My current implementations look like this:

//indexeddb-cache.ts
import { Injectable } from '@angular/core';

@Injectable()
export class IndexedDBCache {
  constructor(
    protected databaseName : string
  ) {}
}

// indexeddb-store.ts
import { Injectable } from '@angular/core';
import { IndexedDBCache } from './indexeddb-cache';

@Injectable()
export class IndexedDBStore {
  constructor(
    protected database : IndexedDBCache,
    protected storeName : string
  ) {}
}

服务是经过分解的:

// test-api.cache.factory.ts
import { IndexedDBCache } from '../indexeddb-cache/indexeddb-cache';
import { IndexedDBStore } from '../indexeddb-cache/indexeddb-store';

// factory functions for FactoryProviders as exports instead of inline:
// https://github.com/rangle/angular-2-aot-sandbox#func-in-providers-usefactory-top
export function mainIndexedDBCacheFactory() { return new IndexedDBCache('main'); }
export function userIndexedDBStoreFactory(testIndexedDBCache: IndexedDBCache) { return new IndexedDBStore(testIndexedDBCache, 'user'); }
export function taskIndexedDBStoreFactory(testIndexedDBCache: IndexedDBCache) { return new IndexedDBStore(testIndexedDBCache, 'task'); }

然后提供:

// test-api.cache.ts
import { InjectionToken, Provider } from '@angular/core';
import { IndexedDBCache } from '../indexeddb-cache/indexeddb-cache';
import { IndexedDBStore } from '../indexeddb-cache/indexeddb-store';
import { mainIndexedDBCacheFactory,
         taskIndexedDBStoreFactory,
         userIndexedDBStoreFactory } from './test-api.cache.factory';

// Caches

export const mainIndexedDBCache = new InjectionToken<IndexedDBCache>('mainIndexedDBCache');

export let mainIndexedDBCacheProvider : Provider = {
  provide: mainIndexedDBCache,
  useFactory: mainIndexedDBCacheFactory
};

// Stores

export const userIndexedDBStore = new InjectionToken<IndexedDBStore>('userIndexedDBStore');

export let userIndexedDBStoreProvider : Provider = {
  provide: userIndexedDBStore, deps: [mainIndexedDBCache],
  useFactory: userIndexedDBStoreFactory
};

export const taskIndexedDBStore = new InjectionToken<IndexedDBStore>('taskIndexedDBStore');

export let taskIndexedDBStoreProvider : Provider = {
  provide: taskIndexedDBStore, deps: [mainIndexedDBCache],
  useFactory: taskIndexedDBStoreFactory
};

在主模块中声明:

// test-api-module.ts
import { NgModule, ModuleWithProviders } from '@angular/core';
import { mainIndexedDBCacheProvider,
         taskIndexedDBStoreProvider,
         userIndexedDBStoreProvider } from './test-api.cache';

@NgModule({
  imports: [], declarations: [], exports: []
})
export class TestAPIModule {
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: TestAPIModule,
      providers: [
        mainIndexedDBCacheProvider,
        userIndexedDBStoreProvider,
        taskIndexedDBStoreProvider
      ]
    };
  }
}

最后在服务中使用:

//user-service/user.service.ts
import { Inject, Injectable } from '@angular/core';
import { IndexedDBStore } from '../../indexeddb-cache/indexeddb-store';
import { userIndexedDBStore } from '../test-api.cache';

@Injectable()
export class UserService {
  constructor(
    @Inject(userIndexedDBStore) protected cache : IndexedDBStore
  ) {}
}

使用JIT编译器时,一切正常。尝试进行AoT编译时,我开始收到警告:无法解析y中的x的所有参数:(?)。对于缓存和存储服务的字符串参数,这将成为Angular v5.x中的错误

Everything works fine when using JIT compilers. When I'm trying to do AoT compilation I start receiving Warning: Can't resolve all parameters for x in y: (?). This will become an error in Angular v5.x for the string parameters of the cache and store service.

我之前已经详细介绍了我的问题在这个问题中:为AoT编译进行标记化。现在看来,使用AoT编译器完全不可能将字符串用作 @Injectable()的参数。如我所述,还有其他方法可以为使用字符串初始化的服务创建工厂吗?

I've detailed my issue before in this question: Tokenizing for AoT compilation. Now it looks like using strings as parameters for an @Injectable() is completely impossible with the AoT compiler. Is there any other way of creating a factory for services initialized using a string as I've described?

我已经在此存储库。检出 aot 分支和 npm install ,然后执行 npm运行build.prod.rollup.aot 应该就是这样。

I've created a workable example in this repository. Checkout the aot branch and npm install followed by npm run build.prod.rollup.aot should work just like that.

推荐答案


根据用户@estus和@Toxicable只能由 Factory 实例化的类本身不应为 @Injectable 本身。从 IndexedDBCache IndexedDBStore 类中删除此标记将解决此问题。

Based on feedback from users @estus and @Toxicable the class that will only be instanced by a Factory should not be @Injectable itself. Removing this tag from the IndexedDBCache and IndexedDBStore classes will resolve the issue.

工厂也必须采用特定形式

export function mainIndexedDBCacheFactory() { return new IndexedDBCache('main'); }

此定义的其他迭代将不起作用。

Other iterations of this definition will not work.

export const mainIndexedDBCacheFactory = function() { return new IndexedDBCache('main'); };
export let mainIndexedDBCacheFactory   = function() { return new IndexedDBCache('main'); };
export let mainIndexedDBCacheFactory   = () => new IndexedDBCache('main');

export 前缀是必需的,即使定义在同一文件中作为提供者

这篇关于创建兼容AoT的服务工厂的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆