项目工程化 create-react-app

302 阅读10分钟

一、项目工程化

1.1初始环境

  • node v18.17.0
  • yarn v1.22.19

1.1.1安装yarn

yarn 是 react 推荐的包管理工具

yarn安装指令

npm i -g yarn

1.1.2搭建脚手架

npx create-react-app my-app

2.2项目配置

一、配置eslint

eslint中文官网:eslint.nodejs.cn/

ESLint最初是由Nicholas C. Zakas 于2013年6月创建的开源项目。它的目标是提供一个插件化的javascript代码检测工具

首先安装eslint

yarn add eslint -D

生成配置文件:.eslintrc.js

npx eslint --init

按自己项目需求进行选择: image.png

生成初始化配置文件.eslintrc.js修改为.eslintrc.cjs (以下是默认内容, 之后要被全部替换)

module.exports = {
   //指定环境
    "env": { 
        "browser": true,//浏览器端
        "es2021": true,//es2021
    },
    //规则继承
    "extends": [ 
       //全部规则默认是关闭的,这个配置项开启推荐规则,推荐规则参照文档
       //比如:函数不能重名、对象不能出现重复key
        "eslint:recommended",
        //vue3语法规则
        "plugin:vue/vue3-essential",
        //ts语法规则
        "plugin:@typescript-eslint/recommended"
    ],
    //要为特定类型的文件指定处理器
    "overrides": [
    ],
    //指定解析器:解析器
    //Esprima 默认解析器
    //Babel-ESLint babel解析器
    //@typescript-eslint/parser ts解析器
    "parser": "@typescript-eslint/parser",
    //指定解析器选项
    "parserOptions": {
        "ecmaVersion": "latest",//校验ECMA最新版本
        "sourceType": "module"//设置为"script"(默认),或者"module"代码在ECMAScript模块中
    },
    //ESLint支持使用第三方插件。在使用插件之前,您必须使用npm安装它
    //该eslint-plugin-前缀可以从插件名称被省略
    "plugins": [
        "vue",
        "@typescript-eslint"
    ],
    //eslint规则
    "rules": {
    }
}
1.1react环境代码校验插件说明(目前共10个)
###### 让所有与prettier规则存在冲突的Eslint rules失效,并使用prettier进行代码检查
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-node": "^11.1.0",

###### 运行更漂亮的Eslint,使prettier规则优先级更高,Eslint优先级低
"eslint-plugin-prettier": "^4.2.1",

###### 该解析器允许使用Eslint校验所有babel code
"@babel/eslint-parser": "^7.19.1",

###############################################
"@typescript-eslint/eslint-plugin": "^6.1.0", //typescript对应的eslint 规则插件
"@typescript-eslint/parser": "^6.1.0",
"eslint": "^8.45.0",
"eslint-plugin-react": "^7.33.0",
"prettier": "^3.0.0"

安装指令( 先装7个,再装3个 )

yarn add -D eslint eslint-plugin-import eslint-plugin-react eslint-plugin-node @babel/eslint-parser @typescript-eslint/eslint-plugin @typescript-eslint/parser
1.2修改.eslintrc.cjs配置文件(全选覆盖)
module.exports = {
  // 运行环境
  env: {
    browser: true,
    es2021: true,
    node: true,
    jest: true,
  },
  /* 指定如何解析语法 */
  parser: '@typescript-eslint/parser', // 指定解析器
  /** 优先级低于 parse 的语法解析配置 */
  parserOptions: {
    parser: '@typescript-eslint/parser', // 指定解析器
    ecmaVersion: 'latest', // 允许解析那个版本的特性
    sourceType: 'module', // 允许使用 import
    jsxPragma: 'React',
    ecmaFeatures: {
      jsx: true, // 允许对JSX进行解析
    },
  },
  /* 继承已有的规则 */
  extends: [
    'eslint:recommended',
    'plugin:react/recommended', // @eslint-plugin-react 的推荐规则
    'plugin:@typescript-eslint/recommended', // @typescript-eslint/eslint-plugin的推荐规则
    'plugin:import/typescript', // eslint-plugin-import 抛出导入等支持的规则
    'plugin:prettier/recommended', // eslint-plugin-prettier 的推荐规则
  ],
  plugins: ['@typescript-eslint', 'react', 'prettier'],
  /*
   * "off" 或 0 - 关闭规则
   * "warn" 或 1 - 打开规则作为警告(不影响退出代码)
   * "error" 或 2 - 打开规则作为错误(退出代码将为 1)
   */
  rules: {
    // eslint(https://eslint.bootcss.com/docs/rules/)
    'no-var': 'error', // 要求使用 let 或 const 而不是 var
    'no-multiple-empty-lines': ['warn', { max: 1 }], // 不允许多个空行
    'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    'no-unexpected-multiline': 'error', // 禁止空余的多行
    'no-useless-escape': 'off', // 禁止不必要的转义字符

    // typeScript (https://typescript-eslint.io/rules)
    '@typescript-eslint/no-unused-vars': 'off', // 禁止定义未使用的变量
    '@typescript-eslint/prefer-ts-expect-error': 'error', // 禁止使用 @ts-ignore
    '@typescript-eslint/no-explicit-any': 'off', // 禁止使用 any 类型
    '@typescript-eslint/no-non-null-assertion': 'off',
    '@typescript-eslint/no-namespace': 'off', // 禁止使用自定义 TypeScript 模块和命名空间。
    '@typescript-eslint/semi': 'off',
  },
  // https://stackoverflow.com/questions/64126764/how-do-i-fix-typescript-compiler-errors-on-css-files
  ignorePatterns: ["**/*.css", "**/*.scss"],
}

1.3创建.eslintignore忽略文件
build
dist
node_modules
1.4配置脚本

package.json新增两个运行脚本

  "scripts": {
    ...
    "lint": "eslint src",
    "fix": "eslint src --fix",
  },

通过yarn lint去检测语法,如果出现不规范格式,通过yarn fix 修改

二、配置prettier

有了eslint,为什么还要有prettier?eslint针对的是javascript,他是一个检测工具,包含js语法以及少部分格式问题,在eslint看来,语法对了就能保证代码正常运行,格式问题属于其次;

而prettier属于格式化工具,它看不惯格式不统一,所以它就把eslint没干好的事接着干,另外,prettier支持

包含js在内的多种语言。

总结起来,eslint和prettier这俩兄弟一个保证js代码质量,一个保证代码美观。

2.1安装依赖包

先装7个,再装3个

yarn add -D eslint-plugin-prettier  prettier  eslint-config-prettier
2.2创建.prettierrc.js, 添加规则
// https://prettier.io/docs/en/options.html
module.exports = {
  printWidth: 100, //单行长度
  tabWidth: 2, //缩进长度
  useTabs: false, //使用空格代替tab缩进
  semi: false, //句末分号
  singleQuote: true, //js中使用单引号
  jsxSingleQuote: false, // jsx中使用双引号
  quoteProps: 'as-needed', //仅在必需时为对象的key添加引号
  trailingComma: 'all', //多行时尽可能打印尾随逗号
  bracketSpacing: true, //在对象前后添加空格-eg: { foo: bar }
  bracketSameLine: false, //多属性html标签的‘>’折行放置
  arrowParens: 'always', //单参数箭头函数参数周围使用圆括号-eg: (x) => x
  requirePragma: false, //无需顶部注释即可格式化
  insertPragma: false, //在已被preitter格式化的文件顶部加上标注
  proseWrap: 'preserve', //什么都不做,让散文保持原样
  htmlWhitespaceSensitivity: 'ignore', //对HTML全局空白不敏感
  vueIndentScriptAndStyle: true, //不对vue中的script及style标签缩进
  endOfLine: 'lf', //结束行形式
  embeddedLanguageFormatting: 'auto', //对引用代码进行格式化
  singleAttributePerLine: false, //在 HTML、Vue 和 JSX 中强制每行使用单一属性
}

2.3创建.prettierignore忽略文件
/.git
/.vscode
/build
/dist/*
.local
/node_modules/**
**/*.svg
**/*.sh
/public/*
2.4配置脚本
 "scripts": {
    "lint": "eslint src",
    "fix": "eslint src --fix",
    "format": "prettier --write \"./**/*.{tsx?,jsx?,json,html,vue}\"",
 }

代码格式化 yarn format

三、配置stylelint

stylelint为css的lint工具。可格式化css代码,检查css语法错误与不合理的写法,指定css书写顺序等。

官网:stylelint.io/

我们的项目样式处理使用 xxx.module.css,安装以下依赖:

npm init stylelint
3.1 .stylelintrc.cjs配置文件

将生成的 .stylelintrc.json 修改为 .stylelintrc.cjs

// @see https://stylelint.bootcss.com/
module.exports = {
  "extends": [
    'stylelint-config-standard', // 配置stylelint拓展插件
    'stylelint-config-css-modules', // 调整stylelint规则以接受css 模块特定语法
    'stylelint-config-recess-order', // 配置stylelint css属性书写顺序插件
    'stylelint-config-prettier', // 配置stylelint和prettier兼容
  ],
  /**
   * null  => 关闭该规则
   * always => 必须
   */
  "rules": {
    "font-family-no-missing-generic-family-keyword": null,
    "font-family-name-quotes": null,
    "selector-class-pattern": null,
    "alpha-value-notation": null,
    "function-url-quotes": null,
    "color-function-notation": null,
  }
}
3.2安装依赖
yarn add -D stylelint-config-css-modules stylelint-config-recess-order stylelint-config-prettier typescript-plugin-css-modules
3.3创建.stylelintignore忽略文件
/node_modules/*
/dist/*
/html/*
/public/*
3.4运行脚本
 "scripts": {
    ...
    "lint": "eslint src",
    "fix": "eslint src --fix",
    "format": "prettier --write \"./**/*.{tsx?,jsx?,json,html,vue}\"",
    "fix:style": "npx stylelint \"**/*.css\" --fix",
  },
3.5创建src/custom.d.ts文件, 注意是项目的src文件夹下
declare module '*.css' {
  const css: { [key: string]: string }
  export default css
}

3.6配置typescript

在tsconfig.json的compilerOptions中添加插件配置项

{
  "compilerOptions": {
    ...
    "baseUrl": "./src",
    "plugins": [{ "name": "typescript-plugin-css-modules" }]
  },
  ...
}
3.7 vscode(可选)

如果使用 vscode 编辑器, 可以在根项目下创建.vscode/settings.json

{
  "typescript.tsdk":"node_modules/typescript/lib",
  "typescript.enablePromptUseWorkspaceTsdk": true
}

这样输入styles.的时候就会有提示代码

image.png

四、配置husky

在上面我们已经集成好了我们代码校验工具,但是需要每次手动的去执行命令才会格式化我们的代码。如果有人没有格式化就提交了远程仓库中,那这个规范就没什么用。所以我们需要强制让开发人员按照代码规范来提交。

要做到这件事情,就需要利用husky在代码提交之前触发git hook(git在客户端的钩子),然后执行 yarn format来自动的格式化我们的代码。

安装 husky

yarn add -D husky

执行

npx husky-init

会在根目录下生成个一个.husky目录,在这个目录下面会有一个pre-commit文件,这个文件里面的命令在我们执行commit的时候就会执行

可以尝试在.husky/pre-commit文件添加如下命令:

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

yarn fix
yarn format
git add .

这样每次git commit -m时都会先执行 yarn fix yarn format git add . 这三条命令

.husky/pre-commit文件在之后配置 lint-staged 时还要再次被修改! 在这里写是为了理解文件可以写一些什么代码, 方便理解.

当我们对代码进行commit操作的时候,就会执行命令,对代码进行格式化,然后再提交。

五、配置cz-customizable

yarn add -D cz-customizable

根目录创建.cz-config.js

module.exports = {
  types: [
    {
      value: '✨ feat',
      name: '✨ feat:     新功能',
    },
    {
      value: '🐛 fix',
      name: '🐛 fix:      修复bug',
    },
    {
      value: '🚀 chore',
      name: '🚀 chore:    构建/工程依赖/工具',
    },
    {
      value: '💄 style',
      name: '💄 style:    代码的样式美化',
    },
    {
      value: '♻️ refactor',
      name: '♻️  refactor: 重构',
    },
    {
      value: '⚡️ perf',
      name: '⚡️ perf:     性能优化',
    },
    {
      value: '✅ test',
      name: '✅ test:     测试',
    },
    {
      value: '🎉 init',
      name: '🎉 init:     初始化',
    },
    {
      value: '📝 docs',
      name: '📝 docs:    文档变更',
    },
    {
      value: '⏪️ revert',
      name: '⏪️ revert:   回退',
    },
    {
      value: '🔧 config',
      name: '🔧 config:   修改配置',
    },
    {
      value: '📦️ build',
      name: '📦️ build:    打包',
    },
    {
      value: '👷 ci',
      name: '👷 ci:       CI related changes',
    },
  ],
  messages: {
    type: '请选择提交类型(必填)',
    customScope: '请输入文件修改范围(可选)',
    subject: '请简要描述提交(必填)',
    body: '请输入详细描述(可选)',
    breaking: '列出任何BREAKING CHANGES(可选)',
    footer: '请输入要关闭的issue(可选)',
    confirmCommit: '确定提交此说明吗?',
  },
  allowCustomScopes: true,
  allowBreakingChanges: [':sparkles: feat', ':bug: fix'],
  subjectLimit: 72,
}

配置脚本

  "scripts": {
    ...
    "lint": "eslint src",
    "fix": "eslint src --fix",
    "format": "prettier --write \"./**/*.{tsx?,jsx?,json,html,vue}\"",
    "fix:style": "npx stylelint \"**/*.css\" --fix",
    "prepare": "husky install",
    "commit": "cz-customizable"
  },

以后使用 yarn commit 代替 git commit -m

但这样做还是会有人使用 git commit,所以要配置 commitlint

六、配置commitlint

git log 日志规范

6.1安装规范包

带gitmoji图标( ✨🎨🔥🐛👽️👥🤡🙈🧐🌱 ... )

yarn add -D @commitlint/cli  commitlint-config-cz  commitlint-config-git-commit-emoji
6.2创建commitlint.config.cjs(注意是cjs),然后添加下面的代码:
module.exports = {
  extends: ['git-commit-emoji', 'cz']
}
6.3在 package.json中配置scripts命令
# 在scrips中添加下面的代码
  "scripts": {
    ...
    "lint": "eslint src",
    "fix": "eslint src --fix",
    "format": "prettier --write \"./**/*.{tsx?,jsx?,json,html,vue}\"",
    "fix:style": "npx stylelint \"**/*.css\" --fix",
    "prepare": "husky install",
    "commit": "cz-customizable",
    "commitlint": "commitlint --config commitlint.config.cjs -e -V"
  },
6.4配置husky
npx husky add .husky/commit-msg 

在生成的commit-msg文件中添加下面的命令

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

yarn commitlint

这样git commit -m就提交不了了,必须用yarn commit提交!

七、配置 lint-staged

yarn add lint-staged -D

package.json文件

  "scripts": {
    ...
    "lint": "eslint src",
    "fix": "eslint src --fix",
    "format": "prettier --write \"./**/*.{tsx?,jsx?,json,html,vue}\"",
    "fix:style": "npx stylelint \"**/*.css\" --fix",
    "prepare": "husky install",
    "commit": "cz-customizable",
    "commitlint": "commitlint --config commitlint.config.cjs -e -V",
    "lint-staged": "lint-staged"
  },
  "lint-staged": {
    "./src/*.{html,css,tsx?,jsx?,json,vue}": [
      "eslint src --fix",
      "npx stylelint \"**/*.css\" --fix",
      "prettier --write"
    ]
  },

.husky\pre-commit 文件内容如下:

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

yarn lint-staged

lint-staged 的作用是只校验 git add 中的文件

没有被 git add 的文件不校验

八、强制使用 yarn 安装依赖

npx only-allow yarn

package.json配置命令

"scripts": {
  ...
  "lint": "eslint src",
  "fix": "eslint src --fix",
  "format": "prettier --write \"./**/*.{tsx?,jsx?,json,html,vue}\"",
  "fix:style": "npx stylelint \"**/*.css\" --fix",
  "prepare": "husky install",
  "commit": "cz-customizable",
  "commitlint": "commitlint --config commitlint.config.cjs -e -V",
  "lint-staged": "lint-staged",
  "preinstall": "npx only-allow yarn"
},

九、代码上传前用 jest 测试

todo...

二、项目最终 package.json 配置

"scripts": {
  "start": "react-scripts start",
  "build": "react-scripts build",
  "test": "react-scripts test",
  "eject": "react-scripts eject",
  "lint": "eslint src",
  "fix": "eslint src --fix",
  "format": "prettier --write \"./**/*.{tsx?,jsx?,json,html,vue}\"",
  "fix:style": "npx stylelint \"**/*.css\" --fix",
  "prepare": "husky install",
  "commit": "cz-customizable",
  "commitlint": "commitlint --config commitlint.config.cjs -e -V",
  "lint-staged": "lint-staged",
  "preinstall": "npx only-allow yarn"
},
"lint-staged": {
  "./src/*.{html,css,tsx?,jsx?,json,vue}": [
    "eslint src --fix",
    "npx stylelint \"**/*.css\" --fix",
    "prettier --write"
  ]
},

三、react组件通信方式

组件通信方式很重要,不管是项目还是面试都是经常用到的知识点。

  • props: 可以实现父子组件、子父组件、甚至兄弟组件通信(状态提升)
  • context: 可以实现任意组件通信
  • 集中式状态管理等: Redux、Mobox、Zustand、Resso 等...
  • 消息订阅-发布: pubsub 等...