diff --git a/Dockerfile b/Dockerfile index 242ee3c2..b53b63f0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ RUN npm ci --omit=dev COPY . . FROM base-dev AS development -CMD ["node", "-r", "./src/lib/tracing.cjs", "--watch", "bin/www.js"] +CMD ["node", "--env-file=.env", "--require=./src/lib/tracing.cjs", "--watch", "bin/www.js"] FROM gcr.io/distroless/nodejs20-debian12:20.15 AS production WORKDIR /app diff --git a/README.md b/README.md index 1111f1c8..a5558204 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Swagger: https://express-rest-boilerplate.onrender.com/docs - [Requirements](#requirements) - [Features](#features) - [Getting Started](#getting-started) - - [With a Package Manager](#with-a-package-manager) + - [With a Node Version Manager](#with-a-node-version-manager) - [With Github](#with-github) - [With Docker Compose](#with-docker-compose) - [Folder Structure](#folder-structure) @@ -26,14 +26,14 @@ Swagger: https://express-rest-boilerplate.onrender.com/docs ## Requirements -- [Node 18+](https://nodejs.org/en/download/) or [Docker](https://www.docker.com/) +- [Node.js v20+](https://nodejs.org/en/download/) or [Docker](https://www.docker.com/) ## Features - No transpilers, just vanilla javascript -- Node 18 and ES2022 latest features like [top-level await](https://h3manth.com/ES2022/#top-level-await) +- Node.js v20 and ES2024 latest features - [ECMAScript modules](https://nodejs.org/api/esm.html#modules-ecmascript-modules) and import aliases -- Code completion and optional type checking with [Typescript](https://www.typescriptlang.org/docs/handbook/intro-to-js-ts.html), [JSDoc](https://code.visualstudio.com/docs/languages/javascript#_jsdoc-support) and [VSCode's IntelliSense](https://code.visualstudio.com/docs/nodejs/working-with-javascript#_intellisense) +- Code completion and optional type checking with [JSDoc](https://code.visualstudio.com/docs/languages/javascript#_jsdoc-support) - Structured logs with [pino](https://github.com/pinojs/pino) - Metrics with [Prometheus](https://github.com/siimon/prom-client) client - [OpenTelemetry](https://opentelemetry.io/) auto instrumentation for traces, metrics and logs. @@ -44,23 +44,23 @@ Swagger: https://express-rest-boilerplate.onrender.com/docs - MongoDB ORM with [Mongoose](https://mongoosejs.com/) - [Docker](https://www.docker.com/) with [multi-stage builds](https://docs.docker.com/develop/develop-images/multistage-build/) and [distroless](https://github.com/GoogleContainerTools/distroless) base image for production builds - [Docker compose](https://docs.docker.com/compose/) file for easy setup, including observability tools (Grafana, Loki, Tempo and Prometheus) -- Load environment variables from .env files with [dotenv](https://github.com/rolodato/dotenv-safe) +- Load environment variables from .env files with Node's [--env-file](https://nodejs.org/en/learn/command-line/how-to-read-environment-variables-from-nodejs) flag - Unit and integration tests with [Vitest](https://vitest.dev/) and [Supertest](https://github.com/visionmedia/supertest) - Code coverage with [Codecov](https://about.codecov.io/) github action - Git pre-commit hooks with [husky](https://github.com/typicode/husky) and [lint-staged](https://github.com/okonet/lint-staged) - Authentication and Authorization with [passport](http://passportjs.org) - Automatic error handling for express asynchronous routes with [express-async-errors](https://github.com/davidbanham/express-async-errors) - CI/CD with [Github Actions](https://github.com/features/actions) -- Auto reload with [node's watch mode](https://nodejs.org/dist/latest-v18.x/docs/api/cli.html#--watch) +- Auto reload with [node's watch mode](https://nodejs.org/dist/latest-v20.x/docs/api/cli.html#--watch) - Server and tests debugging with [VSCode's debugger](https://code.visualstudio.com/docs/editor/debugging) - [Dependabot](https://docs.github.com/pt/code-security/dependabot/dependabot-security-updates/configuring-dependabot-security-updates) configuration file for automatic dependency updates - CORS configuration ## Getting Started -### With a Package Manager +### With a Node Version Manager -1. Install Node.JS v18. You can use a node version manager like [fnm](https://github.com/Schniz/fnm). +1. Install Node.JS v20. You can use a node version manager like [fnm](https://github.com/Schniz/fnm). ```bash fnm install @@ -71,33 +71,39 @@ fnm use ```bash # with npm -npm init @danielfsousa express-rest-boilerplate my-api +npm init @danielfsousa express-rest my-api # with yarn -yarn create @danielfsousa express-rest-boilerplate my-api +yarn create @danielfsousa express-rest my-api # with pnpm -pnpm create @danielfsousa express-rest-boilerplate my-api +pnpm create @danielfsousa express-rest my-api + +# with bun +bun create @danielfsousa express-rest my-api ``` 3. Change .env database credentials ```bash cp .env.example .env -nano .env +vim .env ``` 4. Run server in development mode. The server will restart everytime a file is changed. ```bash # with npm -npm run start:dev +npm run dev # with yarn -yarn start:dev +yarn dev # with pnpm -pnpm start:dev +pnpm dev + +# with bun +bun dev ``` ### With Github @@ -171,7 +177,7 @@ To learn how to search for logs and traces in Grafana, take a look at the [docum npm run lint # lints code and check formatting npm run lint:fix # lints code, check formatting and tries to fix found problems npm run start # starts server -npm run start:dev # starts server in watch mode, waiting for file changes +npm run dev # starts server in watch mode, waiting for file changes npm run test # runn all tests in watch mode, waiting for file changes npm run test:cov # runn all tests and report coverage npm run validate # runs lint and test scripts for files on git's staging area diff --git a/bin/www.js b/bin/www.js index e2c1af93..4d8ba2e5 100755 --- a/bin/www.js +++ b/bin/www.js @@ -1,4 +1,4 @@ -#!/usr/bin/env -S node -r ./src/lib/tracing.cjs +#!/usr/bin/env -S node --env-file=.env --require=./src/lib/tracing.cjs import main from '../src/main.js' await main() diff --git a/package-lock.json b/package-lock.json index aad5e64a..63e9534c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,6 @@ "body-parser": "^1.19.0", "cors": "^2.8.3", "date-fns": "^2.29.3", - "dotenv": "^10.0.0", "email-templates": "^8.0.7", "envalid": "^7.2.1", "express": "^4.15.2", @@ -64,7 +63,7 @@ "vitest": "^0.23.4" }, "engines": { - "node": ">=18" + "node": ">=20" } }, "node_modules/@ampproject/remapping": { @@ -5449,14 +5448,6 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", - "engines": { - "node": ">=10" - } - }, "node_modules/duplexify": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", @@ -16272,11 +16263,6 @@ } } }, - "dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" - }, "duplexify": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", diff --git a/package.json b/package.json index 84c1169c..d6abcfba 100644 --- a/package.json +++ b/package.json @@ -27,11 +27,11 @@ }, "main": "src/main.js", "scripts": { + "dev": "node --env-file=.env --require=./src/lib/tracing.cjs --watch bin/www.js", "lint": "eslint . ; prettier . --check", "lint:fix": "eslint . --fix ; prettier --write .", "prepare": "husky install || true", "start": "bin/www.js", - "start:dev": "node -r ./src/lib/tracing.cjs --watch bin/www.js", "test": "vitest", "test:cov": "vitest run --coverage", "validate": "lint-staged" @@ -51,7 +51,6 @@ "body-parser": "^1.19.0", "cors": "^2.8.3", "date-fns": "^2.29.3", - "dotenv": "^10.0.0", "email-templates": "^8.0.7", "envalid": "^7.2.1", "express": "^4.15.2", @@ -95,7 +94,8 @@ "testcontainers": "^9.0.0", "vitest": "^0.23.4" }, + "packageManager": "npm@10.8.1+sha512.0e9d42e92bd2318408ed81eaff2da5f78baf23ee7d12a6eed44a6e2901d0f29d7ab715d1b918ade601f72e769a824d9a5c322383f22bbbda5dd396e79de2a077", "engines": { - "node": ">=18" + "node": ">=20" } } diff --git a/src/config.js b/src/config.js index 85a7dbe3..4ce35258 100644 --- a/src/config.js +++ b/src/config.js @@ -1,6 +1,5 @@ import fs from 'fs' import path from 'path' -import dotenv from 'dotenv' import { cleanEnv, str, num, bool } from 'envalid' import { LogLevel, LogFormat } from '#enums/log' @@ -8,10 +7,6 @@ const appPath = path.dirname(import.meta.url).replace('file:', '') const pkgPath = path.join(appPath, '../package.json') const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')) -dotenv.config({ - path: path.join(appPath, '../.env'), -}) - const env = cleanEnv(process.env, { NODE_ENV: str({ choices: ['development', 'test', 'production', 'staging'],