Setup dự án Node.js với TypeScript ESLint Prettier

Article banner photo
Published on
/3 mins read/

📁 Cấu trúc thư mục

  • dist: Thư mục chứa các file build
  • src: Thư mục chứa mã nguồn
  • src/constants: Chứa các file hằng số
  • src/middlewares: Các hàm xử lý middleware như validate, check token, ...
  • src/controllers: Nhận request, gọi service xử lý logic nghiệp vụ, trả về response
  • src/services: Gọi đến database để xử lý logic nghiệp vụ
  • src/models: Chứa các model
  • src/routes: Chứa các route
  • src/utils: Chứa các hàm tiện ích như mã hóa, gửi email,...

🥇 Khởi tạo dự án Node.js với TypeScript

  1. Tạo thư mục dự án
    snippet.txt
    mkdir nodejs-typescript
    cd nodejs-typescript
  2. Khởi tạo file package.json
    snippet.txt
    npm init -y
  3. Cài TypeScript
    snippet.txt
    npm install typescript --save-dev
  4. Cài đặt kiểu dữ liệu cho Node.js
    snippet.txt
    npm install @types/node --save-dev
  5. Cài đặt ESLint
    snippet.txt
    npm init @eslint/config@latest

🥈 Cài đặt các package cấu hình

snippet.txt
npm install prettier eslint-config-prettier eslint-plugin-prettier tsx tsc-alias rimraf nodemon --save-dev
  • prettier: Format code
  • eslint-config-prettier: Loại xung đột ESLint - Prettier
  • tsx: Chạy code TS không cần build
  • tsc-alias: Dùng để xử lý alias khi build
  • rimraf: Xoá folder dist
  • nodemon: Tự restart server khi có thay đổi

🥈 Cấu hình tsconfig.json

snippet.txt
{
  "compilerOptions": {
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "target": "ES2023",
    "outDir": "dist",
    "esModuleInterop": true,
    "strict": true,
    "skipLibCheck": true,
    "baseUrl": ".",
    "paths": {
      "~/*": ["src/*"]
    }
  },
  "files": ["src/type.d.ts"],
  "include": ["src/**/*"]
}

🥈 Cấu hình ESLint và Prettier

eslint.config.mjs

snippet.txt
import globals from 'globals'
import pluginJs from '@eslint/js'
import tseslint from 'typescript-eslint'
import eslintPluginPrettier from 'eslint-plugin-prettier'

export default [
  { files: ['**/*.{js,mjs,cjs,ts}'] },
  { languageOptions: { globals: globals.node } },
  pluginJs.configs.recommended,
  ...tseslint.configs.recommended,
  {
    plugins: {
      prettier: eslintPluginPrettier
    },
    rules: {
      '@typescript-eslint/no-explicit-any': 'warn',
      '@typescript-eslint/no-unused-vars': 'warn',
      'prettier/prettier': [
        'warn',
        {
          arrowParens: 'always',
          semi: false,
          trailingComma: 'none',
          tabWidth: 2,
          endOfLine: 'auto',
          useTabs: false,
          singleQuote: true,
          printWidth: 120,
          jsxSingleQuote: true
        }
      ]
    },
    ignores: ['**/node_modules/', '**/dist/']
  }
]

.prettierrc

snippet.txt
{
  "arrowParens": "always",
  "semi": false,
  "trailingComma": "none",
  "tabWidth": 2,
  "endOfLine": "auto",
  "useTabs": false,
  "singleQuote": true,
  "printWidth": 120,
  "jsxSingleQuote": true
}

.prettierignore

snippet.txt
node_modules/
dist/

.editorconfig

snippet.txt
[*]
indent_size = 2
indent_style = space

.gitignore

snippet.txt
node_modules/
dist/

nodemon.json

snippet.txt
{
  "watch": ["src", ".env"],
  "ext": ".ts,.js",
  "ignore": [],
  "exec": "tsx ./src/index.ts"
}

🥈 Scripts trong package.json

snippet.txt
"scripts": {
  "dev": "npx nodemon",
  "build": "rimraf ./dist && tsc && tsc-alias",
  "start": "node dist/index.js",
  "lint": "eslint .",
  "lint:fix": "eslint . --fix",
  "prettier": "prettier --check .",
  "prettier:fix": "prettier --write ."
}

🥇 Tạo file type.d.ts

Tạo trong thư mục src. Nội dung có thể để trống trước, nhưng được dùng để khai báo type toàn cục.

🥇 Tạo file index.ts

snippet.txt
const name: string = 'Dư Thanh Được'
console.log(name)

📌 Câu lệnh quan trọng

  • Chạy dev: npm run dev
  • Build production: npm run build
  • Chạy sau khi build: npm run start
  • Kiểm tra ESLint: npm run lint
  • Sửa ESLint: npm run lint:fix
  • Kiểm tra Prettier: npm run prettier
  • Sửa Prettier: npm run prettier:fix

✅ Một số lưu ý

  • Build bỏ qua lỗi: tsc --noCheck
  • Thư viện thiếu type: cài @types/tên-thư-viện (VD: express)
  • Import thư viện ESModule:
    snippet.txt
    const lib = (await import('ten-thu-vien')).default
;