Ep.04: How to scaffold a project (Settings & Configuration)

Ep.04: How to scaffold a project (Settings & Configuration)

This article is part of an in-depth comparison series of the top Node frameworks. We'll cover all the important aspects: market share, learning curve, ecosystem, security and more. To compare them properly, we will build the exact same app in all these frameworks (plus Vanilla Node), observe all the steps along the way and then benchmark them as we progressively add more functionalities.

Table of contents

  1. Market Share Distribution Analysis: Picking the most used frameworks
  2. Planning Phase: Use cases, Minimum Viable Product requirements, Architecture
  3. Tools & Setup: Getting started and setting up the tools and environment
  4. Scaffolding: Project Settings and Configuration, Common template repo
  5. Express: basic app (MVP)
  6. Koa: basic app (MVP)
  7. Express Flavors: basic app (MVP) in multiple variants: OOP, FP, TypeScript, single-file etc
  8. Nest.js: basic app (MVP)
  9. Fastify: basic app (MVP)
  10. Next.js: basic app (MVP)
  11. Vanilla Node: basic app (MVP)
  12. Functional testing with Postman + Newman


We're almost ready to start building an app. Now, before we go all keyboard-happy and start building, we want to avoid repeating the configuration files every time we try a new framework. We need a template with settings and configurations first. These should address a few other aspects that don't qualify as Cross-Cutting Concerns but are very important.

If you ever opened a node app you probably saw the root directory is littered with lots of weird scary colorful files - these are them configurations we want, things like linting, formatting, credentials, configs, and so on.

You don't need to go through all these, you can just take my word for it and hope none of these files contains a script that will lock the door to your bathroom at random inconvenient times or switch your TV to a soap opera during your favorite Muppets show. If you are curious, do read through and/or have a look at the template repo I'll use as a starting point.


Versioning

  • .nvmrc: this tiny config file will point nvm (Node Version Manager) to the right version. It contains just the version number, and we will use Node 20.12.2, the latest LTS version. If you are using VSCode, I recommend installing an extension that automatically loads the correct node version for the project like vsc-nvm, so you don't need to run 'nvm use' all the time.

Code Formatting

  • .prettierrc: Prettier helps maintain a consistent code style across your project by automatically formatting your code according to predefined rules. It defines rules such as indentation style, wrapping, quoting etc. Here's the list of available settings (i.e. the schema) if you want to set up your own. Pictured, we have a typical .prettierrc file: most of the settings are actually default, added to make things explicit in conjunction with .editorconfig.

  • .editorconfig file: if your team uses different IDEs, it may be useful to enforce formatting styles via EditorConfig. This is built into many code editors, so you just put it in the root folder and it just works. For VSCode you need a plugin, since VSCode has workspace settings enforcing formatting styles. The good thing about it is that EditorConfig will have priority over your workspace settings, so you can still keep them and use them in your other projects. EditorConfig has a lot of overlap with Prettier, but worry not, Prettier will parse .editorconfig file if present and convert it to its own format. Please note that .prettierrc rules take precedence over .editorconfig. In the git repo you will also find an example of a .editorconfig_intellij, for IntellijIdea. I'll work with Codium, so, that will have no effect for my setup though. Here are the settings that we will use - note, I added one that overlaps with Prettier, so we can observe which takes priority: max_line_length = 100 (in .editorconfig) will be overridden by "printWidth": 0 (in .prettierrc)

Linting

  • .eslintrc.ts: ESLint is the de-facto standard, it helps identify and fix common errors and enforce coding standards in your codebase, including the ones enforced with Prettier. Here's a commented version of the file I included in the template:

Git config

  • .gitignore: signals what to ignore when you commit. It simply lists all the files, extensions, and folders that should not be pushed to the remote git repo. You can use wildcards (*) or you can even tell it to include a specific file (!). There are many VSCode extensions that helps you easily git-ignore files or folders from the context menu in the explorer pane, I prefer this one because it allows you to also remove files from gitignore.

NPM config

  • package.json: the key file of any app, with project description, and config, including scripts and dependencies. For now, it's almost empty:

It just has a bunch of generic or even empty scripts to start, test, format and build the app.

IDE config

  • For VSCode and VSCodium you'll see a .vscode folder containing instructions about how to run the debugger, themes, etc. For other IDEs, you'll have different config folders. Note: the settings.json can contain code formatting settings, that will be overwritten by EditorConfig, which, in turn, will be overwritten by Prettier.

Credentials / Configuration management

  • .env, .env.testing: dotenv is the most widely used for this, they will hold our very secret passwords. You'll need to run npm install dotenv for this to work.

TypeScript configuration

  • If the framework supports TypeScript, you will see two files:
  • tsconfig.json: compiler options and settings that tsc compiler uses when transpiling TypeScript to JavaScript, like the target ECMAScript version, module system, strictness level, file paths, etc. Here's a partial and commented version of the tsconfig.json in the template. DO NOT use the commented version, comments are not legal JSON syntax

{
  "compilerOptions": {
// For "module" (module resolution), you might be tempted to use "ES2015" or more recent instead of "commonjs", but that's not the right choice for Node backend (it's more appropriate for a browser environment).
    "module": "commonjs",

// You should stick to a more backwards compatible "target" in a production environment. However, since we're here to experiment, we'll use the latest ECMA Script specification
    "target": "esnext", 

// Allow default imports from modules with no default export
  "allowSyntheticDefaultImports": true,

// Allow importing JSON files directly as modules in TypeScript
  "resolveJsonModule": true,

// Generate corresponding .d.ts declaration files
  "declaration": true,

// Generate source map files for debugging TypeScript code
  "sourceMap": true,

// Enable the generation of decorator metadata in emitted JavaScript output and support for experimental TypeScript decorator syntax. Some frameworks like Nest will need it
  "emitDecoratorMetadata": true,
  "experimentalDecorators": true,

// Specify the output directory for compiled JavaScript files
  "outDir": "./dist",
// Set the base directory for resolving non-relative module names
  "baseUrl": "./",

// Enable incremental compilation, speeding up the compilation process
  "incremental": true,

// Skip type checking of declaration files from external libraries
  "skipLibCheck": true,

// Remove all comments from the compiled JavaScript files
  "removeComments": true,

// Enable strict null checks, catching common null-related errors
  "strictNullChecks": true,

// Disallow the use of implicit any types, enforcing type safety
  "noImplicitAny": true,

// Enable strict checks for bind, call, and apply methods on functions
  "strictBindCallApply": true,

// Force consistency in file names, preventing case sensitivity issues
  "forceConsistentCasingInFileNames": true,

// Enforce a check for missing break statements in switch statements
  "noFallthroughCasesInSwitch": true
  }

// Although tempting, avoid "esModuleInterop": true, it creates more problems than it solves. Use with caution.
}        

  • tsconfig.build.json: build process config like optimizations, different output paths, or specific settings for bundlers like Webpack or tools like Babel. We won't be using this.

CI/CD configuration

  • .gitlab-ci.yml, .github/workflows, .circleci, Jenkinsfile etc: we won't be needing this, but normally it's there.

NPM config

  • .npmrc: It can hold npm config options. We won't be needing this, it's only included as a placeholder. If you do want to host your own npm repository with Verdaccio, Sinopia, Artifactory, etc, it would look like this:

# Set the default registry
registry=https://your-npm-registry.org/

# Avoid running npm audit automatically on install
audit=false

# Set the proxy if needed
proxy=https://your-proxy-url/
https-proxy=https://your-proxy-url/

# Enable npm's offline mode
offline=true

# Define custom scripts shell
script-shell=/bin/bash

# Specify the cache directory
cache=/path/to/npm-cache

# Set Node.js version
node-version=20
engine-strict=true        

Containerization

  • we want to be able to run these apps on any machine, so Docker will be our best friend (Note: there are other alternative best friends out there, like Podman, Containerd...). At first, we will need just the Dockerfile. Later on, we will want a docker-compose.yml to run a database container along with the main app. Again, if you're using VSCode, I recommend the Docker extension to manage those later. You'll also see a .dockerignore file, which does the same thing as the .gitignore file, for Docker.

要查看或添加评论,请登录

Teolin Codreanu的更多文章

社区洞察

其他会员也浏览了