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

背景:老项目没有配 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',
},
],
},
};
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',

      },

    ],

  },
};
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/",
"lint": "eslint --ext .ts,.tsx,.js,.jsx --fix src/",
"lint": "eslint --ext .ts,.tsx,.js,.jsx --fix src/",

执行

yarn lint
yarn lint
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,
},
};
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,
  },
};
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',
},
},
],
overrides: [
    {
      files: [
        'src/pages/activities/list.tsx',
      ],
      rules: {
        '@typescript-eslint/no-explicit-any': 'off',
        eqeqeq: 'off',
      },
    },
  ],
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'),
);
});
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'),
  );
});
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',
// ... 省略
},
},
],
};
// files只允许删减,不允许增加
module.exports = {
  overrides: [
    {
      files: [
        'src/pages/activities/list.tsx',
        // ...省略
      ],
      rules: {
        '@typescript-eslint/no-explicit-any': 'off',
        eqeqeq: 'off',
        // ... 省略
      },
    },
  ],
};
// 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,
};
// 可以添加规则 删除、忽略规则先说明原因 请严格执行
const overrides = require('./ignoreCheckAndLintFiles/.eslintrc.js');

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

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

pC0Q7rT.png

ts check 配置

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

"noImplicitAny": true,
"strict": true
"noImplicitAny": true,
"strict": true
"noImplicitAny": true, "strict": true

配置 ts ckeck 命令

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

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

./ignoreCheckAndLintFiles/tsconfig.json

{
"extends": "../tsconfig.json",
"exclude": [
"../src/pages/login.tsx"
// ... 省略
]
}
{
  "extends": "../tsconfig.json",
  "exclude": [
    "../src/pages/login.tsx"
    // ... 省略
  ]
}
{ "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}`),
});
});
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}`),
  });
});
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"
"tsc": "tsc --project ./ignoreCheckAndLintFiles/tsconfig.json --noEmit --skipLibCheck"
"tsc": "tsc --project ./ignoreCheckAndLintFiles/tsconfig.json --noEmit --skipLibCheck"

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

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MY2e48u5' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片