NodeJS application architecture is a huge theme with a lot of different approaches. In my article series, I am going to start from basics and move to, in my opinion, good application architecture. To keep it short — we will use NestJS. This framework includes all the best design patterns. It is extremely efficient both for small microservices and large applications. But the real goal is to show all these patterns in deep. So we will:
- Create our first simple application
- Use TypeScript and get acquainted with its syntax
- Dive into app architecture principles
- Write a real-world application in NestJS
- Deploy it using Docker
Chapter 1 — Why TypeScript?
There are tons of articles about TypeScript advantages or disadvantages. Especially in Frontend world. But let’s get to it from NodeJS perspective.
Good and bad
First of all, TypeScript is a typed programming language, as you can assume from its name. What does it mean for us?
- Syntax highlights and autocomplete in IDE, then will save you from bugs and speed up your development.
- The code is much easier to maintain and test that is valuable in large enterprise applications.
- Refactoring! You can do it with a blink of an eye and do not afraid to break your code.
Secondly, it implements main object-oriented concepts, such as inheritance, encapsulation, and polymorphism.
But for every feature, we have to pay. In this case, you will pay with your time because you have to write more code. You need an interface for every object, type for any variable, parameter or function return. And if you are using libraries that don’t have types, you have to write it yourself. But in some cases, you can cheat and use any type.
Installation and environment setup
First of all, let us create an example app and deep dive into its structure. All we need is VSCode and a terminal.
Here we enter package name, version, author and description. This command creates us package.json file with basic info. All our app dependencies will be stored here. Now we install typescript globally:
npm i -g typescript
And in your app dependencies we install NodeJS types so we can use it in your app:
npm i @types/node --save-dev
In order to compile TS to JS we need to tell TypeScript how do we want to do that, where do we want output js files or which ECMAScript target version. We need tsconfig.json file which indicates that this is a root directory for our typescript project. I will explain every compile option that we will use, but this knowledge is not very important for a start:
“module”: “commonjs”, // Specify module code generation
“declaration”: false, // Do I generate d.ts files?
“noImplicitAny”: false, // Do I raise an error on expressions and declarations with an implied any type?
“removeComments”: true, // Remove all comments from bundle
“noLib”: false, // Do i exclude lib.d.ts?
“allowSyntheticDefaultImports”: true, // Do I allow default imports from modules with no default export?
“emitDecoratorMetadata”: true, // Necessary for decorators
“experimentalDecorators”: true, // Necessary for decorators
“target”: “es6”, // Specify ECMAScript target version
“sourceMap”: true, // Do I generate .map files for debugging?
“outDir”: “./dist”, // Ouput path
“baseUrl”: “./src” // Base directory to resolve non-relative module names
“src/**/*” // Which files to include
“node_modules” // Which files to exclude
Simple app example
Create index.ts file in src directory:
Then we will add some code, that creates hamster:
Here we declared hamster class and initialized it, passing some process variables like its name and age. Then we call `introduce` function that makes our new friend introduce itself. We use 2nd and 3rd process argument because 0 is node path and 1st is a file path.
And what if we write the same code in JS (es6)?
Is you can see, we had to write more code in TypeScript. Here we declared types of all variables, parameters and returns. For now on VSCode will gracefully promt all parameters and theres type when we create new hamster:
While refactoring we can swap variable name within one click not afraid to break the code:
Or find a class or other object definition from any file:
In this particular example benefits are not so obvious, but in large projects, this will save you a lot of time.
But we got distracted. Let’s get back to our hamster project and finally run it.
Run with tsc
In order to run our project, we need to compile it to JS and run it like a standard NodeJS app. Just run
We will get compiled js file and .map file in dist directory.
Then run it:
node dist/index.js Alfred 34
We got output I am Alfred and I am 34 years old. I recommend using this way in production.
Run with node-ts
When you develop your application it is convenient to just run your app without an extra compile step. In this case, you can use ts-node that will compile your code on a flight. Project link is here.
npm i ts-node --save-dev
npm i typescript --save-dev
You can install it globally, but it is not recommended by its author.
Besides local typescript installation makes your project more stable, so you do not have to worry about TypeScript updates and different versions on other developer machines. Now we can run it without compilation:
./node_modules/.bin/ts-node src/index.ts Alfred 34
Today we created one simple project on NodeJS and TypeScript and learn two ways to run it. In our next article, we will dive into application architecture that will allow us in the end to write enterprise applications.
I will appreciate any feedback or 👏, so I’ll understand that this is useful for you.