Yevhen Klymentiev
dark
light
console
darkness
y.klymentiev@gmail.com
Reusable Snippets|Practical utility code for everyday use — custom-built and ready to share

FE Next.js (TS)

This guide walks you through configuring a Next.js (TypeScript) project with ESLint, Prettier, Stylelint, Jest, Husky, and Semantic Release for a complete, automated development experience.

1. Install core dev dependencies

File
Copied!
1npm install -D \
2  eslint prettier stylelint \
3  eslint-config-prettier eslint-plugin-prettier \
4  eslint-plugin-react eslint-plugin-react-hooks \
5  @typescript-eslint/eslint-plugin @typescript-eslint/parser \
6  stylelint-config-standard stylelint-config-prettier \
7  jest @types/jest ts-jest \
8  @testing-library/react @testing-library/jest-dom @testing-library/user-event \
9  husky lint-staged \
10  @commitlint/config-conventional @commitlint/cli \
11  semantic-release @semantic-release/changelog @semantic-release/git \
12  @semantic-release/github @semantic-release/commit-analyzer @semantic-release/release-notes-generator \
13  identity-obj-proxy

2. Create .eslintrc.js

JavaScript
Copied!
1module.exports = {
2  root: true,
3  parser: '@typescript-eslint/parser',
4  parserOptions: {
5    ecmaVersion: 'latest',
6    sourceType: 'module',
7    ecmaFeatures: { jsx: true },
8    project: './tsconfig.json',
9  },
10  env: {
11    browser: true,
12    es2021: true,
13    jest: true,
14    node: true,
15  },
16  plugins: ['react', 'react-hooks', '@typescript-eslint', 'import', 'prettier'],
17  extends: [
18    'eslint:recommended',
19    'plugin:react/recommended',
20    'plugin:react-hooks/recommended',
21    'plugin:@typescript-eslint/recommended',
22    'plugin:import/recommended',
23    'plugin:import/typescript',
24    'plugin:prettier/recommended',
25  ],
26  settings: {
27    react: { version: 'detect' },
28  },
29  rules: {
30    'prettier/prettier': 'error',
31    'react/react-in-jsx-scope': 'off',
32    '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
33    'import/order': [
34      'warn',
35      {
36        groups: [['builtin', 'external'], 'internal', ['parent', 'sibling']],
37        'newlines-between': 'always',
38      },
39    ],
40  },
41};

3. Create jsconfig.json

JSON
Copied!
1{
2  "compilerOptions": {
3    "paths": {
4      "@/*": ["./*"]
5    }
6  }
7}

4. Create .prettierrc

JSON
Copied!
1{
2  "singleQuote": true,
3  "trailingComma": "all",
4  "printWidth": 100,
5  "tabWidth": 2,
6  "semi": true
7}

5. Create stylelint.config.js

JavaScript
Copied!
1module.exports = {
2  extends: ['stylelint-config-standard', 'stylelint-config-prettier'],
3  rules: {
4    'at-rule-no-unknown': [
5      true,
6      {
7        ignoreAtRules: ['tailwind', 'apply', 'variants', 'responsive', 'screen'],
8      },
9    ],
10    'no-descending-specificity': null,
11  },
12};

6. Configure lint-staged and Husky

Add to package.json:

JSON
Copied!
1{
2  "scripts": {
3    "prepare": "husky install"
4  },
5  "lint-staged": {
6    "*.{ts,tsx,js,jsx}": [
7      "eslint --fix",
8      "prettier --write"
9    ],
10    "*.{css,scss}": [
11      "stylelint --fix",
12      "prettier --write"
13    ],
14    "*.{json,md,yml}": ["prettier --write"]
15  }
16}

Enable hooks:

File
Copied!
1npx husky install
2npx husky add .husky/pre-commit "npx lint-staged"
3npx husky add .husky/commit-msg "npx --no -- commitlint --edit \"$1\""

7. Create jest.config.ts

TypeScript
Copied!
1import type { Config } from 'jest';
2
3const config: Config = {
4  preset: 'ts-jest',
5  testEnvironment: 'jsdom',
6  setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
7  moduleNameMapper: {
8    '^@/(.*)$': '<rootDir>/src/$1',
9    '\.(css|scss)$': 'identity-obj-proxy',
10  },
11  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
12  testPathIgnorePatterns: ['/node_modules/', '/.next/'],
13};
14
15export default config;

8. Create jest.setup.ts

TypeScript
Copied!
import '@testing-library/jest-dom';

9. Create release.config.js

JavaScript
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', 'package-lock.json'],
17        message: 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}',
18      },
19    ],
20    '@semantic-release/github',
21  ],
22};

10. Add common npm scripts to package.json

JSON
Copied!
1{
2  "scripts": {
3    "lint": "eslint . --ext .ts,.tsx,.js,.jsx",
4    "format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,css,scss,md}\"",
5    "stylelint": "stylelint \"**/*.{css,scss,ts,tsx,js,jsx}\" --cache",
6    "test": "jest",
7    "test:watch": "jest --watch",
8    "test:coverage": "jest --coverage",
9    "release": "semantic-release"
10  }
11}

11. Optional: VSCode settings

JSON
Copied!
1{
2  "editor.formatOnSave": true,
3  "editor.codeActionsOnSave": {
4    "source.fixAll.eslint": true
5  },
6  "eslint.validate": ["typescript", "typescriptreact"],
7  "prettier.enable": true
8}
Codebase: Dev Env Setup -> FE Next.js (TS) | Yevhen Klymentiev