Closed xmlking closed 6 years ago
Went one better (I think). I just added you as a collaborator on a barebones repo illustrating the issue.
Put in your project config and you should get the issue right away.
@JefferE Push the commit. Currently, it's on initial commit.
@SachinShekhar, Sorry, pushed now.
@JefferE I checked. Your code is correct. Firebase config is getting passed to the library with correct type. But, due to some mysterious reasons, AngularFireModule has problem with it (interestingly, my multiple projects are working fine with the same code).
I strongly believe that the issue is with AngularFireModule's dependencies (I didn't have time to check everything). Good luck debugging it.
After solving the issue, let me know what the issue was. I am interested.
ok, perhaps a versioning issue somewhere in dependencies.
I'll check it out. Thanks a bunch!
@SachinShekhar, if you could when you have time, post your nx package.json so I have something to compare to at that basic level?
@JefferE I tried to debug your code (because issue is interesting). The issue is: AngularFireModule is being initialized before static data is set in FirebaseConfig service. To solve this, lazy-load the module using @wishtack/reactive-component-loader (You need to create a new module in the same library which return a ModuleWithProvider having FirebaseService and AngularFireModule; keep the setting of static data separate). It works with AOT compilation.
Or, to simplify things, just initialize AngularFireModule in app module and remove the initialization from library module.
@SachinShekhar, ok, I'll give that loader a try.
I tried initializing in the root module long ago and it didn't work (my FirebaseService wouldn't have the config it needed), that's what led me to try passing the config to the shared lib, which made me find this thread.
@SachinShekhar Following your example, I've just tried to do the same thing (but with Ngxs instead of Firebase). From my app.module I'm passing { production: true }
so the logger plugin (initialized in store.module.ts) should be initialized with disabled: true
.
Made this stackblitz: https://stackblitz.com/edit/ngxs-app-initializer?file=src%2Fapp%2Fstore%2Fstore.module.ts
And it seems that Ngxs & plugins initialize before APP_INITIALIZER runs/resolves:
prev state
next state
APP_INITIALIZER
APP_INITIALIZER Resolved
NGXS Logger shouldn't log anymore (but it does)
payload
prev state
next state
Angular is running in the development mode. Call enableProdMode() to enable the production mode.
Anyway, I shouldn't even see the first 2 lines because nothing should be allowed to happen before APP_INITIALIZER, right? Could it be that the same thing happens for firebase initialization also (initializing wrongly, without the appropriate config), only that that config is "updated" at a later time, when APP_INITIALIZER resolves?
EDIT: by the way, it doesn't work when building for production: Function expressions are not supported in decorators
.
@SachinShekhar - Been a while since I reported here but your suggestion worked ('just initialize AngularFireModule in app module and remove the initialization from library module).
However, I'm having he same issue as @MrCroft above, this whole approach doesn't work when building for production - I get the same 'Function expressions are not supported in decorator' as he is getting.
It doesn't really bother me at the moment as I'm not building for production yet and I'm looking into it but figured I'd mention it as soon as possible.
export class SharedDataAccessFirebaseServiceModule {
static config(data: ModuleConfig): ModuleWithProviders {
return {
ngModule: SharedDataAccessFirebaseServiceModule,
providers: [
FirebaseConfigService,
{
provide: APP_INITIALIZER,
multi: true,
useFactory: (firebaseConfig: FirebaseConfigService) => () => {
firebaseConfig.setFirebaseConfig(data);
},
deps: [FirebaseConfigService]
}
]
};
}
}
It doesn't like this part:
useFactory: (firebaseConfig: FirebaseConfigService) => () => {
firebaseConfig.setFirebaseConfig(data);
},
I had this same issue and this thread was helpful to give me ideas to try. I have a library module that I'm trying to setup google maps in (@agm/core), which requires you pass the google maps api key in the forRoot method. I found no other way to set that key.
After none of the ideas in this thread worked, I was able to get it working by simply not calling the forRoot method in the library module, and instead calling it in my app module. My app module did not need the AgmCoreModule reference in it's 'imports' but I added it there anyway and did the forRoot call there, where I have my environment variable available. Then, in the library module, I just used 'AgmCoreModule' in the 'imports', without the '.forRoot(...)' part.
What about react app, how can I get environments for react libs?
I was following this article: https://indepth.dev/tiny-angular-application-projects-in-nx-workspaces/#extract-an-environments-workspace-library, which creates a separate shared environment lib, and then simply exports the environment constant in index.ts, and imports it where used. E.g. a shared NgRx store lib that cuts across all other NgRx feature stores can have dev tools toggled via a single environment constant.
I guess the injector tokens approach, where the app-specific environment variables are injected in the app app.module.ts, works too.
@adamm-monek thanks for the answer, I almost did the same as described in the article :)
Is there a way to 'inject' stuff into modules and use it there, @vsavkin ? I created a stackoverflow question, I'd appreciate an answer on stackoverflow, or here :)
Imo the best way to share env variables is to do something like this:
import {config} from '../environments/environment'; @NgModule({ providers: [ { provider: 'someEndpointUrl', useValue: config.someEndpointUrl } ] }) class AppModule { }
Then do this somewhere in your lib:
@Component({...}) class MyComponent { constructor(@Inject('someEndpointUrl') endpointUrl: string) { } }
- It keeps your libs env independent.
- It allows you to build libs once, without knowing the apps they are used by or the env they ran in. In CLI 1.x this isn't a big deal, but it will get more important once we start more aggressively cache the results of lib compilation.
Using
@env/
has some advantages though. It allows to use to improve treeshaking in some situations.
Hi,
Using the method @vsavkin suggested, how would I provide the environment
var into the service .spec files in the /libs?
I know I can use the following code to solve it but it's definitely not right to import directly from the /apps.
import {environment} from '../../../../../../apps/my-app/src/environments/environment';
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
{
provide: 'environment', useValue: environment
}
]
});
Thank you.
Imo the best way to share env variables is to do something like this:
import {config} from '../environments/environment'; @NgModule({ providers: [ { provider: 'someEndpointUrl', useValue: config.someEndpointUrl } ] }) class AppModule { }
Then do this somewhere in your lib:
@Component({...}) class MyComponent { constructor(@Inject('someEndpointUrl') endpointUrl: string) { } }
- It keeps your libs env independent.
- It allows you to build libs once, without knowing the apps they are used by or the env they ran in. In CLI 1.x this isn't a big deal, but it will get more important once we start more aggressively cache the results of lib compilation.
Using
@env/
has some advantages though. It allows to use to improve treeshaking in some situations.
@vsavkin
I realize you posted this in 2018, however, what would be your intended method of sharing these environment variables across library modules in NestJs? Does every library module that need access to environment variables need to be a dynamic module in order to take advantage of environment variables this way? What would this do to performance?
Example:
@Module({})
export class MyLibModule {
static register(providers: Provider[]): DynamicModule {
return {
module: MyLibModule ,
providers: [...providers],
};
}
}
const ENV_VALUE_PROVIDERS: ValueProvider[] = [
{
provide: 'PRODUCTION',
useValue: environment.production,
},
];
@Module({
providers: ENV_VALUE_PROVIDERS,
imports: [MyLibModule.register(ENV_VALUE_PROVIDERS)],
})
export class AppModule {}
I do not understand why we are forcing any lib modules to be dynamic to access environment variables if these variables are available at compile-time.
anyone has a best practices for React? I have a data-access lib which has all redux code related including the async actions to fetch the api.
What would be a good practice to read env variables values from within the data-access lib?
Reading this thread I still got lost on how to do something like following and what to replace this with
imports: [
!environment.production ? StoreDevtoolsModule.instrument() : [],
]
I understand you can use providers to pass environment to classes but how to use to determine imports for modules? I'm going to use example here https://github.com/trungk18/angular-spotify
Namely, a web shell that has build-specifics determined by fileReplacements
"fileReplacements": [
{
"replace": "apps/angular-spotify/src/environments/environment.ts",
"with": "apps/angular-spotify/src/environments/environment.prod.ts"
},
{
"replace": "libs/web/shell/feature/src/lib/build-specifics/index.ts", <---------------------------
"with": "libs/web/shell/feature/src/lib/build-specifics/index.prod.ts"
}
],
This issue has been closed for more than 30 days. If this issue is still occuring, please open a new issue with more recent context.
in my lib module
CoreModule
I need to accessenvironment
which part of my appmyapp
libs/core/src/core.module.ts
TSLint is complinting this kind of inport.
looking for guideline how we can share app's
environment
with lib module.