從0到1用react+antd+redux搭建一個開箱即用的企業級管理後臺系列(基礎篇)

fozero發表於2021-06-27

背景

最近因為要做一個新的管理後臺專案,新公司大部分是用vue寫的,技術棧這塊也是想切到react上面來,所以,這次從0到1重新搭建一個react專案架子,需要考慮的東西的很多,包括目錄結構、程式碼規範、請求封裝等等,
涉及內容較多,所以我分成了幾個部分來記錄搭建的過程:

  1. 從0到1用react+antd+redux搭建一個開箱即用的企業級管理後臺系列(基礎篇)
  2. 從0到1用react+antd+redux搭建一個開箱即用的企業級管理後臺系列(引入redux)
  3. 從0到1用react+antd+redux搭建一個開箱即用的企業級管理後臺系列(選單路由)
  4. 從0到1用react+antd+redux搭建一個開箱即用的企業級管理後臺系列(許可權)

專案我已經上傳到github,有需要的可以自取,記得star哦!也歡迎大家在上面提issue~

專案初始化

  1. 通過create-react-app並使用typescript模板建立專案
yarn create react-app react-antd-adminMT  --template typescript
  1. 目錄結構調整

為了便於開發和管理程式碼,我們在src下建立components、navigation、pages、redux、services、utils子資料夾

├── LICENSE
├── README.md
├── build
├── mock        			---本地mock服務
│   ├── server.js
│   └── test.js
├── package.json
├── public
├── src
│   ├── components    ---元件
│   ├── config        ---配置檔案
│   ├── index.css
│   ├── index.tsx
│   ├── navigation    ---路由導航
│   ├── pages        	---頁面元件
│   ├── redux
│   ├── services      ---介面檔案
│   ├── setupProxy.js
│   ├── setupTests.ts
│   └── utils         ---工具相關
├── tsconfig.json
└── yarn.lock

多環境打包配置

例如我們需要配置多個不同的環境,載入不同的變數

.env.development
.env.staging
.env.production

每個檔案裡面對應不同的變數值

PORT=3000
REACT_APP_ENV=staging
REACT_APP_BASE_URL=https://www.zhihu.com

打包時載入不同環境變數檔案

兩種方式:

  • env-cmd
  • dotenv-cli
"scripts": {
    "dev": "env-cmd -f .env.development react-scripts start",
    "dev:stg": "env-cmd -f .env.staging react-scripts start",
    "build": "react-scripts build",
    "build:stg": "env-cmd -f .env.staging yarn build",
    "build:prod": "env-cmd -f .env.production yarn build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },

這裡我使用的是env-cmd,通過在指令碼命令配置env-cmd -f .env.development,這樣我們就可以再執行yarn dev的時候載入.env.development檔案裡面的變數,類似,每個不同環境打包載入對應不同的環境變數

配置程式碼規範

prettier配合eslint

eslint主要用於語法校驗,prettier保持風格統一

  1. 安裝相關包
$ yarn add C eslint-plugin-prettier eslint-config-prettier --dev

上面安裝包中eslint、 prettier肯定是必不可少的。eslint-plugin-prettier外掛會呼叫prettier對你的程式碼風格進行檢查,eslint-config-prettier外掛可以關閉一些不必要的或者與prettier衝突的lint選項

  1. 在根目錄下建立.eslintrc.js檔案
module.exports = {
  root: true,
  parserOptions: {
    ecmaFeatures: {
      jsx: true
    }
  },
  env: {
    browser: true,
    es6: true
  },
  extends: ['react-app', 'plugin:prettier/recommended'],
  plugins: ['prettier'],
  rules: {
    'prettier/prettier': 'error',
    'react-hooks/rules-of-hooks': 'error',
    'react-hooks/exhaustive-deps': 'off'
  }
}

eslint配置項有很多,例如:
Parser、parserOptions、Environments、Globals、Plugins、extends、Rules

詳情可以檢視eslint手冊 https://eslint.bootcss.com/docs/user-guide/configuring

這裡主要介紹下extends、plugins和rules選項

  1. extends

一個配置檔案可以從基礎配置中繼承已啟用的規則。extends 裡面可以引入 共享配置包,可以引入 外掛

  • 可共享的配置

可共享的配置 是一個 npm 包,它輸出一個配置物件。extends 屬性值可以省略包名的字首 eslint-config-。

  • 外掛

外掛 是一個 npm 包,通常輸出規則。plugins 屬性值 可以省略包名的字首 eslint-plugin-。

  • extends 屬性值可以由以下組成:

(1)、plugin: (2)、包名 (省略了字首,比如,react) (3)、/ (4)、配置名稱 (比如 recommended)
例如:extends: ['react-app', 'plugin:prettier/recommended']

  1. plugins

ESLint 支援使用第三方外掛。在使用外掛之前,你必須使用包管理工具安裝它,外掛名稱可以省略 eslint-plugin- 字首

  1. rules

ESLint 附帶有大量的規則,可以使用註釋或配置檔案修改你專案中要使用的規則。要改變一個規則設定,你必須將規則 ID 設定為off、warn、error三者之一。

  1. 根目錄下建立.prettierrc.js檔案
module.exports = {
    semi: false,						// 句末加分號
    singleQuote: true,      // 用單引號
    printWidth: 80,    			// 換行字串閾值
    jsxSingleQuote: true,   // 在jsx中使用單引號代替雙引號
    trailingComma: 'none',	// 最後一個物件元素加逗號
    arrowParens: 'avoid'    // (x) => {} 是否要有小括號
}

  1. 上面將eslint和prettier配置完了之後,但是要能夠自動格式化,那麼我們還需要做一些整合。例如,在修改程式碼儲存後,能夠自動格式化程式碼

開啟VScode的配置檔案,新增如下配置

{
  "eslint.alwaysShowStatus": true,
  "editor.formatOnSave": true,
  "[javascript]": {
    "editor.formatOnSave": false
  },
  "[html]": {
    "editor.formatOnSave": false
  },
  "editor.formatOnPaste": false,
  "editor.tabSize": 2,
  "javascript.updateImportsOnFileMove.enabled": "never",
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}

上面新增配置因為是全域性的,為了能夠在團隊開發時統一,我們也可以為專案單獨配置,在專案根目錄下建立.vscode資料夾並新建settings.json檔案,然後將上面內容拷貝進去

配置husky

husky,是一個git hooks工具,它可以再我們程式碼commit或push的時候做一些事情,以保證我們提交的程式碼是符合規範的

  1. 安裝husky
$ yarn add husky --dev
  1. 在package.json中設定我們需要的git hooks
"husky": {
    "hooks": {
      "pre-commit": "lint-staged",//commit前檢查暫存區檔案進行規則校驗
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS",//校驗commit時新增的備註資訊是否符合我們要求的規範
    }
  },

這裡我們需要下面安裝幾個包

$ yarn add @commitlint/cli @commitlint/config-conventional lint-staged eslint-plugin-simple-import-sort -D

lint-staged,在程式碼提交之前,進行程式碼規則檢查能夠確保進入git庫的程式碼都是符合程式碼規則的,如果在整個專案上執行lint速度會很慢,lint-staged能夠讓lint只檢測暫存區的檔案,速度很快。

@commitlint/cli @commitlint/config-conventional,這兩個主要是用來規範程式碼提交的資訊

type支援以下型別:

  • build:主要目的是修改專案構建系統(例如 glup,webpack,rollup 的配置等)的提交
  • ci:主要目的是修改專案繼續整合流程(例如 Travis,Jenkins,GitLab CI,Circle等)的提交
  • docs:文件更新
  • feat:新增功能
  • fix:bug 修復
  • perf:效能優化
  • refactor:重構程式碼(既沒有新增功能,也沒有修復 bug)
  • style:不影響程式邏輯的程式碼修改(修改空白字元,補全缺失的分號等)
  • test:新增測試用例或是更新現有測試
  • revert:回滾某個更早之前的提交
  • chore:不屬於以上型別的其他型別(日常事務)

例如:

$ git commit -m 'feat: 新增xxx功能'
$ git commit -m 'fix: 修復xxxbug'

如果不符合以上支援type的規範,提交的時候會報錯

  1. 根目錄下新建.lintstagedrc.js檔案
module.exports = {
  '**/*.{js,jsx,ts,tsx}': [
    'prettier --write',
    'eslint --fix --plugin=simple-import-sort --rule=simple-import-sort/imports:error',
    'git add'
  ],
  '**/*.{json,md,mdx,css,html,yml,yaml,scss}': ['prettier --write', 'git add']
}

  1. 根目錄下新建.commitlintrc.json檔案
{
  "extends": [
    "@commitlint/config-conventional"
  ]
}
  1. 最後,需要注意的是,配置好了husky之後commit不生效,發現是husky 6.0版本做了破壞性的更新,這裡我們通過移除husky包並新增低版本的方式來解決
$ yarn remove husky 
$ yarn add husky@4.3.8 -D

Http請求封裝

  1. 新一個apiClient.js檔案用來配置axios,最後返回axios例項
import axios from 'axios'

const baseURL = process.env.REACT_APP_BASE_URL

const instance = axios.create({
  baseURL,
  timeout: 15000
})

// Add a request interceptor
instance.interceptors.request.use(
  function (config) {
    // Do something before request is sent
    return config
  },
  function (error) {
    // Do something with request error
    return Promise.reject(error)
  }
)

// Add a response interceptor
instance.interceptors.response.use(
  function (response) {
    // Any status code that lie within the range of 2xx cause this function to trigger
    // Do something with response data
    return response
  },
  function (error) {
    // Any status codes that falls outside the range of 2xx cause this function to trigger
    // Do something with response error
    return Promise.reject(error)
  }
)

export default instance
  1. 引入apiClient並呼叫axios的請求方法
import apiClient from './apiClient'

export const getContractList = () => apiClient.get(`/api/v4/search/top_search`)
  1. get、post傳參形式

這裡需要注意一點是,get和post傳參形式有點區別,get請求傳參需要帶上params欄位

//get請求
axios.get('/user', {
    params: {
      ID: 12345
    }
  })
// post請求
axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })

本地跨域請求

在src目錄下建立setupProxy.js檔案配置代理介面,這樣我們在請求帶有/proxy-api介面的時候,就能代理到http://localhost:3001服務上,從而解決跨域的問題

const { createProxyMiddleware } = require('http-proxy-middleware')

module.exports = function (app) {
  app.use(
    '/proxy-api',
    createProxyMiddleware({
      target: 'http://localhost:3001',
      changeOrigin: true,
      secure: false,
      pathRewrite: {
        '^/proxy-api': '' // 請求中去除/api
      }
    })
  )
}

搭建本地Mock服務

  1. 根目錄下建立mock資料夾,新建server.js檔案 ,這裡我使用express開啟一個node服務
const express = require('express')
const app = express()
const port = 3001

app.use(express.json())
app.use(express.urlencoded({ extended: false }))

app.get('/', (req, res) => {
  res.send('Hello World!')
})

// 載入路由
app.use('/api', require('./test'))

app.listen(port, () => {
  console.log(`mock server listening at http://localhost:${port}`)
})

  1. 介面路由,返回mock資料
var express = require('express')
var router = express.Router()
// http://mockjs.com/
var Mock = require('mockjs')

router.get('/hello', function (req, res) {
  res.json({ user: 'hello' })
})

router.get('/mock', function (req, res) {
  console.log(req.body)
  var data = Mock.mock({
    top_search: {
      'words|10': [
        {
          query: '一人之下',
          display_query: '《一人之下》565'
        }
      ]
    }
  })
  return res.json(data)
})


module.exports = router

  1. 訪問mock介面資料
"scripts": {
    "mock": "nodemon ./mock/server.js",
  },

我們在scripts下新增一個mock指令碼命令,執行yarn mock就能開啟mock服務,例如訪問上面介面http://localhost:3001/api/mock

文章最後

本文作者阿健Kerry,高階前端工程師,轉載請註明出處。如果覺得本文對你有幫助,記得點贊三連哦,也可以掃碼關注我新建立的前端技術公眾號【有你前端】,之後我所有文章會同步發到這個公眾號上面。另外,我建了一個可以幫助我們們程式設計師脫單的公眾號,每週都會推送幾個優秀的單身小姐姐,如果你是程式設計師技術好又正好是單身,那你可以下面掃碼關注【緣來你是程式猿】公眾號開啟你的脫單之旅。

相關文章