Code style and linting

Code style and linting

For enforcing code style and utilizing static code analyzing we use ESLint (opens in a new tab) along with a bunch of rulesets and Prettier (opens in a new tab). The most noteworthy ruleset is the Airbnb JavaScript Style Guide (opens in a new tab).

We choose this approach because it provides strict but conventional rules. You can always execute the commands pnpm format:(check|write) to apply the Prettier formatting settings for all project files inside the src-directory, or pnpm lint to lint all projects files inside the src-directory based on the ESLint configuration.

We modified some rules to fit our code style. By default, ESLint will display an error if any rule is not satisfied. We don't work with warnings.

Our Prettier and ESLint configurations are located in own packages (eslint-config & prettier-config) that get published to npm (opens in a new tab). This way we can easily share the configuration between projects and keep them up to date consistently.

Explanation Prettier rules

We use the default Prettier rules (opens in a new tab) and overwrite the following ones:

"semi": false

Prevents printing semicolons at the end of statements.

"singleQuote": true

Use single quotes instead of double quotes.

"arrowParens": "avoid"

Do not include parentheses around a sole arrow function parameter.

"bracketSpacing": true

Print spaces between brackets in object literals.

Explanation ESLint rules

"react/react-in-jsx-scope": "off"

This rule automatically imports the react package in our file when we use JSX.

"react/jsx-props-no-spreading": "off"

Allow spreading props into components.

"react/require-default-props": "off"

Disable the requirement of default props for components.

"react/jsx-no-bind"

["error", { "allowFunctions": true, "allowArrowFunctions": true }]

Allow passing function references (expressions and declarations) as callbacks to component props.

"simple-import-sort/imports": "error"

To keep our import order consistent we chose to let it auto-sort by this ESLint plugin.

"simple-import-sort/exports": "error"

To keep our export order consistent we chose to let it auto-sort by this ESLint plugin.

"prettier/prettier": "error"

If any rule from the .prettierrc.json is not met, throw an error.

"import/extensions"

[
  2,
  "ignorePackages",
  {
    "": "never",
    "js": "never",
    "jsx": "never",
    "ts": "never",
    "tsx": "never"
  }
]

Allow omitting file extensions when importing either a .js, .jsx, .ts or .tsx file.

"import/no-extraneous-dependencies"

[
  "error",
  {
    "devDependencies": [
      "**/*.test.ts",
      "**/*.test.tsx",
      "**/*.config.js",
      "**/*.config.ts",
      "./scripts/sync-versions.ts",
      "./scripts/seed-db.ts"
    ]
  }
]

Forbid the import of external modules that are not declared in the package.json's dependencies, devDependencies, optionalDependencies, peerDependencies, or bundledDependencies.

"import/prefer-default-export": "off"

Do not prefer default export.

"@nrwl/nx/enforce-module-boundaries"

[
  "error",
  {
    "allow": [],
    "depConstraints": [
      {
        "sourceTag": "scope:app",
        "onlyDependOnLibsWithTags": ["scope:app", "scope:lib", "scope:types"]
      },
      {
        "sourceTag": "scope:lib",
        "onlyDependOnLibsWithTags": ["scope:lib", "scope:types"]
      },
      {
        "sourceTag": "scope:types",
        "onlyDependOnLibsWithTags": ["scope:types"]
      }
    ]
  }
]

Here we set contraints which package can import other packages inside the packages folder. For example, it does not make sense to import anything from app in lib but vice versa.

"@typescript-eslint/explicit-function-return-type"

[
  "error",
  {
    "allowExpressions": true
  }
]

Always pass the return type of a function declaration. As we follow the rule to prefer function declarations over expressions for 'standalone' functions (not as callback) it makes sense to enforce the rule only for function declarations.

"consistent-return": "off"

We disabled the rule due to the fact that we don't want to return undefined in every function explicitly.