Shareable config setting and what is it?

Greetings! In the course of his professional activity, every front-end developer encounters an integral part of development – the ESLint tool. ESLint is a powerful static code analyzer designed to detect and fix problems in your JavaScript code.

Today we’ll talk about setting up shareable config. We’ll look at how this can help product teams or freelance developers, and then move on to setting up this configuration.

Shareable Config: When is it needed?

Imagine a situation in which you have several cross-functional teams developing different company products, but using a similar technology stack. In this context, there is a need for common standards and approaches to writing code to ensure a uniform development style. In this case, the ESLint tool comes to the rescue.

Once the sets of rules have been agreed upon and those responsible for their implementation and configuration have been assigned, the implementation stage in projects begins. However, if you need to make changes to your ESLint configuration, editing all your projects multiple times can be time-consuming and inefficient. It is in such situations that the creation of a Shareable config for ESLint and its subsequent publication in a package repository such as npm or other package registries comes to the rescue

Benefits of creating and using Shareable config:

  1. One rule: By creating a Shareable config, you establish a single set of rules for all projects. This ensures a consistent code style and reduces the likelihood of errors associated with different configurations.

  2. Centralized management: If you need to make changes to the ESLint rules, you can make them in the Shareable config and those changes will automatically apply to all projects using that configuration. This greatly simplifies the management and maintenance of the codebase.

  3. Cost reduction: Instead of editing configurations in each project, you only make changes to the Shareable config and publish it. This saves time and reduces maintenance costs.

  4. Public availability: Publishing Shareable config to the package registry allows other teams and developers to use your configuration. This promotes the spread of front-end standards and allows others to implement them in their projects.

Initializing Project Configuration

Let’s create a folder eslint-config-test and create a module with a limited scope. We use the command npm init --scope=@test and go through the installation steps.

As a result, we will get a file based on this:

{
  "name": "@test/eslint-config-test",
  "version": "1.0.0",
  "description": "ESLint Shareable Config",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "eslint",
    "share",
    "config"
  ],
  "author": "Kim Valentin",
  "license": "ISC"
}

It’s important to note here @test – scope npm module, more details in documentation

Here, if necessary, you can add a few more optional properties: “files”, “repository”,“bugs”, “dependencies”, “devDependencies”, “peerDependencies” and others. You can find out more about each in documentation

I added a couple of packages for the config to work (they will not need to be installed in the main project, except for peerDependencies):

"dependencies": {
    "@typescript-eslint/eslint-plugin": "^6.7.2",
    "@typescript-eslint/parser": "^6.7.2",
    "@vue/eslint-config-typescript": "^12.0.0",
    "eslint-config-airbnb-base": "^15.0.0",
    "eslint-plugin-import": "^2.28.1",
    "eslint-plugin-vue": "^9.17.0"
  },
  "devDependencies": {
    "eslint": "^8.50.0",
    "typescript": "~5.2.2"
  },
  "peerDependencies": {
    "eslint": ">= 8.50.0",
    "typescript": ">= 5.0.0"
  }

Creating a configuration module

Everything is quite simple here, we are creating a module for future use with an extension .js. For example, I came up with the following module:

module.exports = {
  root: true,

  env: {
    es6: true,
    browser: true,
    node: true,
  },

  extends: [
    'plugin:@typescript-eslint/recommended',
    'plugin:vue/vue3-recommended',
    '@vue/eslint-config-typescript',
    'airbnb-base',
  ],

  parserOptions: {
    parser: require.resolve('@typescript-eslint/parser'),
    extraFileExtensions: ['.vue'],
    ecmaVersion: 'latest',
    sourceType: "module",
    ecmaFeatures: {
      jsx: true,
    },
  },

  globals: {
    JSX: true,
  },

  plugins: ['@typescript-eslint'],

  rules: {
    semi: ['error', 'never'],
    'no-param-reassign': 'off',
    'no-void': 'off',
    'no-nested-ternary': 'off',
    'max-classes-per-file': 'off',
    'linebreak-style': 0, // ignore linebreak-style
    'no-plusplus': 'off',
    'max-len': ['error', {
      code: 255,
      ignoreComments: true,
    }],
    'vue/block-order': ['error', {
      'order': [ [ 'script', 'template' ], 'style' ]
    }],
    'no-use-before-define': 'off',
    '@typescript-eslint/no-use-before-define': ['error', { ignoreTypeReferences: true }],
    'no-underscore-dangle': 'off',
    'no-shadow': 0,
    '@typescript-eslint/no-shadow': 0,
    'new-cap': ['error', { newIsCap: false }],
    'import/first': 'off',
    'import/named': 'error',
    'import/namespace': 'error',
    'import/default': 'error',
    'import/export': 'error',
    'import/extensions': 'off',
    'import/no-unresolved': 'off',
    'import/no-extraneous-dependencies': 'off',
    'import/prefer-default-export': 'off',

    // 'prefer-promise-reject-errors': 'off',

    quotes: ['warn', 'single', { avoidEscape: true }],

    // this rule, if on, would require explicit return type on the `render` function
    '@typescript-eslint/explicit-function-return-type': 'off',

    // in plain CommonJS modules, you can't use `import foo = require('foo')` to pass this rule, so it has to be disabled
    '@typescript-eslint/no-var-requires': 'off',

    // The core 'no-unused-vars' rules (in the eslint:recommended ruleset)
    // does not work with type definitions
    'no-unused-vars': 'off',

    // allow debugger during development only
    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    '@typescript-eslint/member-delimiter-style': ['error', {
      multiline: {
        delimiter: 'none',
        requireLast: true,
      },
      singleline: {
        delimiter: 'comma',
        requireLast: false,
      },
      multilineDetection: 'brackets',
    }],
    '@typescript-eslint/no-explicit-any': 'warn',
  },
}

Publishing a package

A couple of steps and we have created our config for you. Next, we can publish the package to npm or the Gitlab package registry. Set up CI and use it.

PS If you decide to use Gitlab’s package registry you will have several options, either configure publishConfig in package.json and ssh key in CI. Or use this construction:

"devDependencies": {
    "@test/eslint-config-test": "git+ssh://user@host/path/eslint-config-test#branch"
}

Using the package

It is necessary to install the necessary dependencies on the project (peerDependencies). Next you can create a file .eslintrc.cjs if you haven’t had it yet. And use your package there.

module.exports = {
  extends: [
    '@test/eslint-config-test',
  ],
}

You can also specify additional rules that will overwrite your config and will be applied locally to the current project.

Conclusion

Just to summarize, if you used to drag around your settings file and transfer it from one project to another, then this article will help you. With just a little bit of your time, you’ll create additional automation that will allow you to modify your coding rules in one place.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *