使用create-react-app
创建的项目默认是无法修改其内部的webpack
配置的,不像vue-cli
那样可以通过一个配置文件修改。 虽然有一个eject
命令可以是将配置完全暴露出来,但这是一个不可逆的操作,同时也会失去CRA
带来的便利和后续升级。
如果想要无 eject
重写 CRA
配置,目前成熟的是下面这几种方式
--scripts-version
参数,创建项目时使用自己重写过的 react-scripts
包react-app-rewired
+ customize-cra
组合覆盖配置craco
覆盖配置这里我们选择的是使用craco
覆盖配置
create-react-app
创建一个项目,这里我们命名为 react-app
npx create-react-app react-app --template typescript
craco
依赖npm install --save @craco/craco
craco.config.js
,并根据实际情况完善配置const path = require('path');
const { name } = require('./package.json');
const pathResolve = pathUrl => path.join(__dirname, pathUrl);
module.exports = {
reactScriptsVersion: 'react-scripts' /* (default value) */,
webpack: {
alias: {
'@': pathResolve('src'),
'@assets': pathResolve('src/assets'),
'@components': pathResolve('src/components'),
'@constants': pathResolve('src/constants'),
'@containers': pathResolve('src/containers'),
'@hooks': pathResolve('src/hooks'),
'@mocks': pathResolve('src/mocks'),
'@routes': pathResolve('src/routes'),
'@services': pathResolve('src/services'),
'@styles': pathResolve('src/styles'),
'@types': pathResolve('src/types'),
'@utils': pathResolve('src/utils'),
'@contexts': pathResolve('src/contexts'),
},
configure(webpackConfig) {
// 配置扩展扩展名
webpackConfig.resolve.extensions = [...webpackConfig.resolve.extensions, ...['.scss', '.css']];
// 接入微前端框架qiankun的配置,不接入微前端可以不需要
webpackConfig.output.library = `${name}-[name]`;
webpackConfig.output.libraryTarget = 'umd';
webpackConfig.output.globalObject = 'window';
return webpackConfig;
},
},
devServer: {
// 本地服务的端口号
port: 3001,
// 本地服务的响应头设置
headers: {
// 允许跨域
'Access-Control-Allow-Origin': '*',
},
},
};
详细配置请参考官网文档
package.json
中的 scripts
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
},
ESLint
是一个在 JavaScript
代码中通过规则模式匹配作代码识别和报告的插件化的检测工具,它的目的是保证代码规范的一致性和及时发现代码问题、提前避免错误发生。
ESLint 的关注点是代码质量,检查代码风格并且会提示不符合风格规范的代码。除此之外 ESLint
也具有一部分代码格式化的功能。
bug
;比如:api语法错误、使用了未定义的变量、修改const变量
比如:使用tab还是空格,使用单引号还是双引号等
比如:可以借助eslint-config-standard配置包扩展社区中流行的最佳实践的风格指南。
这样就能极大提高项目中多人协作开发时的效率、代码的可读性以及可维护性。
ESLint 支持几种格式的配置文件:
.eslintrc.js
然后输出一个配置对象。.eslintrc.yaml
或 .eslintrc.yml
去定义配置的结构。.eslintrc.json
去定义配置的结构,ESLint
的 JSON
文件允许 JavaScript
风格的注释。.eslintrc
,可以使 JSON 也可以是 YAML。eslintConfig
属性,在那里定义你的配置。如果同一个目录下有多个配置文件,ESLint 只会使用一个。优先级顺序如下:
.eslintrc.js
> .eslintrc.yaml
> .eslintrc.yml
> .eslintrc.json
> .eslintrc
> package.json
遇到项目内有多个层叠配置时,依然采用就近原则作为高优先级;
ESLint 附带有大量的规则。你可以使用注释或配置文件修改你项目中要使用的规则。要改变一个规则设置,你必须将规则 ID 设置为下列值之一:
"off"
或 0
- 关闭规则"warn"
或 1
- 开启规则,使用警告级别的错误:warn (不会导致程序退出)"error"
或 2
- 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)例如:
rules: {
'eqeqeq': 2,
'no-alert': 2,
'no-undef': 2,
'no-use-before-define': 2,
'react-hooks/exhaustive-deps': 2,
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-non-null-assertion': 0,
'@typescript-eslint/no-var-requires': 0,
},
启用ESLint
规则后,当访问当前源文件内未定义的变量时,no-undef
规则将发出警告。
而有时候,我们是需要在其他文件访问一些全局变量的,且保证能正常取到值。这时可以在 ESLint
中定义这些全局变量,这样 ESLint
就不会发出警告了。
/* global var1, var2 */
这定义了两个全局变量,var1
和 var2
。如果你想选择性地指定这些全局变量可以被写入(而不是只被读取),那么你可以用一个 "writable"
的标志来设置它们:
/* global var1:writable, var2:writable */
globals
配置属性设置,对于每个全局变量键,将对应的值设置为 "writable"
以允许重写变量,或 "readonly"
不允许重写变量。例如:// .eslintrc.js
"globals": {
"var1": "writable",
"var2": "readonly"
}
每种环境都有一组特定的预定义全局变量。如brower、node环境变量、es2021环境变量等。
env: {
browser: true,
es2021: true,
node: true,
},
ESLint 支持使用第三方插件,先在项目中下载安装要引入的插件,配置文件中使用 plugins
关键字来存放插件名字的列表。插件名称可以省略 eslint-plugin-
前缀。
plugins: ['react', 'babel'], // eslint-plugin-react eslint-plugin-babel
一个配置文件可以被基础配置中的已启用的规则继承。
extends: ["eslint:recommended","plugin:prettier/recommended"],
ESLint 可以安装在当前项目中或全局环境下,但因项目间存在的差异性,我们一般会将它安装在当前项目中。
npm install eslint --save-dev
假如项目中使用了TypeScript和React,则安装
// 安装eslint-plugin-react配置包扩展支持React语法
// 安装 @typescript-eslint/parser,替代掉默认的Espree解析器
// 安装@typescript-eslint/eslint-plugin提供额外的ts 语法的规则
npm install --save-dev eslint-plugin-react @typescript-eslint/parser @typescript-eslint/eslint-plugin
其他的插件和解析器请根据实际项目需要安装。
创建配置文件有以下两种方式
.eslintrc.js
文件,并自己完善该配置文件npx eslint--init
并根据提示自动创建配置文件文件配置大致如下:
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
},
root: true,
extends: ['eslint:recommended', 'react-app', 'plugin:prettier/recommended', 'plugin:@typescript-eslint/recommended'],
overrides: [],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
ecmaFeatures: {
jsx: true,
},
},
plugins: ['react', '@typescript-eslint'],
rules: {
eqeqeq: 2,
'no-alert': 2,
'no-undef': 2,
'no-use-before-define': 2,
'react-hooks/exhaustive-deps': 2,
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-non-null-assertion': 0,
'@typescript-eslint/no-var-requires': 0,
},
};
具体配置可根据项目实际需要进行配置
在package.json
中添加如下命令:
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
// 新添加的lint命令,意思是使用.eslintrc.js检测src文件夹下的后缀为.ts,.tsx,.js,.jsx的所有文件,并对可自动修复的eslint报错进行修复
"lint": "eslint -c .eslintrc.js src --ext .ts,.tsx,.js,.jsx --fix"
},
之后就可以运行npm run lint
这个命令进行eslint校验;
比如,我们在项目内任意一个ts文件内输入如下代码:
console.log('jump', age);
然后运行npm run lint
就会发现终端报如下错误:
这就说明,我们的Eslint
配置成功了
Prettier是一个诞生于2016年就迅速流行起来的专注于代码格式化的工具。出道即巅峰啊-.-
Prettier只关注格式化,并不具有lint检查语法等能力。它通过解析代码并匹配自己的一套规则,来强制执行一致的代码展示格式。
它在美化代码方面有很大的优势,配合ESLint可以对ESLint格式化基础上做一个很好的补充。
npm install prettier --save-dev
在项目根目录新建.prettierrc.js
,并完善配置
大致配置如下:
module.exports = {
// 1.一行代码的最大字符数,默认是80(printWidth: )
printWidth: 120,
// 2.tab宽度为2空格(tabWidth: )
tabWidth: 2,
// 3.是否使用tab来缩进,我们使用空格(useTabs: )
useTabs: false,
// 4.结尾是否添加分号,false的情况下只会在一些导致ASI错误的其工况下在开头加分号,我选择无分号结尾的风格(semi: )
semi: true,
// 5.使用单引号(singleQuote: )
singleQuote: true,
// 6.object对象中key值是否加引号(quoteProps: "")as-needed只有在需求要的情况下加引号,consistent是有一个需要引号就统一加,preserve是保留用户输入的引号
quoteProps: 'as-needed',
// 7.在jsx文件中的引号需要单独设置(jsxSingleQuote: )
jsxSingleQuote: false,
// 8.尾部逗号设置,es5是尾部逗号兼容es5,none就是没有尾部逗号,all是指所有可能的情况,需要node8和es2017以上的环境。(trailingComma: "")
trailingComma: 'es5',
// 9.object对象里面的key和value值和括号间的空格(bracketSpacing: )
bracketSpacing: true,
// 10.jsx标签多行属性写法时,尖括号是否另起一行(jsxBracketSameLine: )
jsxBracketSameLine: false,
// 11.箭头函数单个参数的情况是否省略括号,默认always是总是带括号(arrowParens: "")
arrowParens: 'avoid',
// 12.range是format执行的范围,可以选执行一个文件的一部分,默认的设置是整个文件(rangeStart: rangeEnd: )
rangeStart: 0,
rangeEnd: Infinity,
// 18. vue script和style标签中是否缩进,开启可能会破坏编辑器的代码折叠
vueIndentScriptAndStyle: false,
// 19. endOfLine: "" 行尾换行符,默认是lf,
endOfLine: 'auto',
// 20.embeddedLanguageFormatting: "off",默认是auto,控制被引号包裹的代码是否进行格式化
embeddedLanguageFormatting: 'off',
};
在代码格式化时采用Perttier规则,而我们代码校验使用的是ESLint,如果同一个规则配置不一致,往往就会出现冲突问题;
比如:字符串单、双引号的配置,eslint fix后把字符串变成单引号,再次编辑文件后,保存(Prettier)自动格式化后却又变成双引号,导致代码校验异常。
通常有以下两种解决方法:
安装eslint-config-prettier
插件配置集,把其配置到eslintrc
规则的尾部。执行eslint
命令,会禁用那些和Prettier
配置有冲突的规则。
安装eslint-plugin-prettier
插件,先使用Prettier
对代码进行格式化,再并对不一致的地方进行标记;
这两个包配合使用,可以达到运行 eslint --fix
时,采用Prettier
的配置规则 来格式化文件。
husky
是一个为 git
客户端增加 hook
的工具。安装后,它会自动在仓库中的 .git/
目录下增加相应的钩子;比如 pre-commit
钩子就会在你执行 git commit
的触发。
我们可以在 pre-commit
中实现一些比如 lint
检查、单元测试、代码美化等操作。当然,pre-commit
阶段执行的命令当然要保证其速度不要太慢,每次 commit
都等很久也不是什么好的体验。
也可以在commit-msg
钩子中结合commitlint
实现提交信息的检查
Git Hooks
就是在 Git
执行特定事件(如commit
、push
、receive
等)时触发运行的脚本,类似于“钩子函数”,没有设置可执行的钩子将被忽略。
git hook
的作用是在 git
动作发生前后触发自定义脚本。这些动作包括提交,合并,推送等,我们可以利用这些钩子在 git
流程的各个环节实现自己的业务逻辑。
git hook 分为客户端 hook 和服务端 hook。
客户端 hook 主要有四个:
pre-commit
:提交信息前运行,可检查暂存区的代码prepare-commit-msg
:不常用commit-msg
:非常重要,检查提交信息就用这个钩子post-commit
:提交完成后运行服务端 hook 包括:
pre-receive
:非常重要,推送前的各种检查都在这post-receive
:不常用update
:不常用npx husky-init install // npm
yarn dlx husky-init // Yarn 2+
pnpm dlx husky-init // pnpm
husky-init
命令主要做了以下的事情
pre-commit
的钩子,钩子中内容为#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run test
"prepare":"husky install"
。npm install
时默认会执行这个脚本pre-commit
钩子修改pre-commit
钩子内容为:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
echo "pre-commit";
npm run lint;
这样我们每次执行git commit
命令的时候都会触发pre-commit
钩子,从而在控制台先打印pre-commit
,然后在执行一遍eslint
校验,如果eslint
校验失败就会中止git commit
;
lint-staged
之前我们的配置是每次git commit
的时候都执行一次npm run lint
,这个命令会把src
文件夹下的所有符合文件格式的文件都走一遍eslint
校验,这显然是不太合理的;尤其是项目越来越大的时候这更是一个很耗时的操作。所以,我们需要过滤出git暂存区
里的文件,仅对暂存区的文件做eslint
校验即可。
lint-staged
就是这样一个工具,它可以帮我们过滤出 Git
代码暂存区文件(被 git add
的文件)。这个很实用,因为我们如果对整个项目的代码做一个检查,可能耗时很长,如果是老项目,要对之前的代码做一个代码规范检查并修改的话,这可能就麻烦了呀,可能导致项目改动很大。
lint-staged
总是将所有暂存文件的列表传递给任务。
lint-staged
lint-staged
npm install lint-staged --save-dev
lint-staged
package.json
中新增如下命令:// package.json
"lint-staged": {
"src/**/*.{ts,tsx,js,jsx}": [
"eslint -c .eslintrc.js --fix"
]
}
这条命令的意思是,对于暂存区中src
文件夹下后缀名为ts,tsx,js,jsx
的文件执行eslint
校验并自动修复可修复的eslint
报错。当然,也可以根据项目需要加入其他任务,比如:
// package.json
"lint-staged": {
"src/**/*.{js,vue}": [
"prettier --write",
"eslint --cache --fix",
"git add"
]
}
这里 lint-staged
的配置是:在 git
的待提交的文件中,在 src
目录下的所有 .js .vue
都要执行三条命令。使用prettier
格式化文件样式;校验eslint
并自动修复;将处理过的代码重新 add
到 暂存区 中。
pre-commit
钩子pre-commit
钩子的内容修改为如下:#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
echo "pre-commit";
npx lint-staged;
这样每次提交的时候就只会对暂存区中的文件进行eslint
校验了。
以上就是react
项目使用craco
进行配置并集成Prettier
、Eslint
、husky
、lint-staged
的详细内容,详细代码可查看我的代码仓库。