Що таке Ditsmod
Ознайомлення з Ditsmod
Ditsmod - це веб-фреймворк на базі Node.js, призначений для створення добре-розширюваних та швидких застосунків, його назва складається з DI + TS + Mod, щоб підкреслити важливі складові: він має Dependency Injection, написаний на TypeScript у форматі ESM, та спроектований для хорошої Модульності.
Головні особливості Ditsmod
- Модульна архітектура на декораторах, що дозволяє декларативно описувати структуру застосунку.
- Можливість написання власних розширень (інколи їх називають плагінами), що можуть асинхронно ініціалізуватись, і що можуть залежати один від одного.
- Має підтримку OpenAPI, та має можливість проводити валідацію запитів на основі метаданих OpenAPI.
- На сьогодішній день, Ditsmod є одним із найшвидших серед Node.js веб фрейм ворків:

Деякі концепції архітектури Ditsmod взяті з Angular концепцій, а DI побудована на базі нативного модуля Angular DI.
ExpressJS vs. Ditsmod
Для порівняння, в наступних двох прикладах показано мінімальний код для запуску ExpressJS та Ditsmod застосунків.
import express from 'express';
const app = express();
app.get('/hello', function (req, res) {
ctx.send('Hello, World!');
});
app.listen(3000, '0.0.0.0');
import { controller, route, restRootModule, RestApplication } from '@ditsmod/rest';
@controller()
class ExampleController {
@route('GET', 'hello')
tellHello() {
return 'Hello, World!';
}
}
@restRootModule({ controllers: [ExampleController] })
class AppModule {}
const app = await RestApplication.create(AppModule);
app.server.listen(3000, '0.0.0.0');
Але чому Ditsmod не такий мінімалістичний, як ExpressJS? Як бачите в прикладі, ExpressJS створює об'єкт застосунку, в якому потім додає роути. В об'єкті app представлено API різних окремих складових, зокрема: налаштування роутера, налаштування обробки помилок, налаштування системи рендерінгу, HTTP-сервера і т.д. Такий код у простих прикладах виглядає дуже компактно, але у ньому по-суті порушується Принцип єдиної відповідальності. Натоміс ть в Ditsmod чітко розмежовано:
- роль контролера, в якому створюється роут;
- роль модуля, в якому задекларовано контролери;
- роль застосунку, який містить HTTP-сервер.
Оцінюючи об'єм коду, можна припустити, що через свою багатослівність, Ditsmod є повільнішим за ExpressJS. Але насправді трохи повільнішим є лише холодний старт Ditsmod (на моєму ноутбуку він стартує за 34 ms, тоді як ExpressJS стартує за 4 ms). Що стосується швидкості обробки запитів, то Ditsmod швидший за ExpressJS на ~30%.
Більше прикладів застосунку є у репозиторію Ditsmod, а також у репозиторію RealWorld.
P.S. Хоча нижче надано лінк на репозиторій з усіма необхідними налаштуваннями для Ditsmod-застосунків, але, все ж таки, якщо ви захочете використати лише код з попереднього прикладу, незабудьте у tsconfig-файлах прописати наступне:
{
"compilerOptions": {
// ...
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
Попередні умови
Будь-ласка, переконайтесь що на вашій операційній системі встановлено Node.js >= v20.6.0.
Встановлення
Ви можете встановити пакет @ditsmod/cli глобально, щоб створити новий застосунок:
npm i -g @ditsmod/cli
dm new my-app
cd my-app
Або без попереднього встановлення через npx:
npx @ditsmod/cli new my-app
cd my-app
Також ви можете створити дефолтний REST-застосунок або монорепозиторій:
dm new my-app
Основні опції команди new:
-t, --template <name>— стартовий шаблон (rest,rest-monorepo,trpc-monorepo).-m, --package-manager <name>— менеджер пакетів (npm,yarn,pnpm).--skip-install— пропустити автоматичне встановлення залежностей.
Додайте AGENTS.md та SKILL.md для ШІ-агентів
Файл AGENTS.md призначений для ШІ-агентів, його треба встановлювати в кореневу директорію репозиторію. Цей файл буде братись до уваги ШІ-агентом кожен раз, коли ви звертаєтесь до агента. Щоб скопіювати самий свіжий AGENTS.md, запустіть наступну команду:
cd my-app # Перехід до стартового репозиторію
npm run setup:agents
Додатково можна встановити ще й скіли для ШІ-агентів, щоб вони краще розуміли особливості Ditsmod-застосунків:
npx skills add ditsmod/agent-skills
Ця команда дасть на вибір усі доступні скіли. Якщо ж ви хочете встановити усі офіційни скіли для Ditsmod, це можна зробити так:
npx skills add ditsmod/agent-skills --skill '*' -y
Скіли ШІ-агентами зчитуються лише у разі потреби, коли ви запитуєте щось релевантне у них.
Запуск в режимі розробки
Стартувати застосунок в режимі розробки можна за допомогою команди:
npm run start:dev
Або безпосередньо через Ditsmod CLI:
ditsmod start
# або за допомогою аліасу:
dm start
Утиліта @ditsmod/cli автоматично виконує інкрементальну компіляцію TypeScript та перезапускає Node.js сервер при зміні файлів, тому більше не потрібно відкривати декілька терміналів окремо для компілятора та сервера.
Ви можете налаштувати поведінку запуску за допомогою опцій:
-d, --debug [hostport]— запуск Node.js у режимі налагодження з прапорцем--inspect.--verbose— детальний вивід процесу збірки TypeScript Project References.--restart-delay <ms>— затримка в мілісекундах перед перезапуском сервера після успішної компіляції (за замовчуванням300).--watch-assets <globs...>— не-TypeScript файли (наприклад,.json), які потрібно копіювати вdist/при змінах.
Перевірити роботу сервера можна за допомогою curl:
curl -i localhost:3000/api/hello
Або просто перейшовши у браузері на http://localhost:3000/api/hello.
По дефолту, застосунок працює з деталізацією log level на рівні info. Змінити його можна у файлі src/app/app.module.ts (або apps/backend/src/app/app.module.ts у монорепозиторію).
Завдяки використанню у ditsmod/rest-starter так званих Project References і режиму збірки tsc -b, навіть дуже великі проекти компілюються дуже швидко.
Зверн іть увагу, що у репозиторії ditsmod/rest-starter є чотири конфіг-файли для TypeScript:
tsconfig.json- базова конфігурація, що використовується вашою IDE (у більшості це мабуть VS Code).tsconfig.build.json- ця конфігурація використовується для компіляції коду з текиsrcу текуdist, вона призначається для коду застосунку.tsconfig.e2e.json- ця конфігурація використовується для компіляції коду end-to-end тестів.tsconfig.unit.json- ця конфігурація використовується для компіляції коду юніт-тестів.
Окрім цього, зверніть увагу, що завдяки тому, що ditsmod/rest-starter оголошено як EcmaScript Module (ESM), для скорочення шляху до файлів ви можете використовувати нативні аліаси Node.js. Це аналог compilerOptions.paths у tsconfig. Такі аліаси оголошуються у package.json у полі imports:
"imports": {
"#app/*": "./dist/app/*"
},
Тепер ви можете використовувати його, наприклад у теці e2e, ось так:
import { AppModule } from '#app/app.module.js';
На даний момент (2025-10-07) TypeScript ще не у повній мірі підтримує ці аліаси, тому бажано їх продублювати у файлі tsconfig.json:
// ...
{
"compilerOptions": {
// ...
"paths": {
"#app/*": ["./src/app/*"]
}
}
}
Зверніть увагу, що у package.json аліаси вказують на dist, тоді як у tsconfig.json - на src.
Запуск в продуктовому режимі
Компіляція застосунку та запуск сервера в продуктовому режимі відбувається за допомогою команди:
npm run build
npm run start-prod
Вхідний файл для Node.js
Після встановлення Ditsmod starter, перше, що необхідно знати: весь код застосунку знаходиться у теці src, він компілюється за допомогою TypeScript-утиліти tsc, після компіляції попадає у теку dist, і далі вже у вигляді JavaScript-коду його можна виконувати у Node.js.
Давайте розглянемо файл src/main.ts:
import { ServerOptions } from 'node:http';
import { RestApplication } from '@ditsmod/rest';
import { AppModule } from './app/app.module.js';
import { checkCliAndSetPort } from './app/utils/check-cli-and-set-port.js';
const serverOptions: ServerOptions = { keepAlive: true, keepAliveTimeout: 5000 };
const app = await RestApplication.create(AppModule, { serverOptions, path: 'api' });
const port = checkCliAndSetPort(3000);
app.server.listen(port, '0.0.0.0');
Після компіляції, він перетворюється на dist/main.js та стає вхідною точкою для запуску застосунку у продуктовому режимі, і саме тому ви будете його вказувати у якості аргументу для Node.js:
node dist/main.js
Проглядаючи файл src/main.ts, ви можете бачити, що створюється інстанс класу RestApplication, а у якості аргументу для методу create() передається AppModule. Тут AppModule є кореневим модулем, до якого вже підв'язуються інші модулі застосунку.