本篇文章讲述从零搭建React中后台项目框架模板,方便快速进行具体项目开发。包括Webpack4.0配置及打包优化、React全家桶使用(React + React-router + Axios + Mobx + Antd)、ESLint等项目开发规范等。

——————2020-12-10 更新记录———————

github源码 v2.0.0版本更新:

  • 升级项目中全部依赖库版本,主要包括:react17、antd4、webpack5…
  • 增加 commitlint 规范git提交;
  • 增加 husky + lint-staged + Prettier 规范代码提交校验;
  • 优化 eslint + prettier 规范项目代码风格;

需要查看文章对应之前代码,可切换至v1.0.0查看。
——————2020-12-10 更新记录———————

涉及的技术栈均采用当前最新版本的语法:

  • 使用Webpack5.0构建项目(不使用create-react-appumi等脚手架);
  • 使用Babel7配置转换ES6、React、Mobx等语法;
  • React版本V17.0.1,全部采用函数化 Hooks特性开发项目组件
  • 采用React-router5 工具 配置项目路由;
  • 采用Mobx5 + Hooks实现项目数据状态管理;
  • 封装Axios库实现与后台http请求交互;
  • UI库采用流行的Ant-design4.0组件库;
  • 完整项目实现及模块结构拆分;

作者:nowThen
链接:https://juejin.cn/post/6844904035099623437
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

项目页面截图:
演示.gif

前言

一般React开发,可以使用Facebook提供的 create-react-app 来创建。create-react-app 足够简单易用,从学习 React 的角度来看非常合适。但严格说来,如果要开发一款大型的应用,需要做到更精细、更灵活的配置,只用 create-react-app 并不合适,有规模点的公司都会考虑搭建自己公司级的脚手架工具和框架模板。而基础就是基于webpack从零精细化构建。

企业级React开发也可以采用蚂蚁金服的Umi(一个可插拔的企业级 react 应用框架),可以使用相关的全套全家桶连贯快捷开发,优点还在于大厂出品,经历众多大项目的考验,稳定性和可维护性得到极大的保障。但是增加了不少学习成本,项目的粒度可控性不高,也比较受限。
在构建公司级全套项目架构上可以从Umi、[Ant Design Pro](https://pro.ant.design/)等上获取不少极有价值的参考。

本项目从零搭建React应用模板,一来方便自己快速构建实际应用;二来重点在于梳理各技术栈最新知识点。希望也对看到的人有所帮助。

项目说明

本项目为React中后台项目框架模板,方便快速进行具体项目开发。包括Webpack4.0配置及打包优化、React全家桶使用(React + React-router + Axios + Mobx + Antd)、ESLint等项目开发规范等。

项目Git地址:https://github.com/now1then/react-web-pro
在线演示地址:
文章链接-语雀:https://www.yuque.com/nowthen/longroad/exeuw7

目录结构:

  1. ├── build // webpack配置
  2. ├── webpack.common.js // webpack通用配置
  3. ├── webpack.dev.js // webpack开发环境配置
  4. └── webpack.prod.js // webpack生产环境配置
  5. ├── dist // 打包输出目录
  6. ├── public // 项目公开目录
  7. ├── src // src开发目录
  8. ├── assets // 静态资源
  9. ├── components // 公共组件
  10. ├── layouts // 页面布局组件
  11. ├── modules // 公共业务模块
  12. ├── pages // 具体业务页面
  13. ├── routers // 项目路由配置
  14. ├── services // axios服务等相关
  15. ├── stores // 全局公共 mobx store
  16. ├── styles // 存放公共样式
  17. ├── utils // 工具库/通用函数
  18. ├── index.html // 入口html页面
  19. └── main.js // 项目入口文件
  20. ├── .babelrc // babel配置
  21. ├── .editorconfig // 项目格式配置
  22. ├── .eslintrc.js // ESLint配置
  23. ├── .gitignore // git 忽略配置
  24. ├── .postcssrc.js // postcss配置
  25. ├── package.json // 依赖包配置
  26. └── README.md // 项目说明

项目构建

文章中使用 Yarn 管理安装包,若未安装Yarn,替换成 Npm 对应命令即可。

初始化项目

初始化package.json

  1. yarn init

安装webpack

  1. yarn add -D webpack webpack-cli webpack-merge

项目中使用的Webpack版本是^4.41.2,Webpack4.0 打包构建做了很多默认的优化配置,不少配置项无需配置或更改。
比如:针对开发模式的加快打包速度,合并chunk; 针对生产模式的代码压缩,减少打包体积等。

  1. // 一部分默认配置
  2. optimization: {
  3. removeAvailableModules: true, // 删除已解决的chunk (默认 true)
  4. removeEmptyChunks: true, // 删除空的chunks (默认 true)
  5. mergeDuplicateChunks: true // 合并重复的chunk (默认 true)
  6. }
  7. // 针对生产环境默认配置
  8. optimization: {
  9. sideEffects:true, //配合tree shaking
  10. splitChunks: {...}, //拆包
  11. namedModules: false, // namedChunks:false 不启用chunk命名,默认自增id
  12. minimize: true, // 代码压缩
  13. }

根据开发环境/生产环境 区分webpack配置非常有必要,可以加快开发环境的打包速度,有时候遇到开发环境打包过慢,可以排查下是否配置有误(比如开发环境开启了代码压缩等)。
项目中配合webpack-merge根据开发环境/生产环境进行拆分配置:
build.png

Webpack4.0发布已经很长时间了,相信基本上项目都已迁移至4.0,在这里就不多赘述了。

配置Html模板

安装:
  1. yarn add -D html-webpack-plugin

配置:
  1. const srcDir = path.join(__dirname, "../src");
  2. plugins: [
  3. new HtmlWebpackPlugin({
  4. template: `${srcDir}/index.html`
  5. })
  6. ]

配置本地服务及热更新

安装:
  1. yarn add -D webpack-dev-server clean-webpack-plugin

开发环境利用webpack-dev-server搭建本地 web server,并启用模块热更新(HMR)
为方便开发调试,转发代理请求(本例中配合axios封装 转发接口到easy-mock在线平台)

配置:
  1. mode: "development", // 开发模式
  2. devServer: { // 本地服务配置
  3. port: 9000,
  4. hot: true,
  5. open: false,
  6. historyApiFallback: true,
  7. compress: true,
  8. proxy: { // 代理
  9. "/testapi": {
  10. target:
  11. "https://www.easy-mock.com/mock/5dff0acd5b188e66c6e07329/react-template",
  12. changeOrigin: true,
  13. secure: false,
  14. pathRewrite: { "^/testapi": "" }
  15. }
  16. }
  17. },
  18. plugins: [
  19. new webpack.NamedModulesPlugin(),
  20. new webpack.HotModuleReplacementPlugin()
  21. ],

配置Babel

安装:
  1. yarn add -D babel-loader @babel/core @babel/plugin-transform-runtime
  2. @babel/preset-env @babel/preset-react babel-plugin-import
  3. @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators

Webpack中Babel配置,是比较重要的一环。关系着ES6语法、React jsx、Mobx等语法经过打包后能否正常运行。
其中:

  • @babel/preset-react转换React jsx语法;
  • @babel/plugin-proposal-class-properties 转换 Class语法;
  • @babel/plugin-proposal-decorators 转换 Mobx 等更高级的语法;
  • babel-plugin-import 配合实现React组件的按需加载;

这里需要注意Babel7.0 相较于Babel6.0的区别。

配置:
  1. module: {
  2. rules: [
  3. {
  4. test: /\.(js|jsx)$/,
  5. include: [srcDir],
  6. use: ["babel-loader?cacheDirectory=true"]
  7. },
  8. ]
  9. }

.babelrc 文件配置
  1. {
  2. "presets": [
  3. "@babel/preset-env",
  4. "@babel/preset-react"
  5. ],
  6. "plugins": [
  7. "@babel/transform-runtime",
  8. [
  9. "@babel/plugin-proposal-decorators",
  10. {
  11. "legacy": true
  12. }
  13. ],
  14. ["@babel/plugin-proposal-class-properties", { "loose": true }],
  15. [
  16. "import",
  17. {
  18. "libraryName": "antd",
  19. "libraryDirectory": "es",
  20. "style": "css" // `style: true` 会加载 less 文件
  21. }
  22. ]
  23. ]
  24. }

处理Less样式和图片等资源

安装:
  1. yarn add -D less less-loader style-loader css-loader url-loader
  2. mini-css-extract-plugin postcss-loader autoprefixer

其中:

  • less-loader、style-loader、css-loader处理加载less、css文件;
  • postcss-loader、autoprefixer处理css样式浏览器前缀兼容;
  • url-loader处理图片、字体文件等资源;
  • mini-css-extract-plugin 分离css成单独的文件;

配置:
  1. const MiniCssExtractPlugin = require("mini-css-extract-plugin");
  2. ...
  3. module: {
  4. rules: [
  5. {
  6. test: /\.less$/,
  7. use: [
  8. devMode ? "style-loader" : MiniCssExtractPlugin.loader,
  9. "css-loader",
  10. "postcss-loader",
  11. "less-loader"
  12. ]
  13. },
  14. {
  15. test: /\.css$/,
  16. use: [
  17. devMode ? "style-loader" : MiniCssExtractPlugin.loader,
  18. "css-loader",
  19. "postcss-loader"
  20. ]
  21. },
  22. {
  23. test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
  24. use: ["url-loader"],
  25. include: [srcDir]
  26. },
  27. {
  28. test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
  29. use: ["url-loader"],
  30. include: [srcDir]
  31. },
  32. {
  33. test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
  34. use: ["url-loader"],
  35. include: [srcDir]
  36. }
  37. ]
  38. },
  39. plugins: [
  40. new MiniCssExtractPlugin({
  41. filename: "[name].[contenthash:8].css",
  42. chunkFilename: "chunk/[id].[contenthash:8].css"
  43. }),
  44. ],

配置postcss .postcssrc.js文件
  1. // .postcssrc.js
  2. module.exports = {
  3. plugins: {
  4. autoprefixer: {}
  5. }
  6. };
  7. // package.json中配置兼容浏览器
  8. "browserslist": [
  9. "> 1%",
  10. "last 2 versions",
  11. "not ie <= 10"
  12. ]

利用happypack 多线程打包

安装:
  1. yarn add -D happypack

配置:
  1. const os = require("os");
  2. const HappyPack = require("happypack");
  3. const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
  4. module: {
  5. rules: [
  6. {
  7. test: /\.(js|jsx)$/,
  8. include: [srcDir],
  9. exclude: /(node_modules|bower_components)/,
  10. use: ["happypack/loader?id=happybabel"]
  11. },
  12. ]
  13. },
  14. plugins: [
  15. //开启 happypack 的线程池
  16. new HappyPack({
  17. id: "happybabel",
  18. loaders: ["babel-loader?cacheDirectory=true"],
  19. threadPool: happyThreadPool,
  20. cache: true,
  21. verbose: true
  22. }),
  23. ]

生产环境 拆分模块

根据实际项目情况拆分模块,配合异步加载,防止单个文件过大。

  1. optimization: {
  2. runtimeChunk: {
  3. name: "manifest"
  4. },
  5. splitChunks: {
  6. chunks: "all", //默认只作用于异步模块,为`all`时对所有模块生效,`initial`对同步模块有效
  7. cacheGroups: {
  8. dll: {
  9. test: /[\\/]node_modules[\\/](react|react-dom|react-dom-router|babel-polyfill|mobx|mobx-react|mobx-react-dom|antd|@ant-design)/,
  10. minChunks: 1,
  11. priority: 2,
  12. name: "dll"
  13. },
  14. codeMirror: {
  15. test: /[\\/]node_modules[\\/](react-codemirror|codemirror)/,
  16. minChunks: 1,
  17. priority: 2,
  18. name: "codemirror"
  19. },
  20. vendors: {
  21. test: /[\\/]node_modules[\\/]/,
  22. minChunks: 1,
  23. priority: 1,
  24. name: "vendors"
  25. }
  26. }
  27. }
  28. }

其他配置

引入 ESLint 与 Prettier 配合,规范化团队项目代码开发,统一代码风格。
  1. yarn add -D prettier babel-eslint eslint eslint-loader eslint-config-airbnb
  2. eslint-config-prettier eslint-plugin-babel eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react

(细节待补充)

具体配置详见**/build目录**项目代码

npm scripts

package.json 文件

  1. {
  2. ...
  3. "scripts": {
  4. "start": "webpack-dev-server --color --inline --progress --config build/webpack.dev.js", //
  5. "build": "NODE_ENV=production webpack --progress --config ./build/webpack.prod.js",
  6. "build:report": "NODE_ENV=production webpack --progress --config ./build/webpack.prod.js",
  7. "build:watch": "NODE_ENV=production webpack --progress --config ./build/webpack.prod.js"
  8. },
  9. ...
  10. }

命令行运行:

  1. // 命令行执行
  2. // 运行开发环境;
  3. yarn start
  4. // 生产环境打包压缩;
  5. yarn build
  6. // 图形化分析打包文件大小;
  7. yarn build:report
  8. // 方便排查生产环境打包后文件的错误信息(文件source map);
  9. yarn build:watch

其中build:report、build:watch 能够实现功能,是在build/webpack.prod.js中有如下代码:

  1. // 方便排查生产环境打包后文件的错误信息(文件source map)
  2. if (process.env.npm_lifecycle_event == "build:watch") {
  3. config = merge(config, {
  4. devtool: "cheap-source-map"
  5. });
  6. }
  7. // 图形化分析打包文件大小
  8. if (process.env.npm_lifecycle_event === "build:report") {
  9. const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  10. .BundleAnalyzerPlugin;
  11. config.plugins.push(new BundleAnalyzerPlugin());
  12. }

项目代码架构

实际开发用到的依赖包安装:

  1. yarn add react react-dom react-router-dom mobx mobx-react mobx-react-router
  2. axios antd moment

我们在写具体代码之前要做的第一个决定就是,目录结构怎么构建?要把这些组件放在哪里?

目录结构

根据个人习惯及经验,项目目录构建如下图所示:

  1. ├── build // webpack配置
  2. ├── webpack.common.js // webpack通用配置
  3. ├── webpack.dev.js // webpack开发环境配置
  4. └── webpack.prod.js // webpack生产环境配置
  5. ├── dist // 打包输出目录
  6. ├── public // 项目公开目录
  7. ├── src // src开发目录
  8. ├── assets // 静态资源
  9. ├── components // 公共组件
  10. ├── layouts // 页面布局组件
  11. ├── modules // 公共业务模块
  12. ├── pages // 具体业务页面
  13. ├── routers // 项目路由配置
  14. ├── services // axios服务等相关
  15. ├── stores // 全局公共 mobx store
  16. ├── styles // 存放公共样式
  17. ├── utils // 工具库/通用函数
  18. ├── index.html // 入口html页面
  19. └── main.js // 项目入口文件
  20. ├── .babelrc // babel配置
  21. ├── .editorconfig // 项目格式配置
  22. ├── .eslintrc.js // ESLint配置
  23. ├── .gitignore // git 忽略配置
  24. ├── .postcssrc.js // postcss配置
  25. ├── package.json // 依赖包配置
  26. └── README.md // 项目说明

页面模块目录结构,比如FormDemo页面结构:

  1. ├── FormDemo // 表单演示 页面
  2. ├── index.js // 页面入口文件
  3. ├── newModal.js // 弹窗组件
  4. ├── searchForm.js // 搜索表单 模块组件
  5. ├── store.js // 本页面使用的 mobx store 数据
  6. └── style.less // 页面样式

函数化Hooks

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

当前React版本已更新到16.12,Hooks 完全应该成为 React 使用的主流。本项目中将完全拥抱Hook,一般不再用 class 来实现组件。
**
以下为部分实现代码(可暂忽略mobx的使用):

  1. import React, { useState, useEffect, useContext } from 'react';
  2. import { observer } from 'mobx-react';
  3. import { Button } from 'antd';
  4. import Store from './store';
  5. import './style.less';
  6. const HomePage = () => {
  7. // useContext 订阅mobx数据
  8. const pageStore = useContext(Store);
  9. // useState state状态
  10. const [num, setNum] = useState(0);
  11. // useEffect副作用
  12. useEffect(() => {
  13. pageStore.qryTableDate();
  14. }, []);
  15. return (
  16. <div className="page-home page-content">
  17. <h2>{pageStore.pageTitle}</h2>
  18. <div>
  19. <span>num值:{num}</span>
  20. <Button type="primary" size="small" style={{ marginLeft: 10 }}
  21. onClick={() => setNum(num + 1)}
  22. >+1</Button>
  23. </div>
  24. </div>
  25. );
  26. };
  27. export default observer(HomePage);

Router路由配置

项目是单页应用,路由配置一般分为约定式动态路由和集中配置式路由。
在 React 的世界里,直接采用成熟的react-router工具管理页面路由。我们现在说到react-router,基本上都是在说 react-router 的第4版之后的版本,当前的最新版本已经更新到5.1.x了。
当前react-router支持动态路由,完全用React组件来实现路由,在渲染过程中动态设置路由规则,匹配命中规则加载对应页面组件。

本项目采用集中配置式路由(方便路由鉴权、从服务端接口获取菜单路由配置等),同时兼顾方便地设置侧边菜单栏。 当然为简单起见,项目中读取本地静态菜单配置,也暂未引入路由鉴权。

静态路由配置 src/routes/config.js

  1. import React, { lazy } from "react";
  2. import BasicLayout from "@/layouts/BasicLayout";
  3. import BlankLayout from "@/layouts/BlankLayout";
  4. const config = [
  5. {
  6. path: "/",
  7. component: BlankLayout, // 空白页布局
  8. childRoutes: [ // 子菜单路由
  9. {
  10. path: "/login", // 路由路径
  11. name: "登录页", // 菜单名称 (不设置,则不展示在菜单栏中)
  12. icon: "setting", // 菜单图标
  13. component: lazy(() => import("@/pages/Login")) // 懒加载 路由组件
  14. },
  15. // login等没有菜单导航栏等基本布局的页面, 要放在基本布局BasicLayout之前。
  16. {
  17. path: "/",
  18. component: BasicLayout, // 基本布局框架
  19. childRoutes: [
  20. {
  21. path: "/welcome",
  22. name: "欢迎页",
  23. icon: "smile",
  24. component: lazy(() => import("@/pages/Welcome"))
  25. },
  26. {... /* 其他 */},
  27. { path: "/", exact: true, redirect: "/welcome" },
  28. { path: "*", exact: true, redirect: "/exception/404" }
  29. ]
  30. }
  31. ]
  32. }
  33. ];
  34. export default config;

上面是静态路由的一部分配置,
注意:<Router>中会用<Switch>包裹,会匹配命中的第一个。"/login"等没有菜单导航栏等基本布局的页面, 要放在基本布局BasicLayout之前。

利用<Suspense>React.lazy()实现页面组件懒加载。

路由组件渲染 src/routes/AppRouter.js:

  1. import React, { lazy, Suspense } from "react";
  2. import LoadingPage from "@/components/LoadingPage";
  3. import {
  4. HashRouter as Router,
  5. Route,
  6. Switch,
  7. Redirect
  8. } from "react-router-dom";
  9. import config from "./config";
  10. const renderRoutes = routes => {
  11. if (!Array.isArray(routes)) {
  12. return null;
  13. }
  14. return (
  15. <Switch>
  16. {routes.map((route, index) => {
  17. if (route.redirect) {
  18. return (
  19. <Redirect
  20. key={route.path || index}
  21. exact={route.exact}
  22. strict={route.strict}
  23. from={route.path}
  24. to={route.redirect}
  25. />
  26. );
  27. }
  28. return (
  29. <Route
  30. key={route.path || index}
  31. path={route.path}
  32. exact={route.exact}
  33. strict={route.strict}
  34. render={() => {
  35. const renderChildRoutes = renderRoutes(route.childRoutes);
  36. if (route.component) {
  37. return (
  38. <Suspense fallback={<LoadingPage />}>
  39. <route.component route={route}>
  40. {renderChildRoutes}
  41. </route.component>
  42. </Suspense>
  43. );
  44. }
  45. return renderChildRoutes;
  46. }}
  47. />
  48. );
  49. })}
  50. </Switch>
  51. );
  52. };
  53. const AppRouter = () => {
  54. return <Router>{renderRoutes(config)}</Router>;
  55. };
  56. export default AppRouter;

路由 hooks语法

react-router-dom 也已经支持 hooks语法,获取路由信息或路由跳转,可以使用新的hooks 函数:

  • [useHistory](https://reacttraining.com/react-router/core/api/Hooks/usehistory):获取历史路由,回退、跳转等操作;
  • useLocation:查看当前路由信息;
  • [useParams](https://reacttraining.com/react-router/core/api/Hooks/useparams):读取路由附带的params参数信息;
  • [useRouteMatch](https://reacttraining.com/react-router/core/api/Hooks/useroutematch):匹配当前路由;

只要包裹在中的子组件都可以通过这几个钩子函数获取路由信息。

代码演示:

  1. import { useHistory } from "react-router-dom";
  2. function HomeButton() {
  3. const history = useHistory();
  4. function onClick() {
  5. history.push("/home");
  6. }
  7. return (
  8. <button type="button" onClick={onClick}>
  9. 跳转Home
  10. </button>
  11. );
  12. }

结合mobx管理数据状态

项目中是否使用状态管理工具或使用何种管理工具,依据实际项目情况而定。
本项目使用自己比较熟悉的Mobx,Mobx是一个功能强大,上手非常容易的状态管理工具。

为了使用简洁及管理方便,在组织上,分为全局公共数据状态页面数据状态。
公用数据状态存放在/src/stores目录下;页面几数据存放于对应页面目录下。

在实现上,利用mobx + useContext Hook特性 实现函数式组件的状态管理。
具体在于利用React的createdContext构建包含Mobx 的context上下文;函数式组件中使用useContext Hook 订阅Mobx数据变化。

页面级store.js代码:

  1. import { createContext } from "react";
  2. import { observable, action, computed } from "mobx";
  3. import request from "@/services/newRequest";
  4. class HomeStore {
  5. @observable tableData = [];
  6. @observable pageTitle = "Home主页";
  7. @observable loading = false;
  8. @action.bound setData(data = {}) {
  9. Object.entries(data).forEach(item => {
  10. this[item[0]] = item[1];
  11. });
  12. }
  13. // 列表数据
  14. @action.bound
  15. async qryTableDate(page = 1, size = 10) {
  16. this.loading = true;
  17. const res = await request({
  18. url: "/list",
  19. method: "post",
  20. data: { page, size }
  21. });
  22. if (res.success) {
  23. const resData = res.data || {};
  24. console.log(resData);
  25. }
  26. this.loading = false;
  27. }
  28. }
  29. export default createContext(new HomeStore());

页面组件 代码:

  1. import React, { useContext } from "react";
  2. import { observer } from "mobx-react";
  3. import Store from "./store";
  4. import "./style.less";
  5. const HomePage = () => {
  6. const pageStore = useContext(Store);
  7. return (
  8. <div className="page-home page-content">
  9. home页面
  10. <h2>{pageStore.pageTitle}</h2>
  11. </div>
  12. );
  13. };
  14. export default observer(HomePage);

以上为部分演示代码,具体业务实现可以查看项目代码。

Axios Http请求封装

Axios请求封装,具体代码见/src/services/newRequest.js
思路详见本人之前的另一篇文章(忽略外部组件即可):「漫漫长路-Axios封装

UI组件及页面布局

UI组件使用优秀的Ant Design 组件库,注意使用 babel-plugin-import 配置实现组件的按需加载。

本项目的内部页面布局采用Antd上经典的布局方式:
image.png

页面布局需要合理拆分模块,左侧菜单导航栏根据静态菜单渲染。实际完整代码详见项目,以下为BasicLayout组件:

  1. import React from "react";
  2. import { Layout } from "antd";
  3. import SiderMenu from "../SiderMenu";
  4. import MainHeader from "../MainHeader";
  5. import MainFooter from "../MainFooter";
  6. import "./style.less";
  7. const BasicLayout = ({ route, children }) => {
  8. return (
  9. <Layout className="main-layout">
  10. {/* 左侧菜单导航 */}
  11. <SiderMenu routes={route.childRoutes} />
  12. <Layout className="main-layout-right">
  13. {/* 顶部展示布局 */}
  14. <MainHeader></MainHeader>
  15. <Layout.Content className="main-layout-content">
  16. {/* 实际页面布局 */}
  17. {children}
  18. {/* <MainFooter></MainFooter> */}
  19. </Layout.Content>
  20. </Layout>
  21. </Layout>
  22. );
  23. };
  24. export default BasicLayout;

对于登录页等页面无需套在上面的基本布局之类,需要单独处理(菜单配置在BasicLayout配置之前)。
image.png

待完善项:

  • 完善 ESLint+ prettier规范化团队代码风格;
  • 引入TypeScript及配置;
  • 根据实际场景提取公共模块、组件;

最后

书写不易,觉得还不错、有帮助的童鞋,欢迎多多star;