Создаем приложение на Node.JS, Express и Typescript
Пошаговая инструкция создания приложения на Node.JS, которое использует typescript и express. Пригодится для Backend'а нового приложения.
Создание файла package.json
Создадим директорию с проектом, встанем в нее и командой создадим файл package.json:
mkdir app
cd app
npm init --yes
Установка Typescript
npm install --save-dev typescript @types/node
npm install reflect-metadata
Создаем файл конфигурации /tsconfig.json:
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"lib": ["es6"],
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"outDir": "./dist",
"baseUrl": "./",
"rootDir": "./src",
"sourceMap": false,
"allowJs": true,
"strict": true,
"noImplicitAny": true,
"resolveJsonModule": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
},
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modules"
]
}
Расшифровка конфигурации:
allowSyntheticDefaultImports - позволяет менять схему импорта.
Если true, то
import express from 'express'
Если false, то
import * as express from 'express'
esModuleInterop - устранение проблем с транслитерацией кода. За счёт добавления болерплейта в выходной код, позволяет импортировать CommonJS пакеты как ES6. Также если она в значение true, то автоматически включается allowSyntheticDefaultImports
Создание сервера Express с минимальной конфигурацией
После инициализации файла package.json, установим пакеты для express'а:
npm install dotenv express cors
npm install --save-dev @types/express @types/cors
Далее создадим файл src/index.ts:
import express, { Express, Request, Response } from 'express'
import dotenv from 'dotenv'
dotenv.config()
const app: Express = express()
const port = process.env.PORT
app.get('/', (req: Request, res: Response) => {
res.send('Express + Typescript Server')
})
app.listen(port, () => {
console.log(`⚡️[server]: Server is running at http://localhost:${port}`);
})
Настройка сборки в package.json
Установка пакетов:
npm install --save-dev rimraf concurrently nodemon ts-node
Добавляем файл /nodemon.json:
{
"watch": ["src"],
"ext": ".ts,.js",
"ignore": [],
"exec": "npx ts-node ./src/index.ts"
}
Изменяем /package.json:
...
"main": "dist/index.js",
"scripts": {
"start": "npm run build && node ./dist/index.js",
"build": "rimraf ./dist && npx tsc",
"dev": "nodemon"
},
...
Добавление типизации для .env и файла с конфигом
Установка пакетов:
npm install if-env --save
Изменим /package.json
"scripts": {
"start": "if-env ENV=production ?? npm run start:prod || npm run start:dev",
"start:dev": "nodemon",
"start:prod": "npm run build && node ./dist/index.js",
"build": "rimraf ./dist && npx tsc"
},
Добавляем файл /.env:
PORT=9000
ENV=development
Создаем файл ./src/types/environment.d.ts:
export {}
declare global {
namespace NodeJS {
interface ProcessEnv {
ENV: 'development' | 'production';
PORT: string;
}
}
}
Добавляем в настройки ./tsconfig.json:
"typeRoots": ["./node_modules/@types", "./src/types"]
Создаем файл ./src/config/index.ts
import path from "path"
import dotenv from "dotenv"
dotenv.config({
path: path.resolve(__dirname, '../../.env')
})
interface ENV {
PORT: number | undefined;
ENV: string | undefined;
}
interface Config {
PORT: number;
ENV: string;
}
const getConfig = (): ENV => {
return {
PORT: process.env.PORT ? Number(process.env.PORT) : undefined,
ENV: process.env.ENV ? String(process.env.ENV) : undefined
}
}
const getSanitizedConfig = (config: ENV): Config => {
for (const [key, value] of Object.entries(config)) {
if (value === undefined) {
throw new Error(`Missing key ${key} in .env`)
}
}
return config as Config
}
const config = getConfig()
const sanitizedConfig = getSanitizedConfig(config)
export default sanitizedConfig
Пример применения ./src/index.ts:
import express, { Express, Request, Response } from 'express'
import config from './config'
const app: Express = express()
const port = config.PORT
app.get('/', (req: Request, res: Response) => {
res.send('Express + Typescript Server')
})
app.listen(port, () => {
console.log(`⚡️[server]: Server is running at http://localhost:${port}`);
})
Загрузка комментариев...