Reusable SnippetsPractical utility code for everyday use — custom-built and ready to share
BE Node.js (TS)
Step-by-step setup for a Node.js backend (TypeScript) with ESLint v9 flat config, typescript-eslint v8, Prettier, Jest + ts-jest, Husky v9, and Semantic Release.
1. Install dev dependencies
Copied!
1npm install -D \
2 typescript ts-node @types/node \
3 eslint @eslint/js globals typescript-eslint \
4 eslint-config-prettier eslint-plugin-prettier \
5 prettier \
6 jest ts-jest @types/jest supertest @types/supertest \
7 husky lint-staged \
8 @commitlint/config-conventional @commitlint/cli \
9 semantic-release @semantic-release/changelog @semantic-release/git \
10 @semantic-release/github @semantic-release/commit-analyzer \
11 @semantic-release/release-notes-generatorNote: typescript-eslint v8 is a unified package that replaces the separate @typescript-eslint/parser and @typescript-eslint/eslint-plugin.
2. Initialize TypeScript
Copied!
npx tsc --initRecommended settings in tsconfig.json:
Copied!
1{
2 "compilerOptions": {
3 "target": "ES2021",
4 "module": "CommonJS",
5 "moduleResolution": "node",
6 "outDir": "dist",
7 "rootDir": "src",
8 "esModuleInterop": true,
9 "skipLibCheck": true,
10 "strict": true
11 }
12}3. Create eslint.config.mjs
Copied!
1import js from '@eslint/js';
2import globals from 'globals';
3import tseslint from 'typescript-eslint';
4import prettierConfig from 'eslint-config-prettier';
5import prettier from 'eslint-plugin-prettier';
6
7export default tseslint.config(
8 { ignores: ['dist'] },
9 {
10 extends: [js.configs.recommended, ...tseslint.configs.recommended],
11 files: ['**/*.ts'],
12 languageOptions: {
13 ecmaVersion: 'latest',
14 globals: { ...globals.node },
15 },
16 plugins: { prettier },
17 rules: {
18 '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
19 'prettier/prettier': 'error',
20 },
21 },
22 prettierConfig,
23);Note: Use .mjs extension to force ESM syntax for the config regardless of the project's "type" field.
4. Create .prettierrc
Copied!
1{
2 "singleQuote": true,
3 "trailingComma": "all",
4 "printWidth": 100,
5 "tabWidth": 2,
6 "semi": true
7}5. Configure Husky and lint-staged
Add to package.json:
Copied!
1{
2 "scripts": {
3 "prepare": "husky"
4 },
5 "lint-staged": {
6 "*.ts": ["eslint --fix", "prettier --write"],
7 "*.{json,md,yml}": ["prettier --write"]
8 }
9}Initialize Husky and set up hooks:
Copied!
1npx husky init
2echo "npx lint-staged" > .husky/pre-commit
3echo "npx --no -- commitlint --edit \"$1\"" > .husky/commit-msgNote: Husky v9 replaced husky install with husky init. The prepare script is now just "husky".
6. Create commitlint.config.js
Copied!
1module.exports = {
2 extends: ['@commitlint/config-conventional'],
3};7. Create jest.config.js
Copied!
1/** @type {import('jest').Config} */
2module.exports = {
3 preset: 'ts-jest',
4 testEnvironment: 'node',
5 testMatch: ['**/tests/**/*.test.ts'],
6};8. Create release.config.js
Copied!
1module.exports = {
2 branches: ['main'],
3 plugins: [
4 '@semantic-release/commit-analyzer',
5 '@semantic-release/release-notes-generator',
6 [
7 '@semantic-release/changelog',
8 {
9 changelogFile: 'CHANGELOG.md',
10 changelogTitle: '# Changelog',
11 },
12 ],
13 [
14 '@semantic-release/git',
15 {
16 assets: ['CHANGELOG.md', 'package.json'],
17 message: 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}',
18 },
19 ],
20 '@semantic-release/github',
21 ],
22};In CI/CD, make sure GITHUB_TOKEN is available in the environment.
9. Add npm scripts to package.json
Copied!
1{
2 "scripts": {
3 "start": "node dist/index.js",
4 "build": "tsc",
5 "dev": "ts-node src/index.ts",
6 "lint": "eslint .",
7 "format": "prettier --write .",
8 "test": "jest",
9 "test:watch": "jest --watch",
10 "release": "semantic-release"
11 }
12}10. Optional: VSCode settings
Copied!
1{
2 "editor.formatOnSave": true,
3 "editor.codeActionsOnSave": {
4 "source.fixAll.eslint": "explicit"
5 },
6 "eslint.validate": ["typescript"],
7 "prettier.enable": true
8}