Programming

Facundo Spira • 12 JUN 2023

Node.js in action: our winning tech stack

post cover picture

Over time, Node.js has become one of our top technologies for creating web applications. When building applications with Node.js, we use a variety of frameworks, libraries, and tools that complement Node.js and enhance its capabilities. This combination of different technologies is referred to as a stack.

In this blog post, we will discuss the different components of our Node.js stack, including the programming languages, frameworks, libraries, and tools we use to build our web and mobile applications. We'll explain how each of these components works together to create a seamless development process and how they work smoothly for us.

 

Why do we choose Node.js?

Node.js is an open source Javascript runtime environment that runs on the V8 engine, an execution engine that was initially built for Google Chrome. Written in C++, V8 compiles JavaScript source code to native machine code.

One of the reasons why it is one of the technologies we use the most is because it is perfectly suited for microservices architecture. With microservices, applications are split up into smaller, independent services that can be developed, deployed, and scaled independently. This makes the process of managing an application much more flexible and efficient and makes a software product easily scalable. By utilizing Node.js, we are able to provide our clients with web applications that are robust, reliable, and capable of meeting their specific needs.

Some of the advantages of Node.js:

 

Our Node.js Stack

In addition to Node.js, we use several other tools that complement its capabilities. 

Our Node.js stack is designed to provide a robust and flexible foundation for building high-performing and scalable applications. By leveraging the power of Node.js and its ecosystem of tools and technologies, we can deliver applications that meet the needs of our clients and users. These are the tools we rely on to build Node apps:

 

Typescript

TypeScript is a statically typed superset of JavaScript that provides additional features and functionality to the language. Let’s discuss some of the benefits that Typescript introduces:

 

GraphQL

GraphQL is a query language that provides an approach to developing web APIs and has been compared and contrasted with REST and other web service architectures.

Some common problems developers face when building REST APIs are underfetching and overfetching.

This way, by allowing clients to request exactly the data they need, GraphQL eliminates the need for multiple round trips to the server and reduces network traffic, resulting in faster load times and improved performance.

Another benefit of using GraphQL is its strong typing and introspection capabilities. When building a GraphQL API, schema is defined, serving as a contract between the client and the server. This schema includes types, fields, and operations that are available in the API, as well as the input and output types for each field.

Taking advantage of GraphQL's introspection, the client is able to query the schema itself, allowing them to discover the available types, fields and operations without the need of any additional documentation. This way, by using tools such as GraphQL Playground developers can explore the API Schema and build and test queries. Furthermore, the strong typing in GraphQL eliminates the need for manual type checking, reducing the chance of runtime errors and making development faster and less error-prone. By providing a clear and well-documented schema, GraphQL improves the developer experience and reduces the time and effort required to build and maintain APIs.

 

Taking it one step further

We also use a set of auxiliary tools that are widely used in the software community. They allow us to maintain a high level of code quality while maintaining development efficiency. Some of these are Eslint, Husky and Conventional Commits.

ESlint

ESLint is a static code analysis tool for identifying problematic patterns found in JavaScript/Typescript code.

It’s really easy to set up. Once we have our project created, we can just initialize ESlint by using our package manager (npm in this example).

npm init @eslint/config

This command will install the necessary dependencies and initialize our .eslintrc file with all the predefined rules. These rules can be further customized to the need of the specific project.

 

Husky

We use Husky to automate the execution of scripts before committing or pushing changes to Git. This ensures that for example, the code is formatted correctly and that the tests pass before the changes are pushed to the repository.

# Install husky
npx husky-init && npm install

# Add new hooks for pre-commit and pre-push actions.
npx husky add .husky/pre-commit "npx eslint ."
npx husky add .husky/pre-push "npm test"

 

Conventional Commits

We like to use Conventional Commits to ensure that the commit messages are consistent and informative. It is also really helpful to automatically generating CHANGELOGs. Furthermore, if you are working on an open source project, it is easier for other contributors to understand what changes were made.

When using Conventional Commits, commit messages should be structured as follows:

[optional scope]: 

[optional body]

[optional footer(s)]

 

So a commit message could look like this:

refactor!: drop support for Node 6

Starting with the next major version we will no longer support Node 6.

BREAKING CHANGE: refactor to use JavaScript features not available in Node 6.

 

However, it's usual that most commits doesn't require a body or footer. So, in that case, most commits will look like this:

feat(landing): add spanish translations to the landing page

 

Or even without a scope:

fix: add missing semicolon on Cart controller

 

To help follow this convention, we use a tool called commitlint along with Husky. This tool will check if the commit messages follow the conventional commits convention. If not, it will fail the commit and will not allow you to push the changes to the repository.

 

To install it, we need to follow these steps:

npm install -D @commitlint/{config-conventional,cli}

 

Then we need to create a commitlint.config.js file in the root of the project with the following content:


module.exports = { extends: ['@commitlint/config-conventional'] }

 

This uses the config-conventional preset, which is based on the Angular convention. However, one can decide to further configure the rules to fit the needs of the project, for example by modifying the type-enum rule to only allow certain types of commits.

 

Enhancing Node.js with powerful tools

By incorporating these powerful tools alongside Node.js, we can enhance our development process, streamline workflows, and build robust and reliable applications. These tools address various aspects of web development, including API creation, database interaction, testing, and process management, enabling developers to deliver high-quality applications that meet the demands of modern web development.

This is the stack we chose to create efficient applications based on Node.js. Of course, they are not the only ones, and there are infinite options when it comes to developing scalable applications.

While Node.js serves as the backbone for executing JavaScript on the server side, we lean on these complementary tools that significantly contribute to augment the capabilities of Node.js and enable us to overcome common challenges in web development.

Visit our blog for more information about Node.js and how we use this technology.

 

Stay updated!

project background