快速给老前端项目添加eslint

151 阅读4分钟

背景

最近媳妇接到一个任务,将无外网的vue老项目添加规范,接到这个任务之后,我和我媳妇在家研究了三天三夜,不眠不休,终于搞定了,咱们来往下看看,如何添加规范的。

分析

考虑到开发环境的特殊性,咱们本着低风险,高收益的原则(渐进式)去处理。 受限条件:

  1. 文件个数 1k+
  2. 开发人员无法 install package,只能领导将包下载好之后 copy 给开发人员
  3. 多人维护的项目,尽量不让其他开发人员添加更多的配置
  4. windows 系统

根据上的面的限制,市场上比较流行的组合:eslint+prettier+husky+lint-staged.
husky:不太好使用,因为husky在install的时候才在.git/hooks中添加钩子脚本,内网开发人员做不到install
lint-staged: 主要是一个在 git 暂存文件上(也就是被 git add 的文件)运行已配置的 linter(或其他)任务。这里我们自己实现,能减少依赖尽量减少
最后,我们这个项目只用到 eslint+prettier 了。

那么问题来了,不适用husky,我们怎么在git commit 之前做lint呢?
其实,git已经给我们预留好了钩子,不过需要我们添加,.git/hooks/pre-commit,添加pre commit的相关操作即可,我们git commit之前git会先执行.git/hooks/pre-commit 再往后执行(除非被exit了)

还有一个就是渐进式去lint文件,所谓渐进式,就是commit哪个文件就lint哪个文件,其他的文件不做任何处理,这样只会影响自己改动的,不会影响到其他的文件了。

分析好了,咱们就开始操作了

安装eslint 和 prettier 插件和配置文件

  1. 插件 这个项目老到了node是10版本,因此,使用比较来的插件来处理,这里的插件就不一一解说了,自己可以百度看看是干啥的。
{
    "eslint": "^5.16.0",
    "eslint-config-standard": "^12.0.0",
    "eslint-loader": "^2.2.1",
    "eslint-plugin-html": "^6.1.2",
    "eslint-plugin-import": "^2.24.2",
    "eslint-plugin-node": "^11.1.0",
    "eslint-plugin-promise": "^5.1.0",
    "eslint-plugin-standard": "^5.0.0",
    "eslint-plugin-vue": "^5.0.0",
    "vue-eslint-parser": "^7.11.0",
    "eslint-config-prettier": "^4.0.0",
    "babel-eslint": "^9.0.0",
    "prettier": "^1.0.0",
    "eslint-plugin-prettier": "^3.0.0"
}
  1. eslintrc配置 在根目录添加.eslintrc.js配置文件
// https://eslint.org/docs/user-guide/configuring
module.exports = {
  root: true,
  parserOptions: {
    parser: 'babel-eslint'
  },
  env: {
    browser: true
  },
  extends: ['plugin:vue/essential', 'standard', 'plugin:prettier/recommended'],
  plugins: ['vue'],
  rules: {
    'prettier/prettier': [
      'error',
      {
        printWidth: 100,
        tabWidth: 2,
        useTabs: false,
        singleQuote: true,
        semi: true,
        bracketSpacing: true,
        jsxBracketSameLine: true
      }

    ],
    'generator-star-spacing': 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    // semi 语句结束带分号
    semi: 0,
    // 换行缩进 4个空格
    // indent: ["warn", 2, { SwitchCase: 1 }],
    'template-curly-spacing': 'off',
    indent: [
      'error',
      2,
      {
        ignoredNodes: ['TemplateLiteral']
      }
    ],
    // 禁止空块语句
    'no-empty': 2,
    // 不允许空比较
    'no-eq-null': 2,
    // 不允许 new 完后不赋值
    'no-new': 0,
    // 要求使用 === 和 !==
    eqeqeq: 0,
    // 生产环境无 console
    'no-console': process.env.NODE_ENV === 'production' ? ['error'] : 'off',
    // 函数左圆括号空格设置
    'space-before-function-paren': 0,
    // 对 Vue 组件标签,不进行检查
    'vue/no-parsing-error': [2, { 'x-invalid-end-tag': false }],
    'no-mixed-operators': 0,
    camelcase: 0,
    'standard/computed-property-even-spacing': 0,
    'prefer-promise-reject-errors': 0,
    'no-unused-vars': 0
  }
}
  1. prettier配置 在根目录添加.prettierrc.js配置文件
module.exports = {
  // 最大长度80个字符
  printWidth: 80,
  // 行末分号
  semi: false,
  // 单引号
  singleQuote: true,
  // JSX双引号
  jsxSingleQuote: false,
  // 尽可能使用尾随逗号(包括函数参数)
  trailingComma: "none",
  // 在对象文字中打印括号之间的空格。
  bracketSpacing: true,
  // > 标签放在最后一行的末尾,而不是单独放在下一行
  jsxBracketSameLine: false,
  // 箭头圆括号
  arrowParens: "avoid",
  // 在文件顶部插入一个特殊的 @format 标记,指定文件格式需要被格式化。
  insertPragma: false,
  // 缩进
  tabWidth: 2,
  // 使用tab还是空格
  useTabs: false,
  // 行尾换行格式
  endOfLine: "auto",
  HTMLWhitespaceSensitivity: "ignore"
};
  1. 渐进式校验并格式化文件 根据老项目的结构,我是放在了 build\pre-commit.sh
#!/bin/sh

# 代码冲突
result=$(git --no-pager diff HEAD --check | grep "conflict")
if [[ "$result" != "" ]]; then
 echo Resolve code conflicts, $result,$?
 exit 1
fi

# eslint staged
INFO='\033[36m'
NOR='\033[0m'
# 获取staged的文件相对路径
file=$(git diff --staged --name-only | egrep "^src/")
if [ -z "${file}" ]; then
  echo -e "${INFO}No file changed, exit now ${NOR}"
  exit 0
fi

# 校验并格式化staged的文件
npx eslint --fix --ext .js,.vue $file --cache > .eslitStash
a=$(cat .eslitStash | egrep "[1-9]\d*\s*problems?\s\([1-9]\d*\s*errors?")
cat .eslitStash
rm -rf .eslitStash
if [ -n "${a}" ]; then
   exit 1
fi

# 将格式化之后的文件重新 git add
exec git add $file

如何去做pre-commit呢

上面的分析已经说了,在.git/hooks 文件夹中添加pre-commit 脚本文件,然后去调用上面的 build\pre-commit.sh,这里的.git/hooks/pre-commit 我采用npm run xx形式添加,这样对于其他开发人员操作更加方便.
build\add-exec-to-pre-commit.sh

#!/bin/sh

echo "#!/bin/sh" > .git/hooks/pre-commit
echo "cd ." >> .git/hooks/pre-commit
echo "build\\\pre-commit.sh" >> .git/hooks/pre-commit

在package.json 的 scripts 添加执行命令

{
    "scripts":{
        "addPreCommitHook": "sh build/add-exec-to-pre-commit.sh"
    }
}

这样就OK啦,后面git commit 就会直接lint & fix staged的文件了。

如何利用vscode自动格式化呢

只需要安装三个插件: Prettier 、ESLint、Prettier-ESLint

image.png

image.png

image.png

  • vscode配置
{
  "prettier.configPath": ".prettierrc.js",
  "editor.formatOnSave": true,
  "[javascript]": { "editor.defaultFormatter": "rvest.vs-code-prettier-eslint" },
  "[typescript]": { "editor.defaultFormatter": "rvest.vs-code-prettier-eslint" },
  "[javascript|react]": { "editor.defaultFormatter": "rvest.vs-code-prettier-eslint" },
  "[typescript|react]": { "editor.defaultFormatter": "rvest.vs-code-prettier-eslint" },
  "[less]": { "editor.defaultFormatter": "rvest.vs-code-prettier-eslint" },
  "[css]": { "editor.defaultFormatter": "rvest.vs-code-prettier-eslint" },
  "[json]": { "editor.defaultFormatter": "rvest.vs-code-prettier-eslint" }
}
}

注意,一定要看

  • 上面用的Linux语法,因此,windows系统的,咱们git命令一定要在git bash中执行。否则sh文件无法执行
  • 如果不想eslint校验&fix, 直接使用 git commit -m "xxx" --no-verify

结束

感谢您认真看完,如有不同见解,可以在留言区一起讨论一下