React 脚手架搭建过程记录

2023-05-18  本文已影响0人  peaktan

最近项目中要使用 React 来开发 web 应用,这里记录一下搭建 React web 脚手架的过程,方便后期自查。

一、CRA 创建官方脚手架

npx create-react-app my-app

create-react-app 脚手架中将 webpack + babel 封装成了一个叫做 react-scripts 的库,用来隐藏配置,开发人员可以快速上手。

但是如果要自定义 webpack 的配置,就必须使用 eject 将配置弹出,会导致我们关注到一些无关的配置,体验并不好,同时无法跟随 react-scripts 的官方更新,所以我们通常会借助 craco 来优化这个问题。

二、安装 craco 方便自定义 webpack 配置

craco 全称 Create React App Configuration Override,取首字母即组成了工具名称。

craco 是为了无 eject 、可配置式的去修改 CRA 默认提供的工程配置,这样既能享受 CRA 带来的便利和后续升级,也能自己去自定义打包配置完成项目需要,一举两得。

1、安装 @craco/craco
npm i @craco/craco -D
2、修改 package.json 中的 script 标签。

start/build/test 三个命令修改为 craco 方式:

"scripts": {
   -   "start": "react-scripts start",
   -   "build": "react-scripts build",
   -   "test": "react-scripts test",
   +   "start": "craco start",
   +   "build": "craco build",
   +   "test": "craco test",
}
3、在项目根目录中创建 craco.config.js

下面是支持了 路径@别名配置postcss 集成 的配置示例:

const path = require("path")
const resolve = pathUrl => path.join(__dirname, pathUrl)
const pxToViewport = require("postcss-px-to-viewport")
const vw = pxToViewport({
    viewportWidth: 375
})

const WebpackBar = require("webpackbar")

module.exports = {
    webpack: {
        alias: {
            "@": resolve("src/"),
            "@common": resolve("src/common")
        },
        plugins: [new WebpackBar({ profile: true })]
    },

    style: {
        postcss: {
            mode: "extends",
            loaderOptions: {
                postcssOptions: {
                    ident: "postcss",
                    plugins: [vw]
                }
            }
        }
    }
}

craco 的基础配置已经完成,craco.config.js 配置文件结构,可以在 craco 官方的文档中详细查询:Configuration Overview

关于 react-app-rewrited 的替代品 craco 及最佳实践 可参考

三、支持修改环境变量 cross-env

为了支持添加不同网络域名的环境变量,需要在 node 运行时注入一些自定义的环境变量。

由于不同平台注入环境变量有所差异,为了兼容 WindowsLinux 等不同平台,可以使用 cross-env 这个跨平台设置和使用环境变量的脚本。

1、安装 cross-env
npm install --save-dev cross-env
2、注入自定义变量
{
  "scripts": {
    "build": "cross-env REACT_APP_ENV=sit craco start"
  }
}
3、使用自定义变量
process.env.REACT_APP_ENV

四、支持 sass 样式编写

React 脚手架中已经有了 sass 的配置(并没有配置 less,如果想用 less,需要另外配置),因此只需要安装 sass 的依赖包,就可以直接使用 sass了:

1、安装 sass
npm i sass -D
2、css modules 解决样式污染问题

React 脚手架已集成 CSS Modules ,可直接使用

步骤:

import styles from './index.module.scss'
<div className={styles.css类名}></div>

css类名是 index.module.scss 中定义的类名。

3、css modules 最佳实践

component.tsx

import styles from './index.module.scss'
const 组件 = () => {
  return (
    {/* (1) 根节点使用 CSSModules 形式的类名( 根元素的类名: `root` )*/}
    <div className={styles.root}>
      {/* (2) 所有子节点,都使用普通的 CSS 类名*/}
        <h1 className="title">
        <span className="text">登录</span>  
        <span>登录</span>  
      </h1>
            <form className="login-form"></form>
    </div>
  )
}

index.module.scss

.root {
  display: 'block';
  position: 'absolute';
  // 此处,使用 global 包裹其他子节点的类名。此时,这些类名就不会被处理,在 JSX 中使用时,就可以用字符串形式的类名
  // 如果不加 :global ,所有类名就必须添加 styles.title 才可以
  :global {
    .title {
      .text {
      }
      span {
      }
    }
    .login-form { ... }
  }
}

参考:https://juejin.cn/post/7031556713329197093

五、eslint、prettier 配置

由于我们项目使用的 TS,所以我们需要配置的环境为:react + ts + hooks 的工程配置。

1、安装 eslint 相关依赖

通过 CRA 脚手架创建的 TypeScript 项目,会默认安装一个 eslint-config-react-app 的 eslint 配置库,这个库自带了如下依赖:

基本帮我们把 React 需要的 eslint 相关依赖都预先安装好了,我们只需要再安装 eslint 支持库就可以:

npm install -save-dev eslint

这里要注意你项目中 eslint-config-react-app 需要依赖的 eslint 版本要求,然后安装指定的版本。

2、安装 prettier 相关依赖

我们可以借助 ESlint 来提高我们编码的质量,但是却无法保证统一代码风格。一个统一的代码风格对于团队来说是很有价值的,所以为了达到目的,我们可以选择使用 Prettier 在保存和提交代码的时候,将代码修改成统一的风格。这样做同时也降低了 Code Review 的成本。它不会代替 ESlint,所以需要和 ESlint 搭配使用。

prettier 主要需要安装以下三个依赖:

npm install --save-dev prettier eslint-config-prettier eslint-plugin-prettier
3、配置 eslint

在项目根目录创建 .eslintrc.js 配置文件:

module.exports = {
    env: {
        node: true,
        browser: true,
        es2021: true,
        jest: true
    },
    extends: [ // 继承已有规则,继承按顺序进行覆盖
        "eslint:recommended", // eslint 推荐的规则
        "plugin:react/recommended", // @eslint-plugin-react 的推荐规则
        "plugin:@typescript-eslint/recommended", // @typescript-eslint/eslint-plugin的推荐规则
        "plugin:prettier/recommended" // eslint-plugin-prettier 的推荐规则
    ],
    parser: "@typescript-eslint/parser", // 指定解析器
    parserOptions: {
        ecmaVersion: "latest", // 允许解析那个版本的特性
        sourceType: "module", // 允许使用 import
        ecmafeatures: {
            jsx: true // 允许对JSX进行解析
        }
    },
    plugins: ["react", "react-hooks", "@typescript-eslint", "prettier"],
    settings: {
        react: {
            version: "detect" // 告诉eslint-plugin-react 自动检测 React的版本
        }
    },
    // 自定义规则
    rules: {
        // ///////////////////////// error
        // 禁止不必要的分号
        // "no-extra-semi": 1,
        // 禁止出现令人困惑的多行表达式
        "no-unexpected-multiline": 2,
        // 禁止在return、throw、continue 和 break语句之后出现不可达代码
        /*
       function foo() {
       return true;
       console.log("done");//错误
       }
       */
        "no-unreachable": 2,
        // 强制 typeof 表达式与有效的字符串进行比较
        // typeof foo === "undefimed" 错误
        "valid-typeof": 2,
        // 启用严格模式
        strict: 2,
        // 不允许改变用const声明的变量
        "no-const-assign": 2,
        // 禁止对全局变量赋值
        "no-global-assign": 2,
        // 禁止重复导入模块
        "no-duplicate-imports": 2,

        // ///////////////////////// warning
        // 对于不符合 prettier 规则,eslint只提示警告
        "prettier/prettier": 1,
        // 不允许使用var
        "no-var": 1,
        // 禁止定义没有被使用的变量
        "no-unused-vars": 0,
        "@typescript-eslint/no-unused-vars": 0,
        // 要求或禁止使用分号而不是 ASI(这个才是控制行尾部分号的,)
        semi: [1, "never"],
        // 禁止分号之前出现空格
        "semi-spacing": [1, { before: false, after: true }],
        // 禁止在字符串和注释之外不规则的空白
        "no-irregular-whitespace": 1,
        // 强制使用一致的换行风格
        // "linebreak-style": [1, "unix"],
        // 使用双引号 允许es6的``
        quotes: [1, "double", { allowTemplateLiterals: true }],
        // 强制在代码块中开括号前和闭括号后有空格
        "block-spacing": [1, "always"],
        // 在代码块之前强制使用空格
        "space-before-blocks": 1,
        // 要求操作符周围有空格
        "space-infix-ops": 1,
        // 一元操作符必须要有空格
        "space-unary-ops": 1,
        // 强制在注释中 // 或 /* 使用一致的空格
        "spaced-comment": [1, "always", { exceptions: ["-"] }],
        // 强制关键字周围空格的一致性
        "keyword-spacing": [1, { before: true, after: true }],
        // 强制在箭头函数中 "xxx() => {}"
        "arrow-spacing": [1, { before: true, after: true }],
        // 在冒号后要加上空格
        "key-spacing": [1, { beforeColon: false }],
        // 如果一个变量不会被重新赋值,最好使用const进行声明。
        "prefer-const": 1,
        // 强制类型后面要有一个","
        // "flowtype/delimiter-dangle": [1, "only-multiline"],
        // 在 : 后强制加空格
        // "flowtype/space-after-type-colon": [1, "always"],
        // 在 | & 符号中,强制加空格
        // "flowtype/union-intersection-spacing": [1, "always"],

        // ///////////////////////// off
        // 尽可能使用`===`
        eqeqeq: 0,
        // 禁止不必要的布尔转换
        "no-extra-boolean-cast": 0,
        "no-useless-computed-key": 0,
        // 禁止不必要的括号 (a * b) + c;
        "no-extra-parens": 0,
        // 允许使用行内样式
        "react-native/no-inline-styles": 0,
        // 禁止空格和 tab 的混合缩进
        "no-mixed-spaces-and-tabs": 0,
        "react/jsx-filename-extension": 0,

        // react配置
        // 强制组件方法顺序
        "react/sort-comp": [2],
        // 结束标签,组件省略闭合标签,html不省略闭合标签
        "react/self-closing-comp": [
            2,
            {
                component: true,
                html: false
            }
        ],
        "@typescript-eslint/ban-ts-comment": "off",

        "@typescript-eslint/no-var-requires": 0,
        "@typescript-eslint/ban-types": [
            "error",
            {
                extendDefaults: true,
                types: {
                    "{}": false
                }
            }
        ],

        // 检查 Hook 的规则,不允许在if for里面使用
        "react-hooks/rules-of-hooks": [2],
        // 检查 effect 的依赖
        "react-hooks/exhaustive-deps": [2],
        // suppress errors for missing 'import React' in files
        "react/react-in-jsx-scope": "off",
        "@typescript-eslint/no-non-null-assertion": "off",
        "no-empty-function": "off",
        "@typescript-eslint/no-explicit-any": "off",
        "@typescript-eslint/no-empty-function": "off",
        "@angular-eslint/no-empty-lifecycle-method": "off"
    }
}
4、配置 prettier

根目录创建 .prettierrc.js 配置文件:

module.exports = {
    // 字符串是否使用单引号,默认为false,使用双引号
    singleQuote: false,
    // 在jsx中把'>' 是否单独放一行
    jsxBracketSameLine: true,
    // 根据显示样式决定 html 要不要折行
    htmlWhitespaceSensitivity: "css",
    // 换行符使用 crlf/lf/auto
    endOfLine: "auto",
    // 一个tab代表几个空格数,默认为80
    tabWidth: 4,
    // 是否使用tab进行缩进,默认为false,表示用空格进行缩减
    useTabs: false,
    // 换行字符串阈值
    printWidth: 80,
    // 句末加分号,默认为true
    semi: false,
    // 是否使用尾逗号,有三个可选值"<none|es5|all>"
    trailingComma: "none",
    // 对象大括号直接是否有空格,默认为true,效果:{ foo: bar }
    bracketSpacing: true,
    // (x) => {} 是否要有小括号
    arrowParens: "avoid",
    // 是否要注释来决定是否格式化代码
    requirePragma: false,
    // 是否要换行
    proseWrap: "preserve",
  };
5、配置 VS Code 编辑器 (如果需要保存时自动格式化可以配置)
ESlint.png Prettier.png
{
    "editor.defaultFormatter": "esbenp.prettier-vscode", // 默认的格式化插件prettier
    "editor.formatOnType": true, // 输完一行后自动格式化
    "editor.formatOnSave": true, // 保存时格式化
    "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true // 保存时使用 eslint fix 命令进行格式化对应文件
    },
    "eslint.run": "onSave",
    "eslint.validate": [
        "javascript",
        "javascriptreact",
        "typescriptreact",
        "html",
        "vue"
    ]
}

这样当我们在保存文件的时候,就会自动优化文件格式了。

如果团队合作,VSCode 配置文件可以上传到 git 仓库,这样大家都能共享一份配置,有助于代码格式的统一。

上一篇下一篇

猜你喜欢

热点阅读