项目的创建和运行
项目包管理器使用 pnpm。
pnpm 和 npm/yarn 一样,本质上都是包管理器,但是它在性能上有极大的提升:包安装速度快、高效利用磁盘空间、安全性高、支持 monorepo 等。
它的安装很方便,一般使用 npm
安装:
npm install pnpm
首先,基于 Vite 创建一个命名为 react-basic
的 react-typescript
模板项目:
pnpm create vite react-basic --template react-ts
创建成功后,进入项目,执行 install
命令安装依赖:
pnpm i
启动服务前,可以在 vite.config.ts
中修改开发服务器的配置:
export default defineConfig({
server: {
host: 'localhost',
port: 3333, // 指定服务器端口
open: true, // 启动开发服务器时,自动在浏览器打开应用
strictPort: false, // 若端口被占用,尝试下一个可用端口
https: false, // 不开启 https 服务
cors: true, // 允许跨域
},
})
最后,执行 dev
命令启动项目,就会自动在浏览器打开对应页面:
pnpm run dev
项目配置
Vite 配置
vite.config.js
文件用于管理 Vite 的打包配置。在这个文件中,可以配置插件、别名、构建选项、服务器设置等各种与 Vite
相关的选项。
以下是一些常见的选项及其说明:
import { defineConfig } from 'vite';
import * as path from 'path';
import react from '@vitejs/plugin-react';
export default defineConfig({
base: './',
publicDir: 'public',
resolve: {
// 路径别名
alias: [
{ find: '@', replacement: path.resolve(__dirname, 'src') },
],
},
build: {
target: 'modules', // 浏览器兼容目标
outDir: 'dist', // 打包输出路径
assetsDir: 'assets', // 静态资源存放路径
cssCodeSplit: true, // 允许 css 代码拆分
sourcemap: false, // 不生成 sourceMap 文件
minify: 'terser', // 缩小文件体积
terserOptions: {
compress: {
drop_console: true, // 取消 console
drop_debugger: true, // 取消 debugger
},
},
},
server: {
host: 'localhost',
port: 3333, // 指定服务器端口
open: true, // 启动开发服务器时,自动在浏览器打开应用
strictPort: false, // 若端口被占用,尝试下一个可用端口
https: false, // 不开启 https 服务
cors: true, // 允许跨域
// 配置代理
proxy: {
'/api': {
target: 'http://127.0.0.1:8000', // 接口地址
changeOrigin: true, // 接口跨域
secure: false, // 启用 https 服务时需要配置
},
},
},
plugins: [react()],
});
如果在配置中指定了 minify: terser
,需要单独安装 terser
插件:
pnpm i terser -D
Typescript 配置
tsconfig.json
文件用于检查和编译 TypeScript 静态类型。
由于在 vite.config.ts
中配置了路径别名,为了防止 @
找不到对应模块而报错,接下来需要在 tsconfig.json
中添加以下配置:
"compilerOptions": {
// 路径映射配置
"baseUrl": "./",
"paths": {
"@": [ "src" ],
"@/*": [ "src/*" ],
}
// ...
},
代码规范配置
Eslint 配置
Eslint 用于检查代码质量。以下是个人常用的 .eslintrc.cjs
文件配置:
module.exports = {
env: {
es2020: true,
node: true,
browser: true,
},
extends: [
'eslint:recommended', // Eslint
'plugin:@typescript-eslint/recommended' // Typescript
],
parser: '@typescript-eslint/parser', // 解析 TS 代码
parserOptions: {
parser: '@babel/eslint-parser', // 解析和检查使用 Babel 转译的 JS 代码
sourceType: 'module',
ecmaVersion: 'latest',
ecmaFeatures: {
jsx: true
},
},
plugins: ['react-refresh', '@typescript-eslint'],
rules: {
// 禁止使用分号
'semi': 'off',
// 强制使用单引号
'quotes': ['error', 'single'],
// 不强制在箭头函数体周围使用大括号
'arrow-body-style': 'off',
// 警告变量声明未按字母顺序排序
'sort-vars': 'warn',
// 警告对象键未按字母顺序排序
'sort-keys': 'warn',
// 警告使用 `console` 方法
'no-console': 'off',
// 允许使用未声明的变量
'no-undef': 'off',
// 关闭禁止重复声明变量的规则
'no-redeclare': 'off',
// 关闭禁止重赋值函数参数的规则
'no-param-reassign': 'off',
// 关闭要求函数明确返回类型的规则
'@typescript-eslint/explicit-function-return-type': 'off',
// 警告使用 `any` 类型
'@typescript-eslint/no-explicit-any': 'warn',
// 关闭禁止未处理的 Promise 的规则
'@typescript-eslint/no-floating-promises': 'off',
// 关闭禁止错误使用 Promise 的规则
'@typescript-eslint/no-misused-promises': 'off',
// 关闭禁止使用非 null 断言运算符的规则
'@typescript-eslint/no-non-null-assertion': 'off',
// 强制禁止重复声明类型
'@typescript-eslint/no-redeclare': 'error',
// 关闭禁止使用与外部变量同名的变量的规则
'@typescript-eslint/no-shadow': 'off',
// 关闭禁止默认导出的规则
'import/no-default-export': 'off',
// 关闭禁止使用命名导入作为默认成员的规则
'import/no-named-as-default-member': 'off',
// 无须在组件中显式 import React
'react/jsx-uses-react': 'off',
// 关闭禁止在 JSX 中使用未转义的实体的规则
'react/no-unescaped-entities': 'off',
// 关闭强制要求在 JSX 文件中使用 `<React>` 命名空间的规则
'react/react-in-jsx-scope': 'off'
},
};
另外,可以在根目录下新建 .eslintignore
文件,告诉 Eslint
在进行规则校验时需要跳过的文件和目录。
.idea
.local
.vscode
/bin
/dist
/docs
/node_modules
/public
*.md
*.sh
*.ttf
*.woff
配置完成后,运行命令,看看 Eslint
校验能否正常工作:
pnpm run lint
此时尝试添加一个声明但未使用的变量,就会发出警告。
Prettier 配置
Prettier 专注于代码格式化,对代码不做质量检查。在项目中安装 prettier
:
pnpm i prettier -D
以下是个人常用的 .prettierrc.cjs
文件配置:
module.exports = {
tabWidth: 2, // 缩进长度
useTabs: false, // 使用空格代替 Tab 缩进
printWidth: 150, // 单行长度
semi: false, // 句末不使用分号
singleQuote: true, // 使用单引号
quoteProps: 'as-needed', // 仅在必需时为对象的 key 添加引号
jsxSingleQuote: true, // jsx 中使用单引号
trailingComma: 'all', // 多行时尽可能打印尾随逗号
bracketSpacing: true, // 在对象前后添加空格
arrowParens: 'always', // 箭头函数单参数时包裹圆括号
requirePragma: false, // 无需顶部注释即可格式化
htmlWhitespaceSensitivity: 'ignore', // 对 HTML 全局空白不敏感
embeddedLanguageFormatting: 'auto', // 对引用代码进行格式化
endOfLine: 'auto', // 不检查结束行形式
};
另外,同样可以在根目录下新建 .prettierignore
文件,告诉 Prettier
在进行代码格式化时需要跳过的文件和目录。
# Ignore artifacts:
build
coverage
# Ignore all HTML files:
*.html
配置完成后,我们就可以通过命令行进行文档格式化。
1)使用 write
命令,此处使用 .
指定格式化内容为根目录下所有文件:
npx prettier --write .
2)使用 check
命令,检查指定范围内的文件是否都符合规则:
npx prettier --check .
如果运行的是本地 Prettier
插件,需要在 prettier
命令前加上 npx
。
Eslint 和 Prettier 的集成
由于 Eslint
和 Prettier
有部分重叠功能,为了避免冲突,需要安装下列依赖:
pnpm install eslint-plugin-prettier eslint-config-prettier -D
接下来,在 .eslintrc.cjs
中添加配置:
extends: [
'plugin:prettier/recommended',
],
配置完成后,测试一下 Eslint
和 Prettier
是否可以正常工作。
在这个过程中,可能会遇到一些问题:
1)如果执行 lint
命令后出现了警告或报错信息,可以在 lint
命令加上 --fix
,此时就会采用项目中的 Prettier
配置规则自动格式化文件,而不需要手动修改。
2)如果新建的 Eslint
或 Prettier
配置文件使用了 .js
后缀,执行 lint
命令后会报错,因为 Vite
运行时使用 esbuild
,它遵循 ESModule
语法规范,此时 .js
文件默认使用 ESModule
语法规范来解析,如果配置文件使用了 CommonJS
语法规范,就会出错。
此时,将配置文件的后缀改为 .cjs
,明确声明使用的是 CommonJS
语法规范即可。
扩展:Eslint 相关插件的作用
-
eslint-plugin-vue
插件:针对Vue
的Eslint
语法校验。 -
eslint-plugin-react
插件:针对React
的Eslint
语法校验。 -
eslint-config-prettier
插件:协调Eslint
和Prettier
的格式化规则,防止冲突,本质上是禁用与Prettier
配置冲突的Eslint
规则。 -
eslint-plugin-prettier
插件:将Prettier
规则作为Eslint
规则使用,如果代码不符合Prettier
配置也会报错,此时可以通过eslint --fix
进行自动格式化,从而解决问题。 -
@typescript-eslint/eslint-plugin
插件:针对Typescript
的Eslint
语法校验。 -
@typescript-eslint/parser
插件:将Typescript
语法解析成AST
。
Husky 配置(可选)
Husky 是一个 Git
钩子管理工具,我们可以借助它,在某些 Git
操作对应的生命周期进行一些自动化操作,比如校验提交信息、检查代码质量等。首先,安装 husky
依赖:
pnpm install husky -D
配置 package.json
文件:
"scripts": {
// ...
"prepare": "husky install"
},
执行 prepare
命令,继续安装 husky
:
pnpm run prepare
在这个过程中,可能会遇到一些问题:
1)如果执行 prepare
命令后,出现 install command is deprecated
的提示信息,就将 husky install
替换成 husky
,然后重新执行 prepare
命令。
2)如果出现以下报错,说明项目在本地还没有初始化 git
仓库,需要先执行 git init
操作。重新执行 prepare
命令,继续安装 Husky
。
配置完成后,查看项目结构,可以看到新增了 .husky
目录。
添加 pre-commit hook
pre-commit hook
通常对暂存区文件进行规范校验。安装 lint-staged
依赖:
pnpm i lint-staged -D
添加 package.json
配置:
"scripts": {
// ...
"lint": "eslint src --ext js,jsx,ts,tsx --fix", // 添加 --fix 在遇到问题时会尝试自动修复
"lint:lint-staged": "lint-staged"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"pnpm run lint",
"npx prettier --write"
],
"*.{css,scss,less,styl,html}": [
"npx prettier --write"
],
"package.json": [
"npx prettier --write"
],
"{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": [
"npx prettier --write--parser json"
]
},
// ...
配置完成后,执行命令添加 pre-commit hook
:
npx husky add .husky/pre-commit "pnpm run lint:lint-staged"
现在可以使用 commit
命令,测试一下 lint-staged
配置是否生效。
可以看到,暂存区文件经过 Eslint
和 Prettier
的双重校验后成功提交,说明 pre-commit hook
配置生效了。
添加 commit-msg hook
commit-msg hook
通常对 commit
信息进行规范校验。安装依赖:
pnpm install @commitlint/config-conventional @commitlint/cli -D
在项目根目录下新建 .commitlintrc.cjs
文件,可以直接引入 @commitlint/config-conventional
插件,也可以自定义配置,更推荐直接使用 Angular
规范集。
module.exports = {
// 直接引入插件即可
extends: ['@commitlint/config-conventional'],
// 自定义配置
rules: {
'type-enum': [2, 'always', [
'build', // 编译相关修改,例如发布版本、项目构建或者依赖的改动
'feat', // 添加新功能
'fix', // 修复Bug
'update', // 更新某功能
'refactor', // 重构
'docs', // 文档更改
'chore', // 构建过程或辅助工具的变动,如添加依赖等
'style', // 不影响代码运行的变动
'revert', // 回滚到上一个版本
'perf', // 性能优化
'test', // 单元测试、集成测试等
],
],
'type-case': [0],
'type-empty': [0],
'scope-empty': [0],
'scope-case': [0],
'subject-full-stop': [0, 'never'],
'subject-case': [0, 'never'],
'header-max-length': [0, 'always', 74],
},
};
配置完成后,执行命令添加 commit-msg hook
:
npx husky add .husky/commit-msg "npx --no -- commitlint --edit ${1}"
此时使用 commit
命令提交代码,出现以下结果就说明 commit-msg hook
配置生效了。
目录结构划分
根据个人习惯添加对应的目录和文件,个人常用目录结构及其说明如下:
assets:原始静态资源管理
components:全局通用组件管理
hooks:自定义 Hooks 管理
pages:页面逻辑管理
routes:路由管理
service:接口管理
store:状态管理
utils:公用工具管理
组件库使用 Antd5
:
pnpm i antd@latest @ant-design/icons
在 App.tsx
中引入 Layout 布局,效果如下。
可以看到,Layout
组件不能占满屏幕,这里需要重置一下部分元素的样式。
最简单的解决方法:在 assets
目录下定义一个 css
文件夹,存放全局使用的 css
文件,然后创建 reset.css
文件,配置如下内容:
/* margin、padding 重置 */
body, h1, h2, h3, ul, ol, li, p, dl, dt, dd {
padding: 0;
margin: 0;
}
/* a 元素重置 */
a {
text-decoration: none;
color: #333;
}
/* img 的 vertical-align 重置 */
img {
vertical-align: top;
}
/* ul, ol, li 重置 */
ul, ol, li {
list-style: none;
}
/* 对斜体元素重置 */
i, em {
font-style: normal;
}
配置完成后,在 App.tsx
中引入 reset.css
并刷新一下界面,就可以看到 Layout
占满屏幕了。
最后
新手记录一下自己的学习过程,欢迎大家指出问题或提出建议。
关于项目路由的配置和集中管理,可以看这一篇: React 项目路由配置与跳转