--- tags: Setup --- # Application setup with Next.js and a robust configuration Learn how to set up a Next.js application with useful tooling and a robust configuration. Enforce consistent standards, automate quality checks, and manage environment settings, creating a strong foundation for efficient development and seamless collaboration. ## Create a Well-Organized Workspace I suggest structuring your workspace to mirror the application's domain and subdomains, grouping applications for easier management. For instance, `next-stack/my-app` would contain all files needed to develop and deploy the application hosted on `my-app.next-stack.com`: ```bash mkdir next-stack && cd $_ ``` ## Create a Next.js Application Run the following command and select: - `my-app` as the name - `No` for customize the import alias ```bash npx create-next-app@latest --use-pnpm --typescript --eslint --tailwind --src-dir --app --turbopack ``` ### tsconfig Configuration Add the following properties to `compilerOptions` field in `tsconfig.json` file: ```json "removeComments": true, "forceConsistentCasingInFileNames": true, "noUnusedLocals": true, "noUnusedParameters": true, "exactOptionalPropertyTypes": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "noUncheckedIndexedAccess": true, "noImplicitOverride": true, "noPropertyAccessFromIndexSignature": true, "allowUnusedLabels": false, "allowUnreachableCode": false, ``` ### Add [EditorConfig](https://editorconfig.org) Create a `.editorconfig` file: ```bash touch .editorconfig ``` Insert the following content: ``` root = true [*] charset = utf-8 indent_style = space indent_size = 2 insert_final_newline = true trim_trailing_whitespace = true [*.md] max_line_length = off trim_trailing_whitespace = false ``` ### Add [Vitest](https://vitest.dev/) ```bash pnpm i -D vitest @vitejs/plugin-react jsdom @vitest/coverage-v8 ``` Create the `vitest.config.mts` file: ```bash touch vitest.config.mts ``` Insert the following content: ```typescript import { defineConfig } from 'vitest/config' import react from '@vitejs/plugin-react' export default defineConfig({ plugins: [react()], test: { environment: 'jsdom', }, }) ``` Add the `test` command to the `scripts` property in the `package.json` file: ```json "test": "vitest", ``` ### Add [Prettier](https://prettier.io/) ```bash pnpm i -D prettier prettier-plugin-tailwindcss ``` Create the `.prettierrc` file: ```bash touch .prettierrc ``` Insert the following configuration: ```json { "plugins": ["prettier-plugin-tailwindcss"], "printWidth": 128, "tabWidth": 2, "useTabs": false, "semi": true, "singleQuote": true, "quoteProps": "as-needed", "jsxSingleQuote": true, "trailingComma": "none", "bracketSpacing": true, "bracketSameLine": true, "arrowParens": "always", "requirePragma": false, "insertPragma": false, "proseWrap": "preserve", "htmlWhitespaceSensitivity": "ignore", "vueIndentScriptAndStyle": false, "endOfLine": "lf", "embeddedLanguageFormatting": "auto" } ``` If you are using WebStorm, when opening this file, a message will prompt you to use this configuration for the entire project. Select "Yes" to apply it. Create the `.prettierignore` file: ```bash touch .prettierignore ``` Ignore the following files and directories in the Prettier check: ``` .git/ .idea/ .vscode/ node_modules/ .next/ build/ dist/ coverage/ out/ ``` Run Prettier on all files in the project: ```bash pnpm exec prettier . --write ``` The files that appear in white have been modified, while those in grey were already properly formatted. If you are using WebStorm, in the configurations, search for `Prettier`, select `Automatic Prettier configuration`, and check the box for `Run on save`. ![image](https://hackmd.io/_uploads/H1JA2iu4R.png) Add the `prettier` and `prettier.ci` commands to the `scripts` property in the `package.json` file: ```json "prettier": "prettier --write ./src/", "prettier.ci": "prettier --check ./src/", ``` ### Add [Stylelint](https://stylelint.io/) ```bash pnpm i -D stylelint stylelint-config-standard stylelint-config-tailwindcss ``` Create the `.stylelintrc` file: ```bash touch .stylelintrc ``` Insert the following configuration: ```json { "extends": ["stylelint-config-recommended", "stylelint-config-tailwindcss"] } ``` Run Stylelint with the `fix` option on all `css` files in the project: ```bash pnpm exec stylelint "**/*.css" --fix ``` Add the `lint.style` command to the `scripts` property in the `package.json` file: ```json "lint.style": "stylelint \"**/*.css\"", ``` ### Configurer [ESLint](https://eslint.org/) Install the default ESLint configurations for JS and TS: ```bash pnpm i -D eslint @eslint/js @types/eslint__js typescript-eslint eslint-plugin-functional eslint-plugin-import eslint-config-prettier eslint-plugin-security eslint-plugin-react eslint-plugin-boundaries @vitest/eslint-plugin ``` Replace the `.eslintrc.json` file with `eslint.config.mjs`: ```bash mv .eslintrc.json eslint.config.mjs ``` Replace the file content with: ```js import eslint from '@eslint/js'; import tseslint from 'typescript-eslint'; import functional from 'eslint-plugin-functional'; import importPlugin from 'eslint-plugin-import'; import eslintConfigPrettier from 'eslint-config-prettier'; import pluginSecurity from 'eslint-plugin-security'; import react from 'eslint-plugin-react'; import boundaries from 'eslint-plugin-boundaries'; import vitest from '@vitest/eslint-plugin'; export default tseslint.config( { files: ['src/**/*.spec.ts', 'src/**/*.test.ts'], plugins: { vitest }, extends: [vitest.configs.recommended], rules: { ...vitest.configs.recommended.rules } }, { files: ['src/**/*.ts'], ignores: ['src/**/*.spec.ts', 'src/**/*.test.ts'], plugins: { boundaries }, extends: [ functional.configs.externalTypeScriptRecommended, functional.configs.recommended, functional.configs.stylistic, ], }, { files: ['src/**/*.ts'], plugins: { boundaries }, extends: [ eslint.configs.recommended, ...tseslint.configs.strictTypeChecked, ...tseslint.configs.stylisticTypeChecked, importPlugin.flatConfigs.recommended, pluginSecurity.configs.recommended, react.configs.flat.recommended, react.configs.flat['jsx-runtime'], eslintConfigPrettier ], settings: { 'boundaries/elements': [] }, rules: { ...boundaries.configs.recommended.rules }, languageOptions: { parserOptions: { projectService: true, tsconfigRootDir: import.meta.dirname, ecmaFeatures: { jsx: true } } } } ); ``` Create the `.eslintignore` file: ```bash touch .eslintignore ``` Ignore the following files and directories in Eslint check: ``` .git/ .idea/ .vscode/ node_modules/ .next/ build/ dist/ coverage/ out/ ``` Rename the `lint` command to `lint.es` in the `scripts` property of the `package.json` file: ```json "lint.es": "next lint", ``` ### Add [Commitlint](https://commitlint.js.org/) ```bash pnpm i -D @commitlint/{cli,config-conventional} node --eval "fs.writeFileSync('.commitlintrc.mjs','export default { extends: [\'@commitlint/config-conventional\'] };')" ``` Add the `lint.commit` command to the `scripts` property in `package.json` file: ```json "lint.commit": "commitlint --from origin/main", ``` ### Add [lint-staged](https://github.com/lint-staged/lint-staged) ```bash pnpm i -D lint-staged ``` Create `.lintstagedrc` file: ```bash touch .lintstagedrc ``` Insert the following rules: ```json { "*.(js|mjs|jsx|ts|mts|tsx)": ["eslint", "prettier --write"], "*.(css)": ["stylelint", "prettier --write"], "*.(md|json|xml|html|sh|yml|yaml)": "prettier --write" } ``` ### Add [Husky](https://typicode.github.io/husky/) ```bash pnpm i -D husky npx husky init node --eval "fs.writeFileSync('.husky/pre-commit','pnpm exec lint-staged\n')" node --eval "fs.writeFileSync('.husky/commit-msg','pnpm exec commitlint --edit \$1\n')" ``` ### Add [dotenv](https://github.com/motdotla/dotenv#readme) ```bash pnpm i dotenv ``` Create `.env.example` file: ```bash touch .env.example ``` Add `.env` file to `.gitignore` under `# local env files` ### Make the commit for the configuration. ```bash git add . && git commit -m"chore: application setup and configuration" ``` --- [Next](https://hackmd.io/pVySIYBOSQGH30s7hPQ_Bg) [Home](https://hackmd.io/9GoEP2IbT6SIJQHOf03PbA)