Skip to content
This repository was archived by the owner on Mar 30, 2022. It is now read-only.

Project-Setup/Nextjs_Ts_Eslint

Folders and files

NameName
Last commit message
Last commit date

Latest commit

1597507 · Jan 13, 2021

History

32 Commits
Jan 13, 2021
Dec 2, 2020
Jan 13, 2021
Nov 30, 2020
Nov 30, 2020
Dec 2, 2020
Nov 17, 2020
Nov 14, 2020
Jan 7, 2021
Nov 14, 2020
Nov 17, 2020
Nov 14, 2020
Nov 14, 2020
Jan 13, 2021
Jan 7, 2021
Jan 7, 2021
Jan 13, 2021
Nov 24, 2020

Repository files navigation

Example Project Setup with NextJs, Typescript, Eslint, Jest and Emotion.

Dependency Versions

  • NextJs v10.0.5
  • react v17.0.1
  • Typescript v4.1.3
  • @emotion/react v11.1.4

Usage of this example setup

  1. setup node env
    nvm use || npm install
  2. remove unwanted files in public/, src/
  3. add .env and other .env files
  4. preview dev progress on http://localhost:3000/
    npm run dev
  5. read Setup for notes

Setup

  1. install nvm in the os
  2. nvm install node
    git init
  3. add .gitignore
  4. node -v > .nvmrc
  5. npm init -y
  1. npm i -S next react react-dom
  2. add a script to your package.json like this:
    {
      "scripts": {
        "dev": "next dev",
        "build": "next build",
        "start": "next start"
      }
    }
  1. npm i -D typescript @types/react @types/node
  2. create tsconfig.json
    {
      "compilerOptions": {
        "target": "esnext",
        "lib": ["dom", "dom.iterable", "esnext"],
        "allowJs": true,
        "allowSyntheticDefaultImports": true,
        "alwaysStrict": true,
        "skipLibCheck": true,
        "strict": false,
        "forceConsistentCasingInFileNames": true,
        "noEmit": true,
        "noFallthroughCasesInSwitch": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "esModuleInterop": true,
        "module": "esnext",
        "moduleResolution": "node",
        "resolveJsonModule": true,
        "isolatedModules": true,
        "jsx": "preserve",
        "baseUrl": "./src"
      },
      "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
      "exclude": ["node_modules", "next.config.js"]
    }
  1. create src/pages folder (or pages)
  2. create pages.tsx under src/pages/ (i.e. src/pages/index.tsx for / route)
  1. npm i -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-react eslint-import-resolver-typescript
    npm i -D eslint-config-airbnb eslint-plugin-jsx-a11y eslint-plugin-import eslint-plugin-react-hooks
    npm i -D prettier eslint-config-prettier eslint-plugin-prettier
  2. create .eslintrc.js
    module.exports = {
      env: {
        browser: true,
        node: true,
        es2020: true,
        jest: true,
      },
      parser: '@typescript-eslint/parser', // Specifies the ESLint parser
      parserOptions: {
        ecmaVersion: 2020,
        sourceType: 'module',
        ecmaFeatures: {
          jsx: true,
        },
      },
      plugins: ['@typescript-eslint', 'react', 'react-hooks', 'prettier'],
      extends: [
        'airbnb',
        'plugin:@typescript-eslint/recommended',
        'plugin:react/recommended',
        'plugin:import/errors',
        'plugin:import/warnings',
        'plugin:import/typescript',
        'prettier',
        'prettier/@typescript-eslint',
        'prettier/react',
        'plugin:prettier/recommended', // Enables eslint-plugin-prettier and displays prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.
      ],
      rules: {
        '@typescript-eslint/no-unused-vars': [
          'error',
          {
            vars: 'all',
            args: 'after-used',
            ignoreRestSiblings: false,
          },
        ],
        '@typescript-eslint/no-explicit-any': 0,
        '@typescript-eslint/explicit-function-return-type': 0,
        '@typescript-eslint/no-namespace': 0,
        '@typescript-eslint/explicit-module-boundary-types': 0,
        'import/extensions': [
          1,
          { extensions: ['.js', '.jsx', '.ts', '.tsx'] },
        ],
        'import/no-extraneous-dependencies': [
          'error',
          {
            devDependencies: true,
          },
        ],
        'react/jsx-filename-extension': [
          1,
          { extensions: ['.js', '.jsx', '.ts', '.tsx'] },
        ],
        'react/react-in-jsx-scope': 0,
        'react/jsx-first-prop-new-line': 0,
        'react/prop-types': 0,
        'react/jsx-props-no-spreading': [2, { custom: 'ignore' }],
        'jsx-a11y/anchor-is-valid': [
          'error',
          {
            components: ['Link'],
            specialLink: ['hrefLeft', 'hrefRight'],
            aspects: ['invalidHref', 'preferButton'],
          },
        ],
        'prettier/prettier': 2,
        'react-hooks/rules-of-hooks': 2,
        'react-hooks/exhaustive-deps': 2,
        'no-bitwise': 2,
      },
      settings: {
        'import/resolver': {
          node: {
            extensions: ['.js', '.jsx', '.ts', '.tsx'],
          },
          typescript: {},
        },
        react: {
          version: 'detect', // Tells eslint-plugin-react to automatically detect the version of React to use
        },
      },
    };
  3. create .prettierrc.js
    module.exports = {
      semi: true,
      trailingComma: 'es5',
      singleQuote: true,
      printWidth: 80,
      tabWidth: 2,
    };
  1. npm i -D jest babel-jest @types/jest @next/env
  2. add scripts in package.json

    "scripts": {
      "test": "jest",
      "test:watch": "jest --watch",
      "test:coverage": "jest --coverage"
    },
  3. create jest.config.js

    module.exports = {
      moduleFileExtensions: ['ts', 'tsx', 'js'],
      testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|js?|tsx?|ts?)$',
      globals: {
        NODE_ENV: 'test',
      },
      snapshotSerializers: ['enzyme-to-json/serializer'],
      transform: {
        '^.+\\.(j|t)sx?$': 'babel-jest',
      },
      coveragePathIgnorePatterns: [
        '/node_modules/',
        'jest.setup.js',
        '<rootDir>/configs/',
        'jest.config.js',
        '.json',
        '.snap',
      ],
      setupFiles: ['<rootDir>/jest/jest.setup.js'],
      coverageReporters: ['json', 'lcov', 'text', 'text-summary'],
      moduleNameMapper: {
        '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
          '<rootDir>/__mocks__/mocks.js',
        '\\.(css|less|scss)$': '<rootDir>/__mocks__/mocks.js',
      },
      moduleDirectories: ['node_modules', 'src'],
    };
  4. create babel.config.js

    module.exports = {
      presets: ['next/babel'],
    };
  5. create jest/jest.setup.js

    import { join } from 'path';
    import { loadEnvConfig } from '@next/env';
    
    // to load '.env' files in test
    loadEnvConfig(join(__dirname, '../'));
  6. change env in .eslintrc.js

    env: {
      browser: true,
      node: true,
      jest: true
    },
  1. npm i -S @emotion/react
    npm i -D @emotion/babel-plugin @emotion/eslint-plugin @emotion/jest
  2. change babel.config.js

    module.exports = {
      presets: [
        [
          'next/babel',
          {
            'preset-react': {
              runtime: 'automatic',
              importSource: '@emotion/react',
            },
          },
        ],
      ],
      plugins: ['@emotion/babel-plugin'],
    };
  3. add rules and plugins to .eslintrc.js

    module.exports = {
      // ...
      rules: {
        // ...
        '@emotion/no-vanilla': 'error',
        '@emotion/import-from-emotion': 'error',
        '@emotion/styled-import': 'error',
      },
      // ...
      plugins: [
        '@emotion',
        // ...
      ],
      // ...
    };
  4. add jest/jest.setupAfterEnv.js

    import { matchers } from '@emotion/jest';
    
    expect.extend(matchers);
  5. add serializers and setup files to jest/jest.config.js

    // ...
    snapshotSerializers: ['@emotion/jest/serializer'],
    // ...
    setupFilesAfterEnv: ['<rootDir>/jest.setupAfterEnv.js'],
    // ...
  6. add to tsconfig.json

    {
      "compilerOptions": {
        "jsxImportSource": "@emotion/react"
      }
    }

(deploy to /docs intead of using gh-pages branch; replace {folder} with the project name in github repo)

  1. add .env.production
    NEXT_PUBLIC_LINK_PREFIX=/{folder}
  2. create LINK_PREFIX in next.config.js
    const LINK_PREFIX = process.env.NEXT_PUBLIC_LINK_PREFIX || '';
    module.exports = () => ({
      basePath: LINK_PREFIX,
    });
  3. change scripts in package.json
    {
      "scripts": {
        "export": "NODE_ENV=production npm run build && next export -o docs && touch docs/.nojekyll"
      }
    }