Reputation: 428
I was coding a NodeJS server-side using Typescript, when I came across this scenario. I created a class Secret
to provide me with the environment variables set. Here is it.
import Logger from './logger';
import dotenv from 'dotenv';
import * as fs from 'fs';
class Secret {
private ENVIRONMENT: string;
public constructor() {
this.setEnvironmentVaribales();
}
private setEnvironmentVaribales(): void {
if (fs.existsSync('.env')) {
Logger.logError('Using .env file to supply config environment variables');
dotenv.config({ path: '.env' });
} else {
Logger.debug('Using .env.mm file to supply config environment variables');
dotenv.config({ path: '.env.mm' });
}
this.ENVIRONMENT = process.env['NODE_ENV'];
}
public get environment(): string {
return this.ENVIRONMENT;
}
}
export default Secret;
I then imported the Secret
to 'Logger
where I initialize my logger. Here is the code in logger.ts
import * as Winston from 'winston';
import Secret from './secret';
class Logger {
private logger: Winston.Logger;
private secret: string;
public constructor() {
this.secret = new Secret().environment;
console.log(this.secret);
this.initializeLogger();
}
/**
* Initializes the winston logger
*/
private initializeLogger(): void {
this.logger = Winston.createLogger({
transports: [
new (Winston.transports.Console)({
level: Secret.ENVIRONMENT === 'production' ? 'error' : 'debug'
}),
new (Winston.transports.File)({
filename: 'debug.log',
level: 'debug'
})
]
});
if (Secret.ENVIRONMENT !== 'production') {
this.logger.debug('Logging initialized at debug level');
}
}
}
export default new Logger();
The problem is that Iam not getting the intended value in my this.string
. Infact the new instance of Secret
does not seem to be generating. Iam getting undefined
as the result for the environment
variable in Logger
.
Am I doing anything wrong here.
The only way it seems to work for me is when I change my Secret
to export like this.
import Logger from './logger';
import {dotenv} from 'dotenv/config';
import * as fs from 'fs';
if (fs.existsSync('.env')) {
Logger.logError('Using .env file to supply config environment variables');
dotenv.config({ path: '.env' });
} else {
Logger.debug('Using .env.mm file to supply config environment variables');
dotenv.config({ path: '.env.mm' });
}
export const ENVIRONMENT = process.env['NODE_ENV'];
Or is it the circular dependency that is preventing it. Logger
in Secret
and Secret
in Logger
. If that is the case, I've even tried removing Logger
import from Secret
and used console.log()
. But, still does not work the way I want it to be.
Upvotes: 0
Views: 99
Reputation: 23762
Yes, there is a circular dependency here:
logger.ts
, the exported member is an instance of Logger
: export default new Logger()
Logger
, the class Secret
is instantiated: new Secret().environment
Secret
, the member setEnvironmentVaribales()
is called, which uses the exported instance of Logger
synchronously.Your current solution is not valid too:
if (fs.existsSync('.env')) {
Logger.logError('Using .env file to supply config environment variables');
dotenv.config({ path: '.env' });
} else {
Logger.debug('Using .env.mm file to supply config environment variables');
dotenv.config({ path: '.env.mm' });
}
export const ENVIRONMENT = process.env['NODE_ENV'];
Here, Logger
can't have the content of ENVIRONMENT
before you export it.
The best solution is to NOT import the logger from secret.ts
, because the Logger needs the content of this file to be completely executed first.
If you really need cross references, it'll work if your classes don't use each other from their constructors.
In any case, if the logger needs the secret before to do its job, you can't ask it to work before to give it that secret.
Upvotes: 1