generator-angular2-library
generator-angular2-library copied to clipboard
Adding Library configs using `forRoot()` and `InjectionToken`
I'm having trouble adding library configs using forRoot()
and InjectionToken
.
When passing in environment variables via forRoot(config)
, I can access the variables in the forRoot
method, but they are not injecting into services.
I've added some comments in my sample code to show where things are breaking.
I originally generated my project using [email protected]
app.module.ts (App that uses Library)
@NgModule({
declarations: [AppComponent],
imports: [
CoreModule.forRoot(environment) // {key: 'foobar'}
],
providers: [...],
bootstrap: [AppComponent],
})
export class AppModule { }
index.ts (Library)
import { NgModule, ModuleWithProviders } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Config, LIB_CONFIG } from './config';
import { FooService } from './foo.service';
@NgModule({
imports: [CommonModule],
providers: [FooService],
})
export class CoreModule {
static forRoot(config: Config): ModuleWithProviders {
console.log(config); // prints: `{key: 'foobar'}`
return {
ngModule: CoreModule,
providers: [
{provide: LIB_CONFIG, useValue: config} // If I hard code `useValue: {key: 'FooBar'}`, instead of using `config` it works... weird.
],
};
}
}
config.ts (Library)
import { InjectionToken } from '@angular/core';
export interface Config {
key?: string;
}
export const LIB_CONFIG = new InjectionToken<Config>('LIB_CONFIG');
foo.service.ts (Library)
import { Inject, Injectable } from '@angular/core';
import { Config, LIB_CONFIG } from './config';
@Injectable()
export class FooService {
private key: string;
constructor(
@Inject(WEB_CONFIG) private config: Config,
) {
console.log(config); // prints: `undefined`
this.key = config.key; // can't read property 'key' of undefined
}
Hey, I've got exactly same issue but with one difference: this occurs only with -prod enabled
Anyone found a solution on this?
Well, I didn't - I think wrote some workaround - but will be back at the problem in next days/week. … and last thing I've established was that problem is more in my consuming project rather than builded module (try to create clean project via ng new and install module, than build prod - it might work… if so problem is in building consuming project)
The problem is in the consuming project, yes. Will keep on digging and if I find something will report my findings
You mentioned that you get this bug only with -prod enabled, so I guess it has to do with AoT compiler and the statement cannot be parsed ahead. But there is a trick that worked for me by using the spread operator. You can try this in your provider definition:
providers: [
...[{provide: LIB_CONFIG, useValue: config}]
]
or if you wanna provide a default config as a fallback you can do this way:
...(config) ? [{provide: LIB_CONFIG, useValue: config}] : [{provide: LIB_CONFIG, useValue: new DefaultConfig()]
Thanks, @jotwea. That's interesting.
We abandoned this library and moved on to doing things a different way. I can't easily test to validate that it resolves the issue, but maybe @vonsko or @gkaran can speak to it.
@brentchow : I am little confused. Is there a reason behind adding "WEB_CONFIG" while injecting to the service - FooService. I believe you will have only LIB_CONFIG instance which is an object - {key:'foobar'} when the angular container is initialised.
I am unsure if this will work though, but can you remove providers altogether from the @NgModule in CoreModule and add it to static forRoot() injector like this
static forRoot(config: Config): ModuleWithProviders { console.log(config); return { ngModule: CoreModule, providers: [FooService, {provide: LIB_CONFIG, useValue: config} ], }; }
Also I believe using console.log before the return statement in forRoot() static method causes issues with both AOT and JIT compilation . So please avoid it incase you encounter the exception Error during template compile of 'AppModule' Function calls are not supported in decorators
This actually worked for me in a sample project. I use the following versions `Angular CLI: 6.0.8 Node: 8.11.1 OS: darwin x64 Angular: 6.1.1 ... common, compiler, compiler-cli, core, forms, http ... language-service, platform-browser, platform-browser-dynamic ... router
Package Version
@angular-devkit/architect 0.6.8 @angular-devkit/build-angular 0.6.8 @angular-devkit/build-optimizer 0.6.8 @angular-devkit/core 0.6.8 @angular-devkit/schematics 0.6.8 @angular/animations 6.1.3 @angular/cdk 6.4.5 @angular/cli 6.0.8 @angular/material 6.4.5 @ngtools/webpack 6.0.8 @schematics/angular 0.6.8 @schematics/update 0.6.8 rxjs 6.2.2 typescript 2.7.2 webpack 4.8.3`
@brentchow hi, I have the error function calls are not supported in decorators but ... was called
when i use --prod
, can you give me a solution ? thanks a lot.
@gkaran hi, Have you found a solution?
Sorry @deepthan nothing new to report as I too abandoned this and converted into an angular/cli library project
@vijayakumar-psg587 can you please share git repo location for sample project?
Hey @brentchow, could you share that "different way" of doing this? I'm facing similar problems. Thanks.
@brentchow hi, I have met the same error when I use --prod to build my consume project. could you please give me some advise?
Same issue here. Can't use 'of()' operator in the forRoot() when using prod build
ComponentLibraryModule.forRoot({
appLinks: of(APP_LINKS)
}),
Works and build OK in non prod. Prod build results in: ERROR in src\app\app.module.ts(100,22): Error during template compile of 'AppModule' Function calls are not supported in decorators but 'of' was called.
I realized a simple fix workaround for it is to wrap the observable within a function, ie:
export function appLinksFactory(): Observable<AppLinks[]> {
of(APP_LINKS)
}
ComponentLibraryModule.forRoot({
appLinks: appLinksFactory
}),
You will obviously have to change your configuration object to match, but this works ok and builds in all environments
Any one noticed the use of LIB_CONFIG
and WEB_CONFIG
?