depsi
is a nest.js like dependency injection library for Express.js (Node.js), provide progressive way to add super power to your old or new project!
- Progressive DI(Dependency injection) framework for Express.js
- Super lightweight - (8 kb source code)
- Supports both of CommonJS and ESM module.
- Support both of TypeScript and JavaScript (w/ tsconfig.json)
npm install depsi express @types/express
Make sure these options are true
in your tsconfig.json
experimentalDecorators
emitDecoratorMetadata
{
"compilerOptions": {
//... other options
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
You'll need to create 4 files to get started, here is our recommended setup.
// app.ts
import express from "express";
import { initializeModule } from "depsi";
import { appModule } from "./app.module.js";
async function main() {
const app = express();
initializeModule(app, appModule);
app.listen(3000, () => {
console.log("Server is running on port 3000");
});
}
main();
//app.service.ts
import { Injectable } from "depsi";
@Injectable()
export class Logger {
log(message: string) {
console.log(message);
}
}
//app.router.ts
import { createRouter } from "depsi";
import { Logger } from "./app.service.js"; // or "./app.service" if you are using CommonJS
import { appModule } from "./app.module.js";
// "/" is the prefix of the router
export const appRouter = createRouter("/");
appRouter.get("/hi", (req, res) => {
res.send("hi");
});
appRouter.get("/test", (req, res, next) => {
// we can resolve the Logger service from the appModule
const logger = appModule.resolve(Logger);
logger.log("log from /test");
res.send("hello world from /test");
});
//app.module.ts
import { appRouter } from "./app.router.js"; // or "./app.router" if you are using CommonJS
import { Module } from "depsi";
import { Logger } from "./app.service.js"; // or "./app.service" if you are using CommonJS
export const appModule = new Module({
imports: [],
providers: [Logger],
routes: [appRouter],
});
Now, run your app and see your log by hitting
curl localhost:3000/test
Modules are the basic building blocks in depsi. They allow you to group providers and routes together.
import { Module } from "depsi";
import { Logger } from "./app.service.js";
import { appRouter } from "./app.router.js";
export const appModule = new Module({
imports: [],
providers: [Logger],
routes: [appRouter],
});
Use the @Injectable
decorator to mark a class as a provider that can be injected.
import { Injectable } from "depsi";
@Injectable()
export class Logger {
log(message: string) {
console.log(message);
}
}
@Injectable()
export class Service {
constructor(private logger: Logger) {}
execute() {
this.logger.log("Service is executing...");
}
}
Injectable
class shoule be registered in a module always.
The order of providers matters, depsi
register providers from left to right.
export const appModule = new Module({
imports: [],
providers: [Logger, Service],
routes: [],
});
The module.resolve
function is used to resolve and get the instance for any Injectable
class.
import { createRouter, Depends } from "depsi";
import { Logger } from "./app.service.js";
import { appModule } from "./app.module.js";
const appRouter = createRouter("/");
appRouter.get("/test", (req, res, next) => {
const logger = appModule.resolve(Logger);
logger.log("log from /test");
res.send("hello world from /test");
});
Routers are used to define routes within a module, also depsi's Router
is compatible with Express.js.
import { createRouter, Depends } from "depsi";
import { Logger } from "./app.service.js";
export const appRouter = createRouter("/"); // define the prefix for the router
appRouter.get("/hi", (req, res) => {
res.send("hi");
});
Modules can import other modules to organize your application better.
import { Module } from "depsi";
import { Logger } from "./app.service.js";
import { appRouter } from "./app.router.js";
const subModule = new Module({
imports: [],
providers: [Logger],
routes: [],
});
export const appModule = new Module({
imports: [subModule],
providers: [],
routes: [appRouter],
});
If you have JS code mixed with TS code, this is the guide for it. Make sure you have these in the
tsconfig.json
{
"compilerOptions": {
//... other options
"allowJs": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
JavaScript doesn't provide type information in class constructor that allows us to inject in a normal way. Fortunatelly we can inject in by @Inject(class)
.
import { Injectable, Inject } from "depsi";
@Injectable()
export class TestLogger {
/**
* Optional type declaration
* @param {Logger} logger
*/
constructor(@Inejct(Logger) logger) {
logger.log("TestLogger");
}
}
Other usage are all the same. Please keep in mind this special usage is for vanilla javascript only.
Contributors: Jun Guo @gjuoun