8.5 KiB
Minimal Express.js Scaffolding
This project offers a streamlined and minimalistic scaffolding for Express.js applications. Unlike many generators that require extensive cleanup before you can begin, this boilerplate strikes a balance between simplicity and completeness. It provides just the essentials, allowing you to pull the repository, customize the project name, and start building your API immediately.
Support the Project
If you find this project useful, consider supporting its development:
Installation
To install the project dependencies, run the following command:
pnpm install
Running the App
To run the application in development mode with live reloading, use:
pnpm dev
To build and run the application for production, use:
pnpm start
Customization
To rename the project, modify the "name" field in the package.json file.
{
"name": "your-project-name"
}
Technologies Used
- Express: Fast, unopinionated, minimalist web framework for Node.js.
- TypeScript: Typed superset of JavaScript that compiles to plain JavaScript.
- Jest: A delightful JavaScript Testing Framework with a focus on simplicity.
- Knip: A tool to find unused files, dependencies, and exports in your JavaScript and TypeScript projects.
- ESLint: A pluggable and configurable linter tool for identifying and reporting on patterns in JavaScript.
- Docker: A platform for developing, shipping, and running applications in containers.
- tsx: A CLI to seamlessly execute TypeScript and ESM.
- tsdown: A tool for building TypeScript projects.
Scripts
pnpm start: Starts the production server after building the project.pnpm dev: Runs the application in development mode with live reloading.pnpm build: Builds the TypeScript project into JavaScript.pnpm test: Runs the test suite using Jest and generates a coverage report.pnpm test:watch: Runs the tests in watch mode, re-running them on file changes.pnpm knip: Finds unused files, dependencies, and exports.pnpm lint: Lints the codebase using ESLint and automatically fixes issues.
Building This Scaffold From Scratch
Here is a detailed, step-by-step guide to creating this scaffold from the ground up.
Requirements
Step-by-Step Guide
-
Initialize the project:
pnpm init -
Install Express:
pnpm install express -
Set up TypeScript:
pnpm install --save-dev typescript @types/node @types/express npx tsc --init -
Create the main application file: Create a file at
src/index.ts. -
Install
tsxfor development andtsdownfor building:pnpm install --save-dev tsx tsdown -
Configure
tsdown: Create atsdown.config.tsfile:import { defineConfig } from 'tsdown'; export default defineConfig({ entry: 'src/index.ts', format: ["esm"], target: "ESNext", platform: "node" }); -
Configure
tsconfig.json: Modify yourtsconfig.jsonto look like this:{ "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "Bundler", "baseUrl": "src", "paths": { "@*": ["*"] }, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true } } -
Set up Jest for testing:
pnpm install --save-dev jest ts-jest @types/jest @types/supertest supertest npx ts-jest config:initThis will create a
jest.config.jsfile. -
Refactor the application for testability:
- Move all your Express app definition logic from
src/index.tsinto a newsrc/server.tsfile. - The
src/index.tsfile should only contain theserver.listen()part, which starts the server. - Create a
testsfolder and mirror the structure of yoursrcfolder for your test files.
- Move all your Express app definition logic from
-
Install Knip to keep the project clean:
pnpm add -D knip -
Set up ESLint for code linting:
pnpm add --save-dev eslint jiti @eslint/js typescript-eslint @stylistic/eslint-plugin eslint-plugin-nCreate an
eslint.config.tsfile with the following settings (modify as needed):import eslint from '@eslint/js'; import tseslint from 'typescript-eslint'; import stylistic from '@stylistic/eslint-plugin'; import nodePlugin from 'eslint-plugin-n'; export default tseslint.config( eslint.configs.recommended, nodePlugin.configs['flat/recommended-script'], ...tseslint.configs.strictTypeChecked, ...tseslint.configs.stylisticTypeChecked, { ignores: [ '**/node_modules/*', '**/*.mjs', '**/*.js', ], }, { languageOptions: { parserOptions: { project: './tsconfig.json', warnOnUnsupportedTypeScriptVersion: false, }, }, }, { plugins: { '@stylistic/js': stylistic, '@stylistic/ts': stylistic, }, }, { files: ['**/*.ts'], }, { rules: { '@typescript-eslint/explicit-member-accessibility': 'warn', '@typescript-eslint/no-misused-promises': 0, '@typescript-eslint/no-floating-promises': 0, '@typescript-eslint/no-confusing-void-expression': 0, '@typescript-eslint/no-unnecessary-condition': 0, '@typescript-eslint/restrict-template-expressions': [ 'error', { allowNumber: true }, ], '@typescript-eslint/restrict-plus-operands': [ 'warn', { allowNumberAndString: true }, ], '@typescript-eslint/no-unused-vars': 'warn', '@typescript-eslint/no-unsafe-enum-comparison': 0, '@typescript-eslint/no-unnecessary-type-parameters': 0, '@stylistic/js/no-extra-semi': 'warn', 'max-len': [ 'warn', { 'code': 80, }, ], '@stylistic/ts/semi': ['warn', 'always'], '@stylistic/ts/member-delimiter-style': ['warn', { 'multiline': { 'delimiter': 'comma', 'requireLast': true, }, 'singleline': { 'delimiter': 'comma', 'requireLast': false, }, 'overrides': { 'interface': { 'singleline': { 'delimiter': 'semi', 'requireLast': false, }, 'multiline': { 'delimiter': 'semi', 'requireLast': true, }, }, }, }], '@typescript-eslint/no-non-null-assertion': 0, '@typescript-eslint/no-unused-expressions': 'warn', 'comma-dangle': ['warn', 'always-multiline'], 'no-console': 1, 'no-extra-boolean-cast': 0, 'indent': ['warn', 2], 'quotes': ['warn', 'single'], 'n/no-process-env': 1, 'n/no-missing-import': 0, 'n/no-unpublished-import': 0, 'prefer-const': 'warn', }, }, ); -
Set up Docker: Create a
Dockerfilefile:# Use the official Node.js image. FROM node:22-slim # Create and change to the app directory. WORKDIR /usr/src/app # Copy package.json and pnpm-lock.yaml COPY package.json pnpm-lock.yaml ./ # Install pnpm RUN npm install -g pnpm # Install dependencies RUN pnpm install # Copy the rest of the application's source code. COPY . . # Build the project RUN pnpm run build # Expose the port the app runs on EXPOSE 3000 # Serve the app CMD [ "pnpm", "start" ]Create a
docker-compose.ymlfile:services: exp-min: build: . container_name: "exp-min" ports: - "3000:3000"