前言
现在写前端代码基本都 ES6 了,更前沿的都开始使用 TS 了。本文的目标是:配置项目和编辑器,使写代码更舒服。更舒服一般体现在3点:
- 保存后实时报错(lint)
- 保存后自动格式化(prettier)
- 代码提交时自动lint且格式化(husky),确保团队代码风格统一
支持 ES6
- 转ES5
.babelrc
// react 项目
{
"presets": [
"env",
"react"
],
"plugins": [ "babel-plugin-transform-runtime","transform-object-rest-spread"] // 转换 rest 和 spread operator runtime转异步函数
}
// react-native 项目
{
"presets": ["module:metro-react-native-babel-preset"]
}
- Eslint
安装 eslint 和安装vs code 的 eslint 插件,书写 .eslintrc 文件
插件的目的是实时提示错误,否则只能通过命令行编译后才知道错误
{
"plugins": ["react", "prettier"],
"globals": {
"__DEV__": true,
"__dirname": false,
"__fbBatchedBridgeConfig": false,
"cancelAnimationFrame": false,
"clearImmediate": true,
"clearInterval": false,
"clearTimeout": false,
"console": false,
"document": false,
"escape": false,
"exports": false,
"fetch": false,
"global": false,
"jest": false,
"Map": true,
"module": false,
"navigator": false,
"process": false,
"Promise": true,
"requestAnimationFrame": true,
"require": false,
"Set": true,
"setImmediate": true,
"setInterval": false,
"setTimeout": false,
"window": false,
"XMLHttpRequest": false,
"alert": true,
"pit": false,
"ReactElement": true
},
"parser": "babel-eslint",
"env": {
"es6": true
},
"rules": {
"no-undef": "error",
"react/jsx-boolean-value": 0,
"react/jsx-curly-spacing": 1,
"react/jsx-indent-props": [1, 2],
"react/jsx-key": 1,
"react/jsx-max-props-per-line": 0,
"react/jsx-no-duplicate-props": 1,
"react/jsx-no-undef": 2,
"react/jsx-pascal-case": 1,
"react/jsx-uses-react": 1,
"react/jsx-uses-vars": 1,
"react/no-danger": 1,
"react/no-deprecated": 1,
"react/no-did-mount-set-state": 0,
"react/no-did-update-set-state": 1,
"react/no-direct-mutation-state": 1,
"react/no-is-mounted": 1,
"react/no-multi-comp": [1, {"ignoreStateless": true}],
"react/no-set-state": 0,
"react/no-unknown-property": 1,
"react/prefer-es6-class": 1,
"react/react-in-jsx-scope": 1,
"react/self-closing-comp": 1,
"react/sort-comp": 1,
"react/jsx-wrap-multilines": 1,
"react/prop-types": [2, { "ignore": [ "children", "navigation" ]}],
"jsx-quotes": 1,
"prettier/prettier": "error"
}
}
- Prettier
安装 Prettier 和安装vs code 的 Prettier 插件,书写.prettierrc。
插件的目的是实时提示错误,否则只能通过命令行编译后才知道错误
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": true,
"jsxBracketSameLine": false,
"arrowParens": "avoid",
"rangeStart": 0,
"parser": "babylon",
"requirePragma": false,
"insertPragma": false,
"proseWrap": "preserve"
}
- Eslint 结合 Prettier
安装 eslint-plugin-prettier ,这会让eslint调用prettier来格式化代码
若是 react 项目,还需安装 eslint-plugin-react 以支持 jsx 语法
最后开启 vscode 编辑器设置:
"prettier.eslintIntegration": true,
"eslint.autoFixOnSave": true,
"editor.formatOnSave": true,
- Prettier 结合 Husky
1、安装 husky 和 lint-staged
2、修改 package.json 配置,设置 precommit 和 lint-staged
{
"scripts": {
"precommit": "lint-staged"
},
"lint-staged": {
"*.{js,jsx}": ["eslint --fix", "git add"]
}
}
- 规范提交信息
npm i validate-commit-msg -D
在项目根目录新建 .vcmrc 文件
{
"types": ["feat", "fix", "docs", "style", "refactor", "perf", "test", "build", "ci", "chore", "revert"],
"scope": {
"required": false,
"allowed": ["*"],
"validate": false,
"multiple": false
},
"warnOnFail": false,
"maxSubjectLength": 100,
"subjectPattern": ".+",
"subjectPatternErrorMsg": "subject does not match subject pattern!",
"helpMessage": "",
"autoFix": true
}
修改 package.json
"husky": {
"hooks": {
...
"commit-msg": "validate-commit-msg"
}
}
- 生成 CHANGELOG.md
npm i conventional-changelog -D
修改 package.json
"scripts":{
...
"change-log":"conventional-changelog -p angular -i CHANGELOG.md -s"
}
支持 TS
tsconfig.json
npm install typescript typescript-eslint-parser eslint-plugin-typescript -D
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"strict": true,
"allowJs": true,
"skipLibCheck": true,
"sourceMap": true,
"importHelpers": true,
"downlevelIteration": true,
"lib": ["es2015", "dom"],
"jsx": "react",
"baseUrl": "./src"
},
"include": ["./src/**/*"]
}
// 配套的 .eslintrc 和 .prettierrc 需要调整
{
"plugins": ["typescript", "react", "prettier"],
"globals": {
"__DEV__": true,
"__dirname": false,
"__fbBatchedBridgeConfig": false,
"cancelAnimationFrame": false,
"clearImmediate": true,
"clearInterval": false,
"clearTimeout": false,
"console": false,
"document": false,
"escape": false,
"exports": false,
"fetch": false,
"global": false,
"jest": false,
"Map": true,
"module": false,
"navigator": false,
"process": false,
"Promise": true,
"requestAnimationFrame": true,
"require": false,
"Set": true,
"setImmediate": true,
"setInterval": false,
"setTimeout": false,
"window": false,
"XMLHttpRequest": false,
"alert": true,
"pit": false,
"ReactElement": true,
},
"parser": "typescript-eslint-parser",
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module",
"ecmaFeatures": {
"modules": true
}
},
"env": {
"es6": true
},
"rules": {
"no-undef": "error",
"react/jsx-boolean-value": 0,
"react/jsx-curly-spacing": 1,
"react/jsx-indent-props": [1, 2],
"react/jsx-key": 1,
"react/jsx-max-props-per-line": 0,
"react/jsx-no-duplicate-props": 1,
"react/jsx-no-undef": 2,
"react/jsx-pascal-case": 1,
"react/jsx-uses-react": 1,
"react/jsx-uses-vars": 1,
"react/no-danger": 1,
"react/no-deprecated": 1,
"react/no-did-mount-set-state": 0,
"react/no-did-update-set-state": 1,
"react/no-direct-mutation-state": 1,
"react/no-is-mounted": 1,
"react/no-multi-comp": [1, {
"ignoreStateless": true
}],
"react/no-set-state": 0,
"react/no-unknown-property": 1,
"react/prefer-es6-class": 1,
"react/react-in-jsx-scope": 1,
"react/self-closing-comp": 1,
"react/sort-comp": 1,
"react/jsx-wrap-multilines": 1,
"react/prop-types": [
2,
{
"ignore": ["children", "navigation", "history", "match", "location"]
}
],
"jsx-quotes": 1,
"prettier/prettier": "error",
"typescript/class-name-casing": "error"
}
}
// prettierrc
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": false,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": true,
"jsxBracketSameLine": false,
"arrowParens": "avoid",
"rangeStart": 0,
"requirePragma": false,
"insertPragma": false,
"proseWrap": "preserve",
"parser": "typescript"
}
需要注意的是:
1、在 tslint 中想让代码被 prettier 格式化有个前提,就是 tslint 必须全部编译通过。若一个文件报了 tslint 错误,那么该文件是不会被 prettier 格式化的。这个也是 不如 eslint 可以自动格式化的地方。
2、使用 TS 时,.prettierrc 中的 parser 要设为:'typescript',否则不能使用诸如 enum 之类的关键字(使用了代码不会报错,但 prettier 格式化工具会报错,你这个文件也就无法被 prettier 格式化)
参考
- Configure TypeScript, TSLint, and Prettier in VS Code for React Native Development
- https://segmentfault.com/a/1190000006697219
附录(其他插件)
- 同步插件 Settings Sync
能同步扩展、主题、脚本片段、快捷键等。详细使用:
https://www.cnblogs.com/kenz520/p/7416836.html - EditorConfig
1、在当前项目根目录下添加.editorconfig文件
2、安装EditorConfig扩展(怎么安装扩展哈?纳尼?打开百度或google,输入vscode 安装扩展 | vscode install extension;好了,不能再提示了)
3、全局安装或局部安装editorconfig依赖包(npm install -g editorconfig | npm install -D editorconfig)
4、打开需要格式化的文件并手动格式化代码(shift+alt+f)
注意:vscode自身有一些格式化设定,二者可以结合 - 字体
https://github.com/tonsky/FiraCode - turbojs
包含大部分 js snippest - carbon
代码分享十分美观 https://carbon.now.sh/ - 让不同项目侧边栏颜色不一样提高辨识度配置
// .vscode/settings.json
{
"workbench.colorCustomizations": {
"activityBar.background": "#67C23A"
}
}