# mofish-react-template **Repository Path**: mcfish/mofish-react-template ## Basic Information - **Project Name**: mofish-react-template - **Description**: 基于cra生成typescript模板,使用craco管理配置,统一代码风格、样式风格、代码提交等前端规范 - **Primary Language**: TypeScript - **License**: Not specified - **Default Branch**: dev-1.0 - **Homepage**: https://gitee.com/mcfish/mofish-react-template - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-05-23 - **Last Updated**: 2022-08-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### 创建react项目 ```js npx create-react-app my-app --template typescript ``` ### [Craco](https://www.npmjs.com/package/@craco/craco) #### 使用craco来重写cra配置 1. 安装 ```js npm i @craco/craco - D ``` 2. 修改package.json文件 ```js "scripts": { "start": "craco start", "build": "craco build", "test": "craco test", "eject": "craco eject" }, ``` 3. 新增craco.config.ts 文件 (**项目根目录下新建**) ```js const config = () => ({ // 编写修改webpack配置,可以参考craco,和webpack的语法 }) export default config ``` 或者新增craco.config.js文件 ```js module.exports = () => ({ // 编写修改webpack配置,可以参考craco,和webpack的语法 }) ``` #### 支持less和装饰器语法 1. 安装 ```js npm i craco-less -D npm i @babel/plugin-proposal-decorators -D ``` 2. 修改craco.config.js 文件 ```js // 使用less插件 const CracoLessPlugin = require('craco-less'); const config = () => ({ // 编写修改webpack配置,可以参考craco,和webpack的语法 plugins: [ { plugin: CracoLessPlugin, options: { lessLoaderOptions: { lessOptions: { // 修改主题色 modifyVars: { '@primary-color': '#4578FA' }, javascriptEnabled: true, }, }, }, }, ], babel: { // 支持装饰器模式语法 plugins: [ ["@babel/plugin-proposal-decorators", { legacy: true }] ] } }) export default config ``` #### [设置别名](https://juejin.cn/post/6990896895077908487) **问题背景**:使用cra创建的项目每一次重启都会重置tsconfig.json, 导致在tsconfig.json设置的别名失效。 1. 安装 ```js npm i craco-alias -D ``` 2. 新建tsconfig.path.json (**项目根目录下新建**) ```js { "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["src/*"], "Components": ["src/components"] } } } ``` 3. craco.config.ts **CracoAlias** 配置为 ```js const aliasPlugin = require('craco-alias') const config = () => ({ ... plugins:[ { plugin: aliasPlugin, options: { source: 'tsconfig', baseUrl: '.', tsConfigPath: './tsconfig.path.json', }, }, ] ... }) export default config ``` 4. tsconfig.json 文件插入 ```js "extends": "./tsconfig.path.json", ``` #### 规范代码风格 [ESLint 与 Prettier 配合使用](https://juejin.cn/post/6924568874700505102) 两者配合使用,eslint进行代码质量检验,prettier进行自动格式化代码 1. 安装 ```js npm i -D eslint prettier eslint-config-prettier eslint-plugin-prettier ``` 2. 项目根目录添加 .eslintrc.js 和 .prettierrc ```JS // .eslintrc.js { "extends": ['plugin:prettier/recommended'] // 覆盖eslint格式配置,写在最后 } ``` ```JS // .prettierrc { "printWidth": 100, // 指定代码长度,超出换行 "tabWidth": 2, // tab 键的宽度 "useTabs": false, // 不使用tab "semi": false, // 结尾加上分号 "singleQuote": true, // 使用单引号 "quoteProps": "as-needed", // 要求对象字面量属性是否使用引号包裹,(‘as-needed’: 没有特殊要求,禁止使用,'consistent': 保持一致 , preserve: 不限制,想用就用) "jsxSingleQuote": false, // jsx 语法中使用单引号 "trailingComma": "es5", // 确保对象的最后一个属性后有逗号 "bracketSpacing": true, // 大括号有空格 { name: 'rose' } "jsxBracketSameLine": false, // 在多行JSX元素的最后一行追加 > "arrowParens": "always", // 箭头函数,单个参数添加括号 "requirePragma": false, // 是否严格按照文件顶部的特殊注释格式化代码 "insertPragma": false, // 是否在格式化的文件顶部插入Pragma标记,以表明该文件被prettier格式化过了 "proseWrap": "preserve", // 按照文件原样折行 "htmlWhitespaceSensitivity": "ignore", // html文件的空格敏感度,控制空格是否影响布局 "endOfLine": "auto" // 结尾是 \n \r \n\r auto } ``` 3. 添加eslint自定义规则(和prettier不冲突) 1. 安装自定义解析器 ```js npm i -D babel-eslint @typescript-eslint/parser ``` 2. 配置 ```js module.exports = { settings: { // 在eslintrc.js中指定react版本 react: { version: 'detect' } }, plugins: ['react'], // 配置插件 parser: '@typescript-eslint/parser', // 指定自定义解析器为ts-eslint extends: ['plugin:prettier/recommended'], // 继承 扩展配置文件 parserOptions: { parser: 'babel-eslint', // 指定解析器选项 ecmaVersion: 6, sourceType: 'module', // 默认script,可选module ecmaFeatures: { // 其他语言特性 experimentalObjectRestSpread: true, // ...rest参数和扩展扩算符 jsx: true, modules: true, }, }, env: { // 指定环境 es6: true, node: true, browser: true, }, // 布尔值false和字符串值"readable"等价于"readonly" // 布尔值true和字符串值"writeable"等价于"writable" globals: { // 指定全局变量 React: true, document: false, navigator: false, window: false, DEV: true, TEST: true, PRE: true, PRO: true, }, rules: { /** * @description 规则 ID 可以设置的值 * “off” 或 0 - 关闭规则 * “warn” 或 1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出) * “error” 或 2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出) */ /** * Possible Errors * 这些规则与 JavaScript 代码中可能的错误或逻辑错误有关 * https://cn.eslint.org/docs/rules/#possible-errors */ 'no-cond-assign': 2, // 条件不能有赋值 'no-control-regex': 2, // reg中不能有控制符号 'no-console': process.env.NODE_ENV === 'production' ? 1 : 0, // node环境prod禁用 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, // node环境prod禁用 'no-dupe-args': 2, // 参数不能重复 'no-dupe-keys': 2, // 对象key不能重复 'no-duplicate-case': 2, // switch不能有重复case 'no-empty-character-class': 2, // reg中不能有空字符串 'no-ex-assign': 2, // 不能复制catch中的error 'no-extra-boolean-cast': 2, // 禁止多余的Boolean转换 'no-extra-parens': [2, 'functions'], // 函数中禁止多余的括号 'no-func-assign': 2, // 禁止赋值函数 'no-inner-declarations': [2, 'functions'], // 禁止在条件中声明function 'no-invalid-regexp': 2, // 禁止无用的reg 'no-irregular-whitespace': 2, // 禁止不规则空格 'no-unsafe-negation': 2, // !(key in object)->yes, !key in object->no 'no-obj-calls': 2, // 禁止calling全局对象属性,如Math/JSON 'no-regex-spaces': 2, // 禁止reg出现多个空格 'no-sparse-arrays': 2, // array不能用空元素 'no-unexpected-multiline': 2, // 禁止有疑义的多行表达式 'no-unreachable': 2, // return/throw等之后不应有表达式 'no-unsafe-finally': 2, // 禁止不安全的finally 'use-isnan': 2, // 使用isNaN 'valid-typeof': 2, // typeof的字符串必须正确 /** * Best Practices * 这些规则是关于最佳实践的,帮助你避免一些问题 * https://cn.eslint.org/docs/rules/#best-practices */ 'accessor-pairs': 2, // getter/setter成对出现 'dot-location': [2, 'property'], // .的位置可以在换行 eqeqeq: [2, 'allow-null'], // 必须===, null除外 'no-caller': 2, // 禁止caller/callee 'no-empty-pattern': 2, // 解构不能有空解构模式 'no-eval': 2, // 不能用eval 'no-extend-native': 2, // 不能扩展Object原型 'no-extra-bind': 2, // bind的函数体中要有明确的this 'no-fallthrough': 2, // switch需要break 'no-floating-decimal': 2, // float中0不能省略 'no-implied-eval': 2, // 禁止隐性eval 'no-iterator': 2, // 禁止使用__iterator__属性 'no-labels': [2, { allowLoop: false, allowSwitch: false }], // 禁止label表达式 'no-lone-blocks': 2, // 禁止无用的{} 'no-multi-spaces': 1, // 禁止多空格 'no-multi-str': 2, // 禁止多行的string 'no-global-assign': 2, // 禁止赋值原生对象(window/Object...) 'no-new-wrappers': 2, // String/Number等不能用new 'no-octal': 2, // 禁止八进制文字 'no-octal-escape': 2, // 禁止八进制转义 'no-proto': 2, // 禁止使用__proto__ 'no-redeclare': 2, // 禁止重新复制var 'no-return-assign': [2, 'except-parens'], // 禁止return中赋值 'no-self-assign': 2, // 禁止自身赋值 'no-self-compare': 2, // 禁止自身比较, 如果NaN->Number.isNaN 'no-sequences': 2, // 禁止,操作符 'no-throw-literal': 2, // 禁止直接throw内容,必须是Error() 'no-unmodified-loop-condition': 2, // 循环中的变量要在循环中修改 'no-useless-call': 2, // 禁止无用的call 'no-with': 2, // 禁用with 'wrap-iife': [2, 'any'], // 立即调用的function必须有括号 yoda: [2, 'never'], // 条件中变量在前 'no-useless-escape': 0, // 不检查escape 'no-new-func': 0, // 禁止对 Function 对象使用 new 操作符 'no-param-reassign': 0, // 禁止对 function 的参数进行重新赋值 'consistent-return': 0, // 要求 return 语句要么总是指定返回的值,要么不指定 'class-methods-use-this': 0, // 强制类方法使用 this 'array-callback-return': 0, // 数值循环显示return 'no-unused-expressions': 0, // func && func() 'no-loop-func': 0, // 禁止在loop内写循环函数 /** * Variables * 这些规则与变量声明有关 * https://cn.eslint.org/docs/rules/#variables */ 'no-delete-var': 2, // 不能delete变量,可以用在对象 'no-label-var': 2, // 禁止label var 'no-shadow-restricted-names': 2, // 禁止跟踪严格模式下部分关键词 'no-restricted-globals': 0, // 禁用特定的全局变量 // 'no-undef': 2, // 禁止使用未赋值变量 'no-undef-init': 2, // 变量不能初始化为undefined 'no-unused-vars': [0, { vars: 'all', args: 'none' }], // 禁止不使用的变量,参数可以 'no-use-before-define': [2, { functions: false, classes: true, variables: true }], // 未定义不能使用 'no-shadow': 0, // 禁止变量声明与外层作用域的变量同名 /** * ECMAScript 6 * 这些规则只与 ES6 有关, 即通常所说的 ES2015 * https://cn.eslint.org/docs/rules/#ecmascript-6 */ 'arrow-spacing': [1, { before: true, after: true }], // 箭头函数前后有空格 'constructor-super': 1, // super()在必须构造函数内 curly: [2, 'multi-line'], // if/while等函数可以多行不带{} 'generator-star-spacing': [2, { before: true, after: true }], // generator函数前后有空格 'no-class-assign': 2, // 禁止赋值class 'no-const-assign': 2, // 禁止赋值常量(const) 'no-dupe-class-members': 2, // class中方法不能有重复 'no-new-symbol': 2, // new Symbol(xxx)->no 'no-this-before-super': 2, // super()前不能用this 'no-useless-computed-key': 2, // 禁止无用的计算属性 'no-useless-constructor': 2, // 禁止无用的constructor 'template-curly-spacing': [2, 'never'], // 模版字符串中变量无空格 'yield-star-spacing': [2, 'both'], // yield的*前后有空格 'prefer-const': 0, // 能用const场景用const 'arrow-parens': [2, 'as-needed'], // 要求箭头函数的参数使用圆括号 'arrow-body-style': 0, // 要求箭头函数体使用大括号 'no-confusing-arrow': [2, { allowParens: true }], // 禁止在可能与比较操作符相混淆的地方使用箭头函数 'object-shorthand': [2, 'properties', { avoidQuotes: true }], // 要求或禁止对象字面量中方法和属性使用简写语法 'prefer-destructuring': 1, // 解构 /** * Node.js and CommonJS * 这些规则是关于Node.js 或 在浏览器中使用CommonJS 的 * https://cn.eslint.org/docs/rules/#nodejs-and-commonjs */ 'handle-callback-err': [2, '^(err|error)$'], // 有err/error必须处理异常 'no-new-require': 2, // new require(xxx)->no 'no-path-concat': 2, // __dirname和__filename禁止string拼接 'global-require': 0, // 要求 require() 出现在顶层模块作用域中 /** * eslint-plugin-react * https://github.com/yannickcr/eslint-plugin-react/tree/master/docs/rules */ 'react/jsx-uses-react': 2, 'react/prefer-es6-class': 1, // 禁止使用ES5语法创建React组件 'react/prefer-stateless-function': 1, // 组件没有状态或是没有引用refs,推荐使用无状态组件(函数声明)而不是类 'react/jsx-pascal-case': 2, // 组件名称使用帕斯卡命名法 'react/jsx-closing-bracket-location': 1, // 自关闭的jsx标签代码对齐格式 'react/jsx-tag-spacing': 1, // 自关闭的标签前加一个空格 'react/jsx-curly-brace-presence': 1, // 不需要多余的 去掉props和children多余的花括号,如title={"标题"}和