How to use global variables in nest.js? - node.js

Taking configuration as an example, the Nest.js documentation advocates registering Config Modules and injecting them into other modules in a dependency injection way.
The benefits are obvious, and the dependencies and code are clear, but what if I have a nest.js project that needs to invoke the configuration information at startup? This actually caused me trouble.
My idea is to use a store (actually a closure) to manage all the variables that might be needed globally, the client-side link objects, registered at startup, and introduced when needed.
When corresponding variables are registered in this way, they can be introduced anywhere. The drawback is that you need to manage dependencies yourself.
With the above concept design of demo: https://github.com/sophons-space/nest-server.
Please e help me correct, I am still a rookie.

If you want to use Nest flow it should be defined in the configuration file
// app.module.ts
import configuration from './config/configuration';
imports: [
// first import as first initialization
ConfigModule.forRoot({
isGlobal: true, // to get access to it in every component
load: [configuration],
}),
]
...
// configuration.ts
export default (): any => {
return {
someGlobalConfigVariable: parseInt(process.env.PORT, 10) || 3000,
};
};

Create a file global.service.ts (inside a folder you can name it utils or whatever) & put the code bellow
export class GlobalService{
static globalVar: any;
}
Set value to the globalVar
GlobalService.globalVar = 'some value';
Get value from globalVar
console.log(GlobalService.globalVar);
N.B. Don't forget to import GlobalService wherever you want to use.

The way you can approach this is similar to how NestJS libraries or integrations usually handle configuration; using a method on the base module.
main.ts
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
// Note the `configure`-method
const app = await NestFactory.create(AppModule.configure({
myConfig: 'value',
});
await app.listen(3000);
}
bootstrap();
app.module.ts
import { DynamicModule } from '#nestjs/common';
export class AppModule {
static configure(config): DynamicModule {
return {
module: AppModule,
providers: [{ provide: 'CONFIG', useValue: config }],
// ....
}
}
}

You can use the general NodeJS approach
global.SomeGlobalVariableName = 'SomeGlobalVariableValue';
console.log(SomeGlobalVariableName);

Approach I used is using my config variables in yaml files and then getting those variables or objects wherever I want in my Nestjs project using config package. e.g in default.yml file
key: value
and then in file where I want to use this
import config from 'config';
let value = config.get<string>('key');
you can take this pkg from this npmjs link here

Why not go with more NestJs way i.e. with provide instance scope?
Most of the answers posted here are correct and easy to implement but I have a more generic way to define that variable that fits well in NestJs (Nestjs Scope and Dependency Injection flow). I would be happy to share the sample code, if required
Steps
Create a provider
Add a private instance variable to this provider - instead of a class variable (i.e. static variables) use an instance variable as NestJs automatically (by default) manages the instance of its providers in a singleton way i.e. a single instance of the provider is shared across the entire application. Read more about scopes here
Add get/set and other methods for that variable
Inject that provider wherever you need the global variable (instance variable of the provider(per instance).
Other ways of doing it
Config - preferrable for pre-defined types(like string, number...)
Static variable in util.ts file
Native Global variable - I would not recommend this(explanation is outside the scope of the question)

Related

(webpack) How to import webpack bundled modules as one instance in all require

I am implementing server-side rendering using react and express. So, I am using the context of react in Express.
However, the problem is that every time the context below is requeried, a new context is created and the context cannot be shared by other modules.
import { createContext, ReactElement } from "react";
type State = {
main: ReactElement | null;
srcList: Array<string> | null;
};
export default class Context {
static HtmlContext = createContext<State>({
main: null,
srcList: [],
});
}
What I wanna know is how to import webpack bundled modules as one instance in all require.
Similar to the singleton pattern, I was trying to find a webpack configuration that allows only one instance to be shared. And I was trying to use optimization option with runtimeChunk: 'single'. But it didn't work well and I don't know if I understood it well...
I would be very grateful if you could learn how to approach it.

How to import an Interface from a dependency of a dependency

Simple question, we have a custom package that uses axios as a dependency and exports a function that returns an Axios Client with some custom default configuration. The problem is that I want the AxiosInstance interface that is not exported from the package itself and axios it's not a dependency in my project.
// #myCustomDep
import { AxiosInstance } from 'axios';
export function createAxiosClient(): AxiosInstance { //... }
// Main project
import { createAxiosClient } from '#myCustomDep';
// Err: Cannot find name 'AxiosInstance'.
function buildClient(): AxiosInstance {
const axiosClient = createAxiosClient();
return axiosClient;
}
What would be the correct way of handling this import without modifying the underlying dependency (if possible)?
As long as it is a dependency of your dependency, you may very well also list it as your own dependency.
But even without doing so, you can still directly import from a transitive dependency.
TypeScript will only complain if it cannot find it in your node_modules, whether you have listed it as a dependency or not.
You can also use TypeScript utility types: ReturnType<typeof createAxiosClient>
https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype
Obviously, if possible, you would have your custom dependency re-export whatever is exposed by its API.

What are the benefits of using the Nestjs testing module for unit tests?

In the Nestjs documentation, they suggest using their Test module for instantiating any objects used for testing, like so:
const adoptionServiceMock = {
adoptCat: jest.fn()
};
const moduleRef = await Test.createTestingModule({
providers: [CatsService, { provider: AdoptionService, useValue: adoptionServiceMock }],
}).compile();
catsService = moduleRef.get<CatsService>(CatsService);
What is the benefit of doing it this way, as opposed to regular instantiation? Here's an example of the regular way:
const adoptionServiceMock = {
adoptCat: jest.fn()
} as AdoptionService;
catsService = new CatsService(adoptionService);
I'm specifically referring to using catsService = moduleRef.get<CatsService>(CatsService) instead of newing up a CatsService.
The one thing I can think of is that it does object instantiation the same way Nestjs would do it in production - with DI. If you forget to add Inject() on CatsService or AdoptionService, the test will fail.
If you don't find benefit in it, you absolutely can use whatever method you prefer for mocking. The Test.createTestingModule is there to provide uniformity between Nest projects and to provide an easy way to give mocks to the classes without having to use as whatever, but if you prefer that method, then go for it.
It becomes more powerful out at the e2e/integration level where you can mock guards and other enhancers with fluent methods, but again, the final test implementation is absolutely up to you.
I personally like it cause I can delegate Nest to create providers based off of a class and mock things from there, like a TypeORM repository can be created as
{
provide: getRepositoryToken(EntityClass),
useClass: Repository,
}
No need to extensively create a lot of methods, then later I can use jest.spyOn() or jest.fn() to override the default functionality.

Put data on ServersideProps

Is it possible to get data from server side's config file on client by getServersideProps() in Next.js? How to put data in props? Or how to get it on client in other way?
I have tried publicRuntimeConfig in next.config.js, but it is undefined and I don't know why...
It's hard to tell exactly what's going on but I have one idea from experience: You need to make sure you're calling nextJSApp.prepare() before any modules using next/config are included.
As an example,
// SomeComponent.tsx
import { getConfig } from 'next/config'
const config = getConfig()
export interface X { ... }
// server.ts
import { X } from './SomeComponent'
app.prepare().then(...)
This fails because module are loaded first and the config hasn't been initialized until app.prepare has been completed.
The solution for this is to either use TypeScript's import(...) syntax if you just need a type or use node's require for dynamic resolution during runtime.

Need to export classes for NPM package

I am building an NPM package and am looking for the best way to export my classes.
Right now, I am using this:
import {Swan} from './Swan';
import {Route, Router} from './Router';
import {View, TemplateView, IView} from './views';
export { Route, Router, Swan, View, TemplateView, IView };
This works. The only thing is, of course, each time I add a new class, I have to update the export statement.
Is there a way to export all the classes in all the files I specify without having to update the export statement here?
Is there a way to export all the classes in all the files I specify without having to update the export statement here?
There is no automatic "export everything" or export all classes in Javascript.
But, you could change how you define your classes so they are part of an internal object and you just export that object.
const myExports = {
TemplateView: class TemplateView {
...
},
iView: class iView {
...
}
};
export default myExports;
When you add a new class to this structure, it automatically becomes part of the exports.
On the other hand, I personally don't see what the big deal is to maintain the export list when you add a new item to the module that you want exported. Exports are SUPPOSED to be a thoughtful list of things that only contains the items that need to be exported and does not contain other functions used locally as part of the implementation. The only way that it can be a thoughtful list is if it's not automatic.

Resources