~/blog/nodejs/node.js-structure
Published on

Node js deep dive - part one

734 words4 min read
Authors
  • avatar
    Name
    Mahmoud Amr
    Twitter
    @
Photo by Chase Baker

Photo by Chase Baker on Unsplash


Introduction

Node.js is a runtime environment that allows us to write JavaScript outside the browser. JavaScript needs an engine to understand the syntax and convert it to machine code, and different browsers have their own engines. For example, Google Chrome has V8, Firefox has SpiderMonkey, and Safari has JavaScriptCore. Although this article is not specifically about engines, we will revisit the V8 engine later.

In this article, we will delve deeper into the structure of Node.js files and explore how dependencies are managed. Understanding the file structure and dependencies is crucial for building efficient and robust Node.js applications.

Node.js Source Code Folder Structure

When you download Node.js on your machine, you get a folder that is organized into several directories, each containing different types of files and code. Here's a high-level overview of the folder structure:

  • benchmark/: Contains benchmarks for testing Node.js performance.
  • deps/: Contains third-party dependencies used by Node.js, including OpenSSL and zlib.
  • doc/: Contains documentation for Node.js, including the API reference and the Node.js website.
  • lib/: Contains the core Node.js library, which provides the implementation of Node.js features and APIs.
  • src/: Contains the C++ source code for Node.js, including the V8 JavaScript engine and the libuv library.
  • test/: Contains the automated tests for Node.js, including unit tests, integration tests, and more.
  • tools/: Contains various tools used in the development and testing of Node.js.
  • typings/: Contains TypeScript type definitions

To learn more about the Node.js repository and its contents, you can explore the codebase on GitHub.

There are two folders we care about: lib/ and src/.

  • The lib/ folder contains all the JavaScript definitions, functions, and modules. It represents the JavaScript side of Node.js, and you can use Node's require() directly.
  • The src/ folder contains all the C++ implementations of the above functions, which Node.js uses V8 and libuv internally. It represents the C++ side of Node.js, and the files must be manipulated before use.

We will come back to these folders later, but for now, the question is: how do these two sides of Node.js communicate?

How the Two Worlds Meet

Why do we use C++ and where is the bridge that allows JavaScript and C++ to understand each other?

The answer to the first question is simple: C/C++ is relatively much closer to the hardware and hence much faster than other high-level languages. Now, let's look at this diagram:

Node.js Architecture

We mentioned the lib/ and src/ folders earlier. We can think of the lib/ folder as the JavaScript world and the src/ folder as the C++ world.

So, where is the bridge that allows them to understand each other? It's the process.binding() method.

process.binding()

The process.binding() method connects the JavaScript side of Node.js to the C++ side of Node.js. It's a method that grabs the C++ code and makes it available inside JavaScript.

It provides access to C++ addon modules from JavaScript and is used to load and access various low-level system resources and functionality that are not available directly from JavaScript.

The process.binding() method takes a single argument, which is the name of the C++ addon module to load. For example, process.binding('fs') would load the fs module, which provides file system functionality.

The process.binding() method is typically used internally by Node.js to implement various core modules, such as fs, net, and http. However, developers can also use it to load and access custom C++ addon modules.

Dependencies Used by Node.js

Node.js Dependencies

Node.js relies on several third-party dependencies to provide various features and functionality. Here are some of the main dependencies used by Node.js:

  • V8: The JavaScript engine used by Node.js to execute JavaScript code.
  • libuv: A library used by Node.js for cross-platform asynchronous I/O operations.
  • OpenSSL: A cryptography library used by Node.js for secure network communications.
  • zlib: A compression library used by Node.js for gzip compression and decompression.
  • http-parser: A parser library used by Node.js to parse HTTP messages.
  • c-ares: A DNS library used by Node.js for asynchronous DNS resolution.
  • icu: A library used by Node.js for Unicode and internationalization support.

And voilà! We have JavaScript ready to use outside the browser.

Node.js is single-threaded, but it introduces itself as non-blocking I/O. How is this achieved? That is what we will discuss in the next part of this series.