别人在代码里拉的shi,凭什么要我去扒,如何给老项目加上 eslint,外加 ts check 配置

1,157 阅读3分钟

背景:老项目没有配 eslint,或者 eslint 规则松散,配了跟没配一样。需要加上 eslint 或者加入更加严格的规则。

做减法

选择一个规则比较严格的扩展包,根据实际情况把不需要的规则一个个关掉,这个过程中一些歪瓜裂枣的写法无法遁形。个人喜欢用 eslint-config-airbnb ,常规配置如下:

module.exports = {
  root: true,
  globals: {
    page: true,
    REACT_APP_ENV: true,
    UMI_ENV: true,
  },
  settings: {
    react: {
      version: 'detect',
    },
  },
  parserOptions: {
    parser: '@typescript-eslint/parser',
    ecmaFeatures: {
      jsx: true,
    },
  },
  extends: [
    'airbnb',
    'plugin:@typescript-eslint/recommended',
    'prettier',
    'plugin:react/recommended',
  ],
  plugins: ['prettier', 'react', 'react-hooks', '@typescript-eslint'],
  rules: {
    'prettier/prettier': 'error',
    '@typescript-eslint/no-explicit-any': 'error',
    eqeqeq: 'error',
    '@typescript-eslint/no-unused-vars': [
      'error',
      {
        vars: 'local',
        args: 'none',
        varsIgnorePattern: 'usePresenter|^I',
        caughtErrors: 'none',
      },
    ],
  },
};

根据配置,全量代码 lint 一遍:

"lint": "eslint --ext .ts,.tsx,.js,.jsx --fix src/",

执行

yarn lint

你可能会得到这样的大礼包

image.png

根据实际情况把不需要的规则减去,我的配置如下:

module.exports = {
  root: true,
  globals: {
    page: true,
    REACT_APP_ENV: true,
    UMI_ENV: true,
  },
  settings: {
    react: {
      version: 'detect',
    },
  },
  parserOptions: {
    parser: '@typescript-eslint/parser',
    ecmaFeatures: {
      jsx: true,
    },
  },
  extends: [
    'airbnb',
    'plugin:@typescript-eslint/recommended',
    'prettier',
    'plugin:react/recommended',
  ],
  plugins: ['prettier', 'react', 'react-hooks', '@typescript-eslint'],
  rules: {
    'prettier/prettier': 'error',
    '@typescript-eslint/no-explicit-any': 'error',
    eqeqeq: 'error',
    '@typescript-eslint/no-unused-vars': [
      'error',
      {
        vars: 'local',
        args: 'none',
        varsIgnorePattern: 'usePresenter|^I',
        caughtErrors: 'none',
      },
    ],
    'react-hooks/exhaustive-deps': 0,
    '@typescript-eslint/no-empty-function': 0,
    '@typescript-eslint/no-var-requires': 0,
    'react/react-in-jsx-scope': 0,
    'react/display-name': 0,
    '@typescript-eslint/no-non-null-assertion': 0,
    'react/jsx-filename-extension': 0,
    'react/function-component-definition': 0,
    'import/no-unresolved': 0,
    'import/extensions': 0,
    'arrow-body-style': 0,
    'react/jsx-no-useless-fragment': 0,
    'react/jsx-props-no-spreading': 0,
    'react/no-unstable-nested-components': 0,
    'jsx-a11y/alt-text': 0,
    'prefer-template': 0,
    'import/prefer-default-export': 0,
    'no-use-before-define': 0,
    'object-shorthand': 0,
    camelcase: 0,
    radix: 0,
    'class-methods-use-this': 0,
    'import/no-extraneous-dependencies': 0,
    'prefer-destructuring': 0,
    'jsx-a11y/click-events-have-key-events': 0,
    'jsx-a11y/no-static-element-interactions': 0,
    'consistent-return': 0,
    'no-unsafe-optional-chaining': 0,
    'jsx-a11y/media-has-caption': 0,
    'react/destructuring-assignment': 0,
    'no-plusplus': 0,
    'no-else-return': 0,
    'no-console': 0,
    'prefer-exponentiation-operator': 0,
    'func-names': 0,
    'react/require-default-props': 0,
    'no-return-assign': 0,
    'no-lonely-if': 0,
    'no-empty': 0,
    'jsx-a11y/anchor-is-valid': 0,
    'no-restricted-properties': 0,
    'operator-assignment': 0,
    'prefer-promise-reject-errors': 0,
    'no-prototype-builtins': 0,
    'prefer-object-spread': 0,
    'no-param-reassign': 0,
    '@typescript-eslint/no-empty-interface': 0,
  },
};

处理老代码

按上面配置执行 lint 时,新加的代码是能通过的。但是原来的代码可能还是一大堆问题

image.png

原来的代码如果不再改动,那么我们完全不需要去管了,但这是不可能的。一旦有迭代需要改原来的代码,哪怕只改了一行代码,提交代码的时候 git 钩子是过不去的,而且打开这些代码时,编辑器估计是一片红。

秉着别人拉的shi,凭什么要我去扒的原则,我们不想去改迭代需求之外的代码,但是又要能正常提交。需要借助 eslint 的一个配置,那就是 overrides

overrides 允许给特定的文件配置特定的rules,比如:

overrides: [
    {
      files: [
        'src/pages/activities/list.tsx',
      ],
      rules: {
        '@typescript-eslint/no-explicit-any': 'off',
        eqeqeq: 'off',
      },
    },
  ],

需要将所有的旧代码文件配置到 files 数组里,这可是个体力活,写个脚本去处理:

import glob from 'glob';
import path from 'path';
import fs from 'fs-extra';

export const getFiles = () =>
  new Promise<string[]>((resolve, reject) => {
    glob(
      '**',
      {
        cwd: path.join('H:/你的项目地址/src'),
        ignore: [],
        nodir: true,
        dot: true,
      },
      (err, files) => {
        if (err) {
          reject(err);
          return;
        }
        resolve(files);
      },
    );
  });

getFiles().then((files) => {
  fs.writeFileSync(
    './overrides.txt',
    files
      .filter(
        (s) =>
          s.includes('.vue') ||
          s.includes('.ts') ||
          s.includes('.js') ||
          s.includes('.tsx'),
      )
      .map((s) => `'src/${s}',`)
      .join('\r'),
  );
});

把文件 overrides.txt 里的内容复制到 files 数组中。内容可能会非常的多,可以将 overrides 配置在独单的文件里,比如:

./ignoreCheckAndLintFiles/.eslintrc.js 配置到这个文件里

// files只允许删减,不允许增加
module.exports = {
  overrides: [
    {
      files: [
        'src/pages/activities/list.tsx',
        // ...省略
      ],
      rules: {
        '@typescript-eslint/no-explicit-any': 'off',
        eqeqeq: 'off',
        // ... 省略
      },
    },
  ],
};

在项目根目录的 .eslintrc.js 文件中引入

const overrides = require('./ignoreCheckAndLintFiles/.eslintrc.js');

module.exports = {
  // ... 省略
  overrides: overrides.overrides,
};
// 可以添加规则 删除、忽略规则先说明原因 请严格执行

再执行lint ,强迫症都治好了

pC0Q7rT.png

ts check 配置

配置 tsconfig.json 文件,禁止使用 any,严格模式

"noImplicitAny": true,
"strict": true

配置 ts ckeck 命令

"tsc": "tsc --noEmit --skipLibCheck"

老代码肯定是过不去的,配置 exclude 数组,把旧代码文件放进去,也是配置在单独的文件里。

./ignoreCheckAndLintFiles/tsconfig.json

{
  "extends": "../tsconfig.json",
  "exclude": [
    "../src/pages/login.tsx"
    // ... 省略
  ]
}

也是用脚本去处理

import glob from 'glob';
import path from 'path';
import fs from 'fs-extra';

export const getFiles = () =>
  new Promise<string[]>((resolve, reject) => {
    glob(
      '**',
      {
        cwd: path.join('H:/VankeService/katarina/src'),
        ignore: [],
        nodir: true,
        dot: true,
      },
      (err, files) => {
        if (err) {
          reject(err);
          return;
        }
        resolve(files);
      },
    );
  });

getFiles().then((files) => {
  fs.writeJSONSync('./exclude.json', {
    extends: '../tsconfig.json',
    exclude: files
      .filter(
        (s) => s.includes('.vue') || s.includes('.ts') || s.includes('.tsx'),
      )
      .map((s) => `../src/${s}`),
  });
});

exclude.json 内容复制到 ./ignoreCheckAndLintFiles/tsconfig.json

修改 ts check 命令

"tsc": "tsc --project ./ignoreCheckAndLintFiles/tsconfig.json --noEmit --skipLibCheck"

新代码里引入旧代码还是会报错,所以尽量不要再去使用旧代码,或者旧代码里使用// @ts-ignore