> For the complete documentation index, see [llms.txt](https://redberry.gitbook.io/resources/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://redberry.gitbook.io/resources/node-js/node.js-express-tan-da-typescript-tan-ertad.md).

# Node.JS Express-თან და Typescript-თან ერთად

დღესდღეობით საკმაოდ პუპულალური არჩევანია TypeScript-ის არსებობა JavaScript-ის პროექტებში რადგანაც გვაქვს რა შემოღებული ტიპები, ჩვენი კოდი ხდება ნაკლებად ბაგიანი, გვაქვს დამატებითი Feature-ები და ასევე შესანიშნავი autocomlete-ი.

შესაბამისად TypeScript საკმაოდ მძლავრი ხელსაწყოა დეველოპერის ხელსაწყოთა არსენალში.

## **მაგრამ, მაინც რა არის TypeScript?**

TypeScript არის პროგრამირების ენა, რომელიც არის დაფუძნებული ჯავასკრიპტზე და რომელიც საბოლოო ჯამში მაინც ჯავასკრიპის სკრიპტად გარდაიქმნება რამეთუ ბრაუზერის ძრავებმა და ასევე Node-ის ძრავამ არ იცის TypeScript-ის კოდი შეუიარაღებელი თვალით როგორ წაიკითხონ და გადათარგმნონ მანქანურ ინსტრუქციებში.

*🐶 Fun Fact: Microsoft-მა TypeScript იმიტომ შექმნა, რომ საკუთარ C# დეველოპერებს ჯავასკრიპტთან მუშაობა გაადვილებოდათ. ამიტომაც ტაიპსკრიპტი ძალიან გაქვს C#-ს.*

იმისათვის, რომ TypeScript-ის კოდი გარდაიქმნას ჯავასკრიპტის კოდად TypeScript-ს აქვს საკუთარი compiler, რომელსაც აქვს უამრავი პარამეტრი, რომელიც შეგვიძლია "ვაწვალოთ" და მოვარგოთ ჩვენს პრეფერენციებს.

ჩვენს Node.JS - Express.JS პროექტში ტაიპსკრიპტის ინტეგრაციისათვის დაგვჭირდება ასევე პოპულალური პაკეტი Babel - რომლის მთავარი დანიშნულებაა ჯავასკრიპტის კოდის ტრანსფორმაცია ამა თუ იმ გზით(მაგალითად: ჩვენი ES6 კოდი, რომ გარდაიქმნას ყველა ბრაუზერზე მორგებულ კოდად - რომ ყველგან ისე მუშაობდეს ჩვენი კოდი როგორც გვაქვს ჩაფიქრებული, ასევე გვქონდეს backward compatibility)

ჩვენ ტაიპსკრიპტს გამოვიყენებთ Babel-ის მეშვეობით, რადგანაც მხოლოდ TypeScript-ის კომპილატორს აქვს რიგი ლიმიტაციები.

## პროექტის შექმნა

მოდი შევქმნათ პატარა Express-ის პროექტი:

```bash
mkdir express-typescript
cd express-typescript
npm init
npm install express
npm install --save-dev typescript @types/express
```

ახლაკი შევქმნათ src/server.ts ფაილი ჩვენს პროექტში და შიგნით ჩავწეროთ შემდეგი სკრიპტი:

```typescript
import express, { Request, Response } from "express";

const images = [
    'https://c.tenor.com/rK3k9EgLkhEAAAAC/steins-gate.gif',
    'https://c.tenor.com/wvZfA6FeOs0AAAAd/naruto-boruto.gif',
    'https://media3.giphy.com/media/pGlDpwgWTLgBi/giphy.gif',
    'https://c.tenor.com/stGMm1ODsGsAAAAC/anime-vinland-saga.gif',
    'https://i.pinimg.com/originals/ee/8f/ed/ee8fed71f21624f59205460b23820873.gif',
    'https://i.pinimg.com/originals/dd/9d/1b/dd9d1bef17c23fccf6f8224d7a70b766.gif',
]

const server = express()

server.get('/', async (_: Request, res: Response) => {
  
    const randomImgIdx = Math.floor(Math.random() * 100) % images.length

    res.send(`
    <html>
        <head>
            <title>Anime Images</title>
        </head>
        <body>
        <style>
            body {
                display: flex;
                justify-content: center;
                align-items: center;
                background-color: #0c112d;
            }

            img {
                border-radius: 10px;
            }
        </style>
        <a href="/" style="width: 50%">
            <img src="${images[randomImgIdx]}" style="width: 100%" />
        </a>
        </body>
    </html>
    `);
})


server.listen(4444, () => console.log("Server is listening at http://localhost:4444"))
```

> ეს არის უბრალოდ პატარა ვებსაიტი, რომელიც რენდომ ანიმე გიფებს გაჩვენებს დარეფრეშებისას

## TypeScript-ის კონფიგურაცია

ახლა კი ჩვენ გვჭირდება, რომ შევქმნათ TypeScript-ის კონფიგურაციის ფაილი შემდეგი ბრძანებით:

```bash
npx tsc --init
```

ჩვენ დაგვიგენერირდება default კონფიგურაცია, რომელიც ჩვენს პროექტს უნდა მოვარგოთ. რიგი ცვლილებების შემდგომ TypeScript-ის კონფიგურაცია tsconfig.json- შემდეგ სახეს მიიღებს:

```json
{
  "compilerOptions": {
    "target": "es2016",                       /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
    "module": "commonjs",                     /* Specify what module code is generated. */
    "paths": {
      "*": ["src/*"]                          /* Specify a set of entries that re-map imports to additional lookup locations. */
    },
    "baseUrl": "./",                          /* Specify the base directory to resolve non-relative module names. */            
    "outDir": "./build",                      /* Specify an output folder for all emitted files. */
    "removeComments": true,                   /* Disable emitting comments. */
    "esModuleInterop": true,                  /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
    "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
    "strict": true,                           /* Enable all strict type-checking options. */
    "strictNullChecks": true,                 /* When type checking, take into account 'null' and 'undefined'. */
    "strictFunctionTypes": true,              /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
    "strictBindCallApply": true,              /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
    "strictPropertyInitialization": true,     /* Check for class properties that are declared but not set in the constructor. */
    "noImplicitThis": true,                   /* Enable error reporting when 'this' is given the type 'any'. */
    "alwaysStrict": true,                     /* Ensure 'use strict' is always emitted. */
    "noUnusedLocals": true,                   /* Enable error reporting when local variables aren't read. */
    "noUnusedParameters": true,               /* Raise an error when a function parameter isn't read. */
    "skipLibCheck": true                      /* Skip type checking all .d.ts files. */
  }
}
```

ახლა ჩვენ თუ გავუშვებთ შემდეგ ბრძანებას:

```bash
npx tsc
```

ეს ბრძანება ტაიპსკრიპტის კონფიგურაციის მიხედვით შექმნის build ფოლდერს, რომელიც უკვე node-ის მიერ წაკითხვადია.

გავუშვათ node-ით დაკომპილირებული სკრიპტი:

```bash
node build/server.js
```

და დავინახავთ, რომ ჩვენი აპლიკაცია მუშაობს:

![](/files/J9k2I1DROwk7rDQzBxxc)

მაგრამ, რეალურად ნახევარი საქმე გავაკეთეთ ჯერ, რადგანაც როდესაც შევცვლით ჩვენს ქოუდბეისს გვჭირდება, რომ ჩვენი TypeScript-ის ქოუდბეისი ხელახლა დაკომპილირდეს და ასევე დარეფრეშებისას ცვლილებაც დავინახოთ.

## Babel-ის საჭიროება

ამის გაკეთება რეალურად ტაიპსკრიპტის კომპაილერითაც შეიძლება, მაგრამ რაღაც ნაკლი აქვს ტაიპსკრიპტს. \
მაგალითისათვის, თუ ჩვენი ქოუდბეისი შეიცავს არა .ts ფაილებსაც, მაგალითად swagger.yaml, html და css ფაილები და ა.შ. საბოლო build ფოლდერში მხოლოდ \*.ts ფაილები მოხვდება.

ამისათვის საჭიროა, რომ გამოვიყენოთ Babel-ი.\
გვჭირდება, რიგი package-ები:

* **@babel/core** - ძირეული babel-ის ფუნქციონალისთვის
* **@babel/cli** - CLI, რომლითაც babel-ს ვეტყვით რა უნდა გააკეთოს
* **@babel/preset-env** - პრესეტი, რომლის მეშვეობითაც ვეტყვით როგორ გადააკომპილიროს კოდი
* **babel-plugin-module-resolver** - პლაგინი, რომლის საშუალებითაც შესაძლებელია გვქონდეს absolute import-ები
* **@babel/preset-typescript** - პრესეტი, რომელიც იქნება შუამავალი babel-ს და ტაიპსკრიპტს შორის

დავაინსტალიროთ ყველა ეს ჩამოთვლილი ფექიჯი(ყველა არის dev dependency):

```
npm install --save-dev @babel/core
npm install --save-dev @babel/cli 
npm install --save-dev @babel/preset-env 
npm install --save-dev babel-plugin-module-resolver
npm install --save-dev @babel/preset-typescript
```

და ასევე შევქმნათ პროექტის root-ში babel-ის კონფიგურაციის ფაილი, რომელსაც დავარქმევთ babel.config.json-ს.

შიგნით კი შემდეგი კონფიგურაცია გავუწეროთ:

```json
{
    "presets": [
        "@babel/preset-typescript",
        [
            "@babel/preset-env", {
            "targets": {
                "node": 16
                }
            }
        ]
    ],
    "plugins": [
        [
            "module-resolver", {
                "root": ["./src"],
                "extensions": [".ts"]
            }
        ]
    ]
}
```

ამის შემდგომ package.json-ში ჩავამატოთ რამოდენიმე სკრიპტი, იმისათვის, რომ მარტივად გავუშვათ ჩვენი პროექტი საჭირო ვარიანტში:

```json
{
  "scripts": {
    "start": "node build/server.js",
    "build:watch": "babel src --out-dir build --extensions .ts --copy-files --watch",
    "build:prod": "babel src --out-dir build --extensions .ts --copy-files --minified"
  },
 ...
}

```

ახლა თუ გავუშვებთ ბრძანებას:

```
npm run build:watch
```

ამ შემთხვევაში როცა კი რაიმე ცვლილებას შევიტანთ კოდში მაშინვე გადაკომპილირდება build ფოლდერში.

## საბოლოო ცვლილებები

მაგრამ ამასთანავე გვჭირდება,რომ nodemon-ით გავუშვათ საბოლოო ჯავასკრიპტის ბილდი, რადგანაც ყოველ ცვლილებაზე nodemon-მა თავისით გადაარესტარტოს ჩვენი node-ის სერვერი.

მაგრამ რეალურად გამოდის, რომ გვჭირდება გვქონდეს გაშვებული ორი პროცესი:

* babel - რომელიც აკონვერტირებს ჩვენს TypeScript-ის ქოუდბეიზს JavaScript-ის build ვარიანტად
* nodemon - რომელიც build ფოლდერში გვაქვს გაშვებული და ნებისმიერ ცვლილებაზე არესტარტებს ჩვენს node-ის სერვერს, რომ ახალი ცვლილებები აღიქვას

შეგვიძლია, რომ ეს პროცესები ცალ-ცალკე გავუშვათ(ცალ-ცალკე ტერმინალის სესიაში) მაგრამ ისიც შეგვიძლია, რომ ერთდროულად გავუშვათ concurrently ფექიჯის დახმარებით 👊

ეს ორი ფექიჯიც დავაინსტალიროთ:

```
npm install --save-dev nodemon concurrently
```

და ასევე package.json-ში ერთი სკრიპტიც ჩავამატოთ:

```json
{
...
"scripts": {
    ...
    "dev": "concurrently \"npm run build:watch\" \"nodemon build/server.js\"",
 }
}
```

ახლა თუ გავუშვებთ npm run dev-ს უკვე ჩვენი დეველოპმენტ გარემო მზად იქნება, Voilla 😇

* npm run build:prod - უნდა გავუშვათ, როდესაც პროდაქშენის ვერსია გვინდა დავბილდოთ
* npm start - უნდა გავუშვათ პროდაქშენზე იმის შემდგომ რაც გავუშვებთ `npm run build:prod` -ს

აბა თქვენ იცით, ღმერთი თქვენსკენ 🐶
