灏天阁

从0到1搭建一个 React 项目开发模板

· Yin灏

👨🏻‍💻 GitHub

项目 repo: react-enterprise-template

🚀 技术栈

react TypeScriptwebpack axios mobx react-router-domhttps://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3ad153e52d71455ab5dc58171224cd43~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp

React v18
react-dom v18
TypeScript v4
webpack v5
axios v1
mobx v6
mobx-react-lite v3
react-router-dom v6

📱 说明

  • 📦 开箱即用,无需配置
  • 📝 全面注释说明,学习低成本
  • 🚀 启动编译迅速
  • 🌱 极易定制, 拓展容易

🎄 更新日志

① 样式处理 ✅ config: 🔧 新增样式文件 (css/less/sass/postCss) 处理

② 代码规范 ✅ config: 🔧 新增 Prettier/ESlint/StyleLint/EditorConfig 代码规范

③ 路由管理 ✅ config: 🔧 新增路由管理 react-router-dom v6

④ 网络请求 ✅ feat: ✨ 新增网络请求 Axios v1

⑤ 状态管理 ✅ feat: ✨ 新增状态管理 Mobx v6

⑥ React Hook 规则 ✅ feat: ✨ 新增 react hooks 规则检查

⑦ 封装全局 SVG 组件 ✅ feat: ✨ 封装全局 SVG 组件

📂 目录结构

下文中文件创建路径以此为参考
    ├── .vscode
    │   └──setting.json                 # 先于vscode全局的settings.json配置
    ├── doc                             # 开发文档记录
    ├── webpack                         # 打包编译
    │   └──config                       # webpack配置
    │       ├── webpack.common.js       # 基础配置
    │       ├── webpack.dev.js          # 开发环境配置
    │       └──webpack.prod.js          # 生产环境配置
    ├── pubilc
    │   ├──favicon.ico                  # HTML图标
    │   └──index.html                   # HTML入口模板
    ├── src
    |   ├── api                         # 接口配置
    |   ├── assets                      # 静态资源
    │   ├── components                  # 项目通用通用组件
    │   ├── http                        # 请求统一封装
    │   ├── httpinterface               # ts类型定义
    │   ├── constData                   # 系统内的常量列表
    │   ├── router                      # 统一路由入口
    │   ├── store                       # 数据共享
    │   ├── styles                      # 全局样式
    │   ├── utils                       # 工具库
    │   ├── view                        # 页面
    │   ├── App.tsx                     # 主界面
    │   └──index.tsx                    # 入口文件
    ├── .babelrc.js                     # babel配置
    ├── .editorconfig                   # 跨编辑器维护一致编码风格
    ├── .env.json                       # 环境变量配置
    ├── .eslin tignore                  # ESLint忽略检测文件
    ├── .eslintrc.js                    # ESLint配置
    ├── .gitignore                      # git提交忽略文件
    ├── .npmrc
    ├── .prettierignore                 # prettierc忽略文件
    ├── .prettierrc                     # prettierc配置
    ├── .stylelintrc.js                 # 代码风格配置
    ├── LICENSE                         # 开源协议
    ├── package-lock.json               # npm安装包锁定管理
    ├── package.json                    # 依赖包管理
    ├── README.md                       # 项目说明
    ├── tsconfig.json                   # ts配置文件
    └── yarn.lock                       # yarn安装包锁定管理

① 项目初始化

1. package.json

在前端开发中,package.json 文件通常用于存储和管理前端项目的依赖关系。用于描述项目的基本信息,如包名、版本号、依赖关系等。通过 package.json 文件,开发者可以轻松地管理项目的依赖关系、版本号、历史记录等,并在项目中进行版本控制和协作。package.json 文件包含了以下重要的字段:

name:项目的名称,通常是一个唯一的字符串,可以用于发布到 npm 或者其他包管理器中。
version:项目的版本号,遵循 Semantic Versioning 规范。
description:项目的简介和描述。
main:项目的主入口文件,通常是一个 JavaScript 文件。
scripts:包含一组命令行脚本,用于自动化构建、测试、部署等任务。例如:"start": "node index.js" 表示通过运行 npm start 命令启动项目。
dependencies:列出项目所依赖的包和版本信息,这些包会在安装时自动下载到本地环境中。
devDependencies:列出项目开发过程中所依赖的包和版本信息,这些包只在开发时使用,不会在生产环境中使用。
peerDependencies:列出项目运行时所依赖的包和版本信息,这些包需要在项目的上级依赖中进行声明和安装。
engines:指定项目所需的 Node.js 和 npm 版本范围。
repository:指定项目的代码仓库地址。
keywords:关键字数组,用于描述项目的主题和类型。
author:作者信息。
license:项目的许可证类型。

根目录运行以下命令,生成 package.json。

yarn init -y

2. README.md

readme.md 用于描述文档内容。

<h1 align="center">react 模板</h1>
## 👨🏻‍💻 项目说明

3. .npmrc

.npmrc 文件是 npm 的配置文件之一,用于配置 npm 在执行安装和发布等操作时的行为和参数。在前端项目中,我们通常使用 npm 或 Yarn 管理依赖和构建脚本,.npmrc 文件则是这些工具的核心配置文件之一。.npmrc 文件支持以下类型的配置项:

  • registry:指定 npm 的镜像源地址,例如 registry=registry.npm.taobao.org
  • cache:指定 npm 的缓存目录,例如 cache=/path/to/cache。
  • proxy:指定 npm 的网络代理设置,例如 proxy=my.proxy.com:8080
  • https-proxy:指定 npm 的 HTTPS 网络代理设置,例如 https-proxy=my.proxy.com:8080
  • strict-ssl:指定是否开启 npm 的 SSL 证书校验,例如 strict-ssl=false。
  • loglevel:指定 npm 的日志输出级别,例如 loglevel=warn。
  • save-exact:指定是否在安装依赖时自动保存精确的版本号,例如 save-exact=true。
  • progress:指定 npm 的进度条输出设置,例如 progress=false。
  • access:指定包的访问权限,例如 access=public 或 access=restricted。

本项目将 npm 源设置为淘宝镜像源,提高安装速度。

npm config set registry https://registry.npm.taobao.org

.npmrc 文件中添加以下内容

registry=https://registry.npm.taobao.org/

4. .gitignore

.gitignore 用于指定 Git 忽略的文件或目录,这些文件或目录不会被 Git 跟踪或提交。可以帮助你减少 Git 操作时的文件提交量,减小仓库的体积和维护成本,提高 Git 仓库的性能和稳定性。

完整内容点击查看 .gitignore

② Webpack 配置

18586afe0401616d302ff6b1ae1cecd0.png

官方文档webapck

Webpack 是一个模块打包工具,可以将多个模块打包成一个或多个文件,以便在浏览器中使用。Webpack 可以处理各种类型的文件,包括 JavaScript、CSS、图片等,并可以处理模块之间的依赖关系。以下是 Webpack 的一些说明:

1. 安装 webpack

yarn add webpack webpack-cli webpack-dev-server@3.11.2 webpack-merge -D

2. 安装 webpack 相关插件

yarn add html-webpack-plugin -D                 # 简化 HTML 文件创建以服务捆绑包的插件, 将js文件自动引进 html 文件中
yarn add chalk@4.1.2 -D                         # 终端字符串样式个性化自定义
yarn add detect-port-alt -D                     # 端口检测
yarn add ip -D                                  # 获取ip地址
yarn add copy-webpack-plugin -D                 # 将已存在的单个文件或整个目录复制到生成目录
yarn add css-minimizer-webpack-plugin -D        # 这个插件优化和压缩css
yarn add mini-css-extract-plugin -D             # 抽离css文件, 将css取到单独的文件中,为每个包含css的js件创建一个css文件。
yarn add fork-ts-checker-webpack-plugin -D      # 启动本地服务/打包错误提示, 单独的进程上运行 TypeScript 类型检查器。
yarn add error-overlay-webpack-plugin -D        # 这个插件将在你的应用程序中定位显示出错信息
yarn add terser-webpack-plugin -D               # 这个插件使用 terser 压缩 JavaScript
yarn add webpack-bundle-analyzer -D             # 使用交互式可缩放树形地图可视化 webpack 输出文件的大小
yarn add compression-webpack-plugin -D          # 静态资源压缩, 使用Content-Encoding为它们提供服务
yarn add webpackbar -D                          # 优雅的 Webpack 进度条和分析器
yarn add postcss-flexbugs-fixes -D              # 用于修复一些和 flex 布局相关的 bug
yarn add babel-loader -D

3. 安装样式文件处理

yarn add style-loader -D        # 将结果以style标签的方式插入DOM树中。style-loader将css-loader打包好的 CSS 代码以<style>标签的形式插入到 HTML 文件中
yarn add css-loader -D          # 主要是解析css文件中的@import和url语句,处理css-modules,并将结果作为一个js模块返回
yarn add less less-loader -D    # less预处理器处理
yarn add postcss-loader -D      # 进一步处理css文件,比如添加浏览器前缀,压缩 CSS 等
yarn add postcss-preset-env -D  # 最新的 CSS 语法转换为目标环境的浏览器能够理解的 CSS 语法,目的是使开发者不用考虑浏览器兼容问题。
yarn add autoprefixer  -D       # PostCSS 处理浏览器兼容问题

4. 添加 webpack 配置文件

根目录创建 webpack 文件,添加 webpack.common.js 、webpack.dev.js 与 webpack.prod.js 三个配置文件。

webpack.common.js      # 基础配置
webpack.dev.js         # 开发环境配置
webpack.prod.js        # 生产环境配置

webpack.common.js 配置

const HtmlWebpackPlugin = require("html-webpack-plugin"); // 简化 HTML 文件创建以服务捆绑包的插件, 将js文件自动引进 html 文件中
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // 抽离css文件, 这个插件将CSS取到单独的文件中。它为每个包含CSS的JS文件创建一个CSS文件。它支持按需加载 CSS 和 SourceMaps。
const WebpackBar = require("webpackbar"); // 优雅的 Webpack 进度条和分析器
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); // 启动本地服务/打包错误提示
const CopyPlugin = require("copy-webpack-plugin"); // 将已存在的单个文件或整个目录复制到生成目录
const webpack = require("webpack");
const paths = require("../paths");
const { isDevelopment, isProduction } = require("../env");
const {
  imageInlineSizeLimit,
  imageBase64Path,
  shouldBase64FromFileEnd,
} = require("../conf");
const cssLoaders = (importLoaders) => [
  // 执行顺序从后到前 less-loader -> postcss-loader -> css-loader -> style-loader/MiniCssExtractPlugin.loader
  isDevelopment ? "style-loader" : MiniCssExtractPlugin.loader, // style-loader的作用就是将结果以style标签的方式插入DOM树中。style-loader将css-loader打包好的 CSS 代码以<style>标签的形式插入到 HTML 文件中
  {
    loader: "css-loader", // 主要是解析css文件中的@import和url语句,处理css-modules,并将结果作为一个js模块返回
    options: {
      modules: false,
      sourceMap: isDevelopment, // 开发环境开启
      importLoaders, // 执行顺序: 需要先被 less-loader postcss-loader (所以这里设置为 2)
    },
  },
  {
    loader: "postcss-loader", // 进一步处理css文件,比如添加浏览器前缀,压缩 CSS 等
    options: {
      postcssOptions: {
        plugins: [
          require("postcss-flexbugs-fixes"), // 用于修复一些和 flex 布局相关的 bug
          isProduction && [
            "postcss-preset-env", // 最新的 CSS 语法转换为目标环境的浏览器能够理解的 CSS 语法,目的是使开发者不用考虑浏览器兼容问题。
            {
              // 使用 autoprefixer 来自动添加浏览器头
              autoprefixer: {
                grid: true,
                flexbox: "no-2009",
              },
              stage: 3,
            },
          ],
        ].filter(Boolean),
      },
    },
  },
];
const config = {
  entry: {
    app: paths.appIndex,
  },
  cache: {
    // 缓存,cache.type 设置为 'filesystem' 是会开放更多的可配置项。
    // 收集在反序列化期间分配的未使用的内存,, 仅当 cache.type 设置为 'filesystem' 时生效。这需要将数据复制到更小的缓冲区中,并有性能成本。
    type: "filesystem",
    buildDependencies: {
      // 是一个针对构建的额外代码依赖的数组对象。webpack 将使用这些项和所有依赖项的哈希值来使文件系统缓存失效。
      config: [__filename],
    },
  },
  resolve: {
    extensions: [".tsx", ".ts", ".js", ".json"],
    alias: {
      "@": paths.appSrc,
      mock: paths.appMock,
      Components: paths.appSrcComponents,
      Utils: paths.appSrcUtils,
    },
  },
  module: {
    rules: [
      {
        test: /.(tsx?|js)$/,
        loader: "babel-loader", // 使用缓存
        options: { cacheDirectory: true },
        exclude: [/node_modules/, /(.|_)min.js$/],
      },
      {
        test: /.css$/,
        use: cssLoaders(1),
      },
      {
        test: /.less$/,
        use: [
          ...cssLoaders(2),
          {
            loader: "less-loader",
            options: {
              sourceMap: isDevelopment,
            },
          },
        ],
      },
      {
        test: [/.bmp$/, /.gif$/, /.jpe?g$/, /.png$/],
        type: "asset",
        parser: {
          // 当提供函数时,返回 true 值时告知 webpack 将模块作为一个 Base64 编码的字符串注入到包中,
          // 否则模块文件会被生成到输出的目标目录中。将base64的资源都放在一个目录下
          dataUrlCondition: (source, { filename }) => {
            // 1. 如果是base64下的目录,将文件打包成base64
            if (filename.includes(imageBase64Path)) {
              return true;
            }
            // 2. 如果开启了文件尾部扫描,则形如 xxx.base64.xxx会以Base64 编码的字符串注入到包中
            if (shouldBase64FromFileEnd && filename.includes(".base64")) {
              return true;
            }
            // 3. 对于小于imageInlineSizeLimit的文件,会以Base64 编码的字符串注入到包中
            if (source.length <= imageInlineSizeLimit) {
              return true;
            }
            return false;
          },
        },
      },
      {
        test: /.(eot|ttf|woff|woff2?)$/,
        exclude: paths.appSvg, // 不处理 svg类型文件
        type: "asset/resource",
      },
      {
        test: /.svg$/,
        loader: "svg-sprite-loader",
        include: paths.appSvg,
        options: {
          symbolId: "icon-[name]", // symbolId和use使用的名称对应 <use xlinkHref={"#icon-" + svgName} />
        },
      },
    ],
  },
  plugins: [
    new webpack.DefinePlugin(paths.appDefineVariable),
    new HtmlWebpackPlugin({
      template: paths.appHtml,
      cache: true,
      env: process.env.ENV || "",
    }),
    new CopyPlugin({
      patterns: [
        {
          context: paths.appPublic,
          from: "*",
          to: paths.appBuild,
          toType: "dir",
          globOptions: {
            dot: true,
            gitignore: true,
            ignore: ["**/index.html"],
          },
        },
      ],
    }),
    new WebpackBar({
      name: isDevelopment ? "RUNNING" : "BUNDLING",
      color: isDevelopment ? "#52c41a" : "#722ed1",
    }),
    new ForkTsCheckerWebpackPlugin({
      typescript: {
        configFile: paths.appTsConfig,
      },
    }),
  ],
};
module.exports = config;

webpack.dev.js 配置

const Webpack = require("webpack");
const ErrorOverlayPlugin = require("error-overlay-webpack-plugin"); // 这个插件将在你的应用程序中定位显示出错信息
const { merge } = require("webpack-merge"); // Webpack合并函数
const commonConfig = require("./webpack.common.js");
const paths = require("../paths");
const devConfig = {
  mode: "development",
  devtool: "cheap-module-source-map",
  target: "web",
  output: {
    path: paths.appBuild,
    publicPath: "/",
    filename: "js/[name].js",
  },
  devServer: {
    host: "0.0.0.0",
    compress: true, // 是否启用 gzip 压缩
    stats: "errors-only", // 终端仅打印 error
    clientLogLevel: "silent", // 日志等级
    open: true, // 打开默认浏览器
    hot: true, // 热更新
    noInfo: true,
    proxy: {
      ...require(paths.appProxySetup),
    },
    historyApiFallback: true, // 单页面配置appProxySetup
  },
  plugins: [new Webpack.HotModuleReplacementPlugin(), new ErrorOverlayPlugin()],
  optimization: {
    minimize: false, //关闭压缩
    minimizer: [],
    splitChunks: {
      chunks: "all",
      minSize: 0,
    },
  },
};
module.exports = merge(commonConfig, devConfig);

webpack.prod.js 配置

const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 抽离css文件, 这个插件将CSS取到单独的文件中。它为每个包含CSS的JS文件创建一个CSS文件。它支持按需加载 CSS 和 SourceMaps。
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); // 这个插件优化和压缩css
const TerserPlugin = require('terser-webpack-plugin'); // 这个插件使用 terser 来缩小/最小化你的 JavaScript
const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer'); // 使用交互式可缩放树形地图可视化 webpack 输出文件的大小
const CompressionPlugin = require('compression-webpack-plugin'); // 静态资源压缩, 使用Content-Encoding为它们提供服务
const {merge} = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
const paths = require('../paths');
const {shouldOpenAnalyzer, ANALYZER_HOST, ANALYZER_PORT} = require('../conf');
const prodConfig = {
    mode: 'production',
    target: 'browserslist',
    output: {
        path: paths.appBuild,
        filename: 'js/[name].[contenthash:8].js',
        assetModuleFilename: 'images/[name].[contenthash:8].[ext]',
        publicPath: process.env.PUBLIC_PATH,
        clean: true // 在生成文件之前清空 output 目录
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: 'css/[name].[contenthash:8].css',
            chunkFilename: 'css/[name].[contenthash:8].chunk.css',
            ignoreOrder: true
        }),
        new CompressionPlugin({
            test: /.js$|.html$|.\css/, // 匹配文件名
            threshold: 10240, // 对超过10k的数据压缩
            deleteOriginalAssets: false // 不删除源文件
        }),
        shouldOpenAnalyzer &&
            new BundleAnalyzerPlugin({
                analyzerMode: 'server',
                analyzerHost: ANALYZER_HOST,
                analyzerPort: ANALYZER_PORT
            })
    ].filter(Boolean),
    optimization: {
        // 允许你通过提供一个或多个定制过的 TerserPlugin 实例, 覆盖默认压缩工具(minimizer)
        minimizer: [
            new TerserPlugin({
                extractComments: false, // 删除注释
                terserOptions: {
                    compress: {pure_funcs: ['console.log', 'console.warn']}
                }
            }),
            new CssMinimizerPlugin()
        ],
        // 对于动态导入模块,请在 SplitChunksPlugin 页面中查看配置其行为的可用选项。
        splitChunks: {
            automaticNameDelimiter: '-', // 生成名称的分隔符
            chunks: 'all', // all-所有模块生效,async-抽取异步模块,initial:同步模块生效
            // minSize: 100000, //  todo, 后续还有性能问题再拆, 生成 chunk 的最小体积(以 bytes 为单位)。
            // maxSize: 40000, // todo, 后续还有性能问题再拆, 生成 chunk 的最大体积(以 bytes 为单位)。
            cacheGroups: {
                commons: {
                    test: /[/\]node_modules[/\]/,
                    name: 'vendors',
                    chunks: 'all'
                },
                // 抽离自定义工具库
                utilCommon: {
                    name: 'common',
                    minSize: 0, // 将引用模块分离成新代码文件的最小体积
                    minChunks: 2, // 表示将引用模块如不同文件引用了多少次,才能分离生成新chunk
                    priority: -20 // 优先级
                }
            }
        }
    }
};
module.exports = merge(commonConfig, prodConfig);

③ React 支持

1. React

官方文档:React

React 是一个用于构建用户界面的 JavaScript 库。

安装 react

yarn add react react-dom

2. Babel

官方文档:Babel

Babel 是一个工具链,主要用于将 ECMAScript 2015+ 代码转换为当前和旧版浏览器或环境中的向后兼容版本的 JavaScript。Babel 可以在构建过程中将源代码转换为目标代码,也可以在运行时实时转换代码。以下是 Babel 的一些说明:

  • Babel 可以转译多种 JavaScript 语法和特性,包括 ES6/ES2015、ES7/ES2016、ES8/ES2017、ES9/ES2018 等。
  • Babel 的转译规则是可配置的,可以使用预设集合或插件来指定转译规则。
  • Babel 可以与 Webpack、Rollup、Gulp 等构建工具集成使用,以便在项目构建过程中对代码进行转译。
  • Babel 可以实时转译代码,以便在开发过程中使用最新的 JavaScript 特性,而无需担心它们是否受到浏览器支持的限制。
  • Babel 可以使用 polyfill 来模拟新特性,以便在旧版本浏览器或环境中使用新特性。
  • Babel 还支持 TypeScript 转译,可以将 TypeScript 代码转译为 JavaScript 代码,以便在浏览器或 Node.js 等环境中运行。

安装 babel 及相关预设

yarn add @babel/core  -D.                       # Babel 的核心功能
yarn add @babel/cli  -D                         # 一个能够从终端(命令行)使用的工具
yarn add @babel/preset-env  -D.                 # 根据 browserslist 中浏览器设定,进行 polyfill
yarn add @babel/preset-react -D                 # 预设集合: 转译jsx
yarn add @babel/plugin-transform-runtime  -D    # 按需转换api
yarn add @babel/runtime-corejs3 -D              # corejs: false 只对ES语法进行了转换, corejs:2 沙盒环境,不污染全局空间, 无法实例方法, corejs: 3 沙盒环境,不污染全局空间, 可以实例方法

babelrc 配置

根目录创建 .babelrc.js

module.exports = {
  // 预设集合 (presets) 执行顺序: 从后往前。
  presets: [
    [
      "@babel/preset-env", // 根据 browserslist 中浏览器设定,进行 polyfill
      {
        /**
         * useBuiltIns功能说明: '@babel/preset-env'如何进行 polyfills
         * useBuiltIns配置说明如下:
         * false: 只做了语法转换
         * entry: 引入了所有的es扩展包 (不用的也会打包进来)
         * usage: 自动检测代码中用到的功能自动引入模块
         */
        useBuiltIns: "usage",
        corejs: 3,
      },
    ],
    "@babel/preset-react",
    "@babel/preset-typescript",
  ],
  // 插件集合 (plugins) 执行顺序: 从前往后。
  plugins: [
    [
      "@babel/plugin-transform-runtime",
      {
        absoluteRuntime: false,
        /**
         * corejs配置说明如下:
         * corejs: false 只对ES语法进行了转换
         * corejs:2 沙盒环境,不污染全局空间, 无法实例方法
         * corejs: 3 沙盒环境,不污染全局空间, 可以实例方法
         */
        corejs: 3,
        helpers: true,
        regenerator: true,
        useESModules: false,
      },
    ],
  ],
};

④ TypeScript 支持

官方文档:TypeScript

安装 typescript

yarn add @types/react @types/react-dom -D    // 安装类型校验
yarn add typescript -D                       // 添加 TypeScript

ts 编译为 js

Babel 支持 TypeScript 转译,可以将 TypeScript 代码转译为 JavaScript 代码,以便在浏览器或 Node.js 等环境中运行。

yarn add @babel/preset-typescript  -D         # 预设集合: 编译ts

typescript 配置

  • node 提供了 npx 命令直接通过 tsc –init 命令创建 tsconfig.json
npx tsc --init

根目录创建 tsconfig.json

// tsconfig.json 配置参考: https://lq782655835.github.io/blogs/project/ts-tsconfig.html
{
    "compilerOptions": {
        /* 基本选项 */
        "module": "esnext",                     // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
        "target": "esnext",                     // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'("ESNext"表示最新的ES语法,包括还处在stage X阶段)
        "noEmit": true,                         // 不输出, 不编译代码,只执行类型检查, 不生成输出文件
        "allowJs": true,                        // 允许编译 JavaScript 文件
        "jsx": "react",                         // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react'
        "isolatedModules": true,                // 将每个文件做为单独的模块 (与 'ts.transpileModule' 类似)
        "lib": [                                // 指定要包含在编译中的库文件
            "esnext",
            "dom"
        ],
        /* 严格的类型检查选项 */
        "strict": true,                         // 启用所有严格类型检查选项
        /* 模块解析选项 */
        "baseUrl": "./",                        // 用于解析非相对模块名称的基目录
        "skipLibCheck": true,                   // 跳过所有声明文件的类型检查
        "allowSyntheticDefaultImports": true,   // 允许从没有设置默认导出的模块中默认导入
        "esModuleInterop": true,                // 发出额外的JavaScript以简化对导入CommonJS模块的支持
        "moduleResolution": "node",             // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)。默认是classic
        "resolveJsonModule": true,              // 允许使用 .json 扩展名导入的模块
        "paths": {                              // 模块名到基于 baseUrl 的路径映射的列表
            "@/*": ["src/*"],
            "Components/*": ["src/components/*"],
            "Utils/*": ["src/utils/*"]
        },
        /* 额外的检查 */
        "noUnusedLocals": true,                 // 有未使用的变量时,抛出错误
        "noUnusedParameters": true,             // 有未使用的参数时,抛出错误
        "noFallthroughCasesInSwitch": true,     // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch 的 case 语句贯穿)
        /* 其他选项 */
        "experimentalDecorators": true,         // 是否启用实验性的ES装饰器
    },
    "include": [
        "src",
        "*.ts"
    ],
    "exclude": ["node_modules", "build"]
}

⑤ 代码规范

1. 代码风格规范( js / ts )

EditorConfig

官方文档: EditorConfig

EditorConfig 帮助多个开发人员在不同的编辑器和集成开发环境上维护一致的编码风格。EditorConfig 项目由一个文件格式和一系列文本编辑器插件组成,它们使编辑器能够读取文件格式并遵循定义的风格。EditorConfig 文件易于阅读,并且与版本控制系统兼容。

安装 EditorConfig(vscode)

Xnip2023-04-04_15-49-29.jpg

以 vscode 平台为例,安装 EditorConfig For vs Code 插件即可,如图。其他平台安装方式参考官方文档。

EditorConfig 配置

根目录创建 .editorconfig

root = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
end_of_line = lf
[*.md]
trim_trailing_whitespace = false

Prettier

官方文档:Prettier

Prettier 是一款非常流行的代码格式化工具,它可以根据预定义的规则自动调整代码的格式以达到统一的编码风格。

安装 Prettier - Code formatter(vscode)

Xnip2023-04-12_11-31-04.jpg

安装 Prettier
npm install prettier -D
Prettier 配置

官方配置文档: prettier.io/docs/en/opt…

  • printWidth:指定每行的最大长度。默认为 80。
  • tabWidth:指定一个制表符应该有多少个空格。默认为 2。
  • useTabs:指定是否应该使用制表符而不是空格缩进。默认为 false。
  • semi:指定是否应该在语句末尾添加分号。默认为 true。
  • singleQuote:指定是否应该使用单引号而不是双引号。默认为 false。
  • quoteProps:指定是否应该为对象中的属性添加引号。默认为 “as-needed”,即只在必要时添加引号。
  • jsxSingleQuote:指定在 JSX 中是否应该使用单引号而不是双引号。默认为 false。
  • trailingComma:指定是否应该在多行对象和数组的最后一项后添加逗号。默认为 “none”。
  • bracketSpacing:指定是否应该在对象字面量中的括号内添加空格。默认为 true。
  • arrowParens:指定在箭头函数中是否应该添加括号。默认为 “always”。

根目录创建 .prettierrc

{
  "trailingComma": "all",
  "tabWidth": 4,
  "semi": false,
  "singleQuote": true,
  "endOfLine": "lf",
  "printWidth": 120,
  "bracketSpacing": true,
  "arrowParens": "always"
}

2. 代码质量规范( js / ts )

ESLint

官方文档:ESlint

ESLint 是一个开源的 JavaScript 代码检查工具,它可以帮助开发者检查 JavaScript 代码中的错误,改进代码质量,并遵守 ESLint 规则。ESLint 可以在 JavaScript 项目中自动运行,也可以集成到 IDE 中。ESLint 的主要功能包括代码格式化、代码提示、错误提示、性能分析等。

安装 ESlint (vscdoe)

Xnip2023-04-12_14-10-56.jpg

安装 eslint
yarn add eslint -D
npx eslint --init
ESLint 配置

根目录创建 .eslintrc.js

const OFF = 0; // "off" 或 0 - 关闭规则
const WARN = 1; // "warn" 或 1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出)
const ERROR = 2; // "error" 或 2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)
module.exports = {
  // 提供运行环境,一个环境定义了一组预定义的全局变量
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  // 配置文件可以被基础配置中的已启用的规则继承。
  extends: [
    "eslint:recommended", // 使用eslint中recommened的规则
    "plugin:react/recommended", // 推荐的react lint配置
    "plugin:@typescript-eslint/recommended", // 可开启针对 ts 语法推荐的规则定义, 需额外手动安装 @typescript-eslint/eslint-plugin
    "plugin:react-hooks/recommended", // react hook当依赖项指定不正确时,会发出警告并建议修复。
  ],
  overrides: [],
  // ESLint 默认使用Espree作为其解析器,你可以在配置文件中指定一个不同的解析器
  parser: "@typescript-eslint/parser", // 需手动安装 @typescript-eslint/parser,这使Eslint能够理解TypeScript语法
  // 配置解析器支持的语法
  parserOptions: {
    ecmaVersion: "latest",
    sourceType: "module",
  },
  settings: {
    "import/resolver": {
      node: {
        extensions: [".tsx", ".ts", ".js", ".json"],
      },
      typescript: {},
    },
  },
  // ESLint 支持使用第三方插件。在使用插件之前,你必须使用 npm 安装它。
  // 在配置文件里配置插件时,可以使用 plugins 关键字来存放插件名字的列表。插件名称可以省略 eslint-plugin- 前缀。
  plugins: ["react", "@typescript-eslint", "react-hooks"],
  // ESLint 附带有大量的规则。你可以使用注释或配置文件修改你项目中要使用的规则。要改变一个规则设置,你必须将规则 ID 设置为下列值之一:
  rules: {
    "import/extensions": [
      OFF,
      "ignorePackages",
      {
        ts: "never",
        tsx: "never",
        js: "never",
      },
    ],
    "@typescript-eslint/no-var-requires": OFF, // 忽略没有导入声明模块
    "react-hooks/rules-of-hooks": ERROR, // 检查 Hook 的规则
    "react-hooks/exhaustive-deps": WARN, // 检查 Effect 的依赖
  },
};

3. 样式代码规范( css )

Stylelint

官方文档:stylelint

stylelint 是一个基于规则的 CSS 校验工具,可以帮助开发者检查和修复 CSS 代码中的错误、警告和风格问题。与 ESLint 类似,stylelint 可以通过配置文件和插件进行定制,以满足不同项目和团队的需求。

安装 Stylelint(vscode)

Xnip2023-04-12_14-08-24.jpg

安装 stylelint 与相关插件
npm install stylelint -D                        # stylelint基础包
npm install stylelint-config-standard -D        # stylelint配置标准, 如需修改请在rules添加配置
npm install stylelint-config-prettier -D        # 关闭所有不必要的或者可能与prettier相冲突的规则。(放到后面)
npm install stylelint-config-rational-order -D  # 将相关属性声明进行排序, 按照(1.Positioning 2.Box Model 3.Typography 4.Visual 5.Animation 6.Misc)
npm install stylelint-declaration-block-no-ignored-properties -D   # 提示样式矛盾情况, 禁止由于同一规则中的另一个属性值而忽略的属性值。
npm install stylelint-order -D                  # 可以用来定义样式的顺序
stylelint 配置

根目录创建 .stylelintrc.js

module.exports = {
  extends: [
    "stylelint-config-standard", // stylelint配置标准, 如需修改请在rules添加配置
    "stylelint-config-rational-order", // 将相关属性声明进行排序, 按照(1.Positioning 2.Box Model 3.Typography 4.Visual 5.Animation 6.Misc)
    "stylelint-config-prettier", // 关闭所有不必要的或者可能与prettier相冲突的规则。(放到后面)
  ],
  plugins: [
    "stylelint-order",
    "stylelint-declaration-block-no-ignored-properties", // 提示样式矛盾情况, 禁止由于同一规则中的另一个属性值而忽略的属性值。
  ],
  // rules: 其中添加重写和添加内容。可以通过将规则的值设置为 null 来关闭规则
  rules: {
    "plugin/declaration-block-no-ignored-properties": true,
    "comment-empty-line-before": null,
    "declaration-empty-line-before": null,
    "function-name-case": "lower",
    "no-descending-specificity": null,
    "no-invalid-double-slash-comments": null,
    "block-no-empty": null,
    "value-keyword-case": null,
    "rule-empty-line-before": [
      "always",
      { except: ["after-single-line-comment", "first-nested"] },
    ],
    "at-rule-no-unknown": null,
  },
  // 忽略检测文件
  ignoreFiles: [
    "node_modules/**/*",
    "build/**/*",
    "dist/**/*",
    "src/assets/font/*",
  ],
};

4. 代码提交规范

Husky

官方文档:husky

husky 是一个代码提交钩子,即在代码被提交到 Git 仓库之前,我们可以在这里做一些预检查或者格式化,需要做这些操作,我们需要一个 Git 的提交钩子,简单说就是使用 Git 命令会触发的函数。

安装 husky
npm install husky -D

Lint-staged

官方文档:lint-staged

lint-staged 是一个前端文件过滤的工具,是一个仅仅过滤出 Git 代码暂存区文件(被 committed 的文件)的工具。Lint-staged 仅仅是文件过滤器,不会帮你格式化任何东西。

安装 lint-staged
npm install lint-staged -D
husky && lint-staged 配置

根目录 package.json 中增加以下内容:

"husky": {
    "hooks": {
        "pre-commit": "lint-staged",
        "commit-msg": "commitlint --config .commitlintrc.js -E HUSKY_GIT_PARAMS"
    }
},
"lint-staged": {
    "*.{ts,tsx,js}": [
        "eslint --config .eslintrc.js"
    ],
    "*.{css,less,scss}": [
        "stylelint --config .stylelintrc.js"
    ],
    "*.{ts,tsx,js,json,html,yml,css,less,scss,md}": [
        "prettier --write"
    ]
},

⑥ 环境区分

Env-cmd

官方文档:env-cmd

env-cmd 是一个前端开发中常用的工具,它可以帮助开发人员管理环境变量。在开发过程中,我们通常需要使用不同的环境变量来适应不同的场景,例如本地开发、测试、生产等。

安装 env-cmd

npm install env-cmd -D

env-cmd 配置

根目录创建 .env.json

{
  "development": {
    "USER_BASE_URL": "/",
    "ENV": "dev"
  },
  "qa": {
    "USER_BASE_URL": "/",
    "ENV": "qa"
  },
  "production": {
    "USER_BASE_URL": "/",
    "ENV": "prod"
  }
}

env-cmd 项目启动配置

根目录 package.json 中增加以下内容:

"scripts": {
    "dev": "npm run start",
    "start": "env-cmd -r .env.json -e development node webpack/server",
    "build:qa": "env-cmd -r .env.json -e qa webpack --config ./webpack/config/webpack.prod.js",
    "build:prod": "env-cmd -r .env.json -e production webpack --config ./webpack/config/webpack.prod.js"
},

命令说明:

  • -r: 自定义 rc 文件路径(默认路径: ./. env-cmdrc (| . js | . json)
  • -e: 使用的 rc 文件环境环境--environments( -e) 。

⑦ 路由管理

Xnip2023-04-18_14-56-30.jpg

React Router

官方文档:react-router

React Router 是一个轻量级、功能齐全的路由库。

安装 react-router-dom

yarn add react-router-dom

router 配置

根目录创建 /src/router/index.tsx

/*
 * react-router-dom v6 官方文档
 * https://reactrouter.com/en/v6.3.0/getting-started/installation
 */
import React from "react";
import SuspenseLazy from "@/components/SuspenseLazy";
import { Navigate, RouteObject } from "react-router-dom";
const Home = SuspenseLazy(() =>
  import(/* webpackChunkName:"" */ "@/view/Home")
);
const HomeOne = SuspenseLazy(() =>
  import(/* webpackChunkName:"homeOne" */ "@/view/Home/HomeOne")
);
const HomeTwo = SuspenseLazy(() =>
  import(/* webpackChunkName:"homeTwo" */ "@/view/Home/HomeTwo")
);
const HomeThree = SuspenseLazy(() =>
  import(/* webpackChunkName:"HomeThree" */ "@/view/Home/HomeThree")
);
const Dashboard = SuspenseLazy(() =>
  import(/* webpackChunkName:"dashboard" */ "@/view/Dashboard")
);
const About = SuspenseLazy(() =>
  import(/* webpackChunkName:"about" */ "@/view/About")
);
const NotFound = SuspenseLazy(() =>
  import(/* webpackChunkName:"about" */ "@/view/NotFound")
);
const routes: RouteObject[] = [
  {
    path: "/",
    element: <Navigate to="home/two" />, // 重定向
  },
  {
    path: "home",
    element: Home,
    children: [
      // 嵌套路由
      {
        path: "one",
        element: HomeOne,
      },
      {
        path: "two",
        element: HomeTwo,
      },
      {
        path: "three",
        element: HomeThree,
      },
    ],
  },
  {
    path: "dashboard",
    element: Dashboard,
  },
  {
    path: "about",
    element: About,
  },
  // 未匹配到页面
  {
    path: "*",
    element: NotFound,
  },
];
export default routes;

其他页面配置

参考:commit ✅config: 🔧 新增路由管理 react-router-dom v6

⑧ 状态管理

Mobx

image.png

官方文档:Mobx

Mobx 是一个状态管理库。

安装 mobx

npm install mobx --save

Mobx-react-lite

官方文档:mobx-react-lite

mobx-react-lite 是一个用于将 Mobx 和 React 结合使用的轻量级库, 旨在提供最简单的方式来使用 Mobx 来管理 React 组件的状态。

直至 2018 年底,React 项目中统一使用 mobx 的方式都是 mobx-react。然而随着 react hooks 的诞生,mobx-react-lite 也出现了,它是专门服务于 react hooks 的 mobx-react 轻量级版本。虽然 mobx-react@6 已经包含了 mobx-react-lite,但官方是推荐在没有类组件的 react 项目中直接使用 mobx-react-lite。

npm install mobx-react --save

其他页面配置

参考:commit ✅ feat: ✨ 新增状态管理 Mobx v6

⑨ 增加 React Hook 规则 监查

⑩ 增加 封装全局 SVG 组件

参考这篇文章 《 React 项目如何封装 SVG 组件 》

本文整理代码如有缺失请参考 commit 记录, 推荐直接去 github 查看源码 项目 repo: react-enterprise-template

- Book Lists -