0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

基于vite3的monorepo前端工程搭建步驟

OSC開源社區(qū) ? 來源:OSCHINA 社區(qū) ? 2023-06-09 10:21 ? 次閱讀

一、技術(shù)棧選擇

1. 代碼庫管理方式 - Monorepo:將多個項目存放在同一個代碼庫中

a44a3d48-05f0-11ee-962d-dac502259ad0.png

選擇理由

1:多個應(yīng)用(可以按業(yè)務(wù)線產(chǎn)品粒度劃分)在同一個 repo 管理,便于統(tǒng)一管理代碼規(guī)范、共享工作流 選擇理由

2:解決跨項目 / 應(yīng)用之間物理層面的代碼復用,不用通過發(fā)布 / 安裝 npm 包解決共享問題

2. 依賴管理 - PNPM:消除依賴提升、規(guī)范拓撲結(jié)構(gòu)

選擇理由 1:通過軟 / 硬鏈接方式,最大程度節(jié)省磁盤空間 選擇理由 2:解決幽靈依賴問題,管理更清晰

3. 構(gòu)建工具 - Vite:基于 ESM 和 Rollup 的構(gòu)建工具

選擇理由:省去本地開發(fā)時的編譯過程,提升本地開發(fā)效率

4. 前端框架 - Vue3:Composition API

選擇理由:除了組件復用之外,還可以復用一些共同的邏輯狀態(tài),比如請求接口 loading 與結(jié)果的邏輯

5. 模擬接口返回數(shù)據(jù) - Mockjs

選擇理由:前后端統(tǒng)一了數(shù)據(jù)結(jié)構(gòu)后,即可分離開發(fā),降低前端開發(fā)依賴,縮短開發(fā)周期

二、目錄結(jié)構(gòu)設(shè)計:重點關(guān)注 src 部分

1. 常規(guī) / 簡單模式:根據(jù)文件功能類型集中管理

```
mesh-fe
├── .husky                  #git提交代碼觸發(fā)
│   ├── commit-msg            
│   └── pre-commit                  
├── mesh-server             #依賴的node服務(wù)
│   ├── mock   
│   │   └── data-service   #mock接口返回結(jié)果 
│   └── package.json
├── README.md
├── package.json
├── pnpm-workspace.yaml     #PNPM工作空間
├── .eslintignore           #排除eslint檢查
├── .eslintrc.js            #eslint配置
├── .gitignore
├── .stylelintignore        #排除stylelint檢查
├── stylelint.config.js     #style樣式規(guī)范
├── commitlint.config.js    #git提交信息規(guī)范
├── prettier.config.js      #格式化配置
├── index.html              #入口頁面
└── mesh-client #不同的web應(yīng)用package
    ├── vite-vue3 
        ├── src
            ├── api                 #api調(diào)用接口層
            ├── assets              #靜態(tài)資源相關(guān)
            ├── components          #公共組件
            ├── config              #公共配置,如字典/枚舉等
            ├── hooks               #邏輯復用
            ├── layout              #router中使用的父布局組件
            ├── router              #路由配置
            ├── stores              #pinia全局狀態(tài)管理
            ├── types               #ts類型聲明
            ├── utils
            │   ├── index.ts        
            │   └── request.js     #Axios接口請求封裝
            ├── views               #主要頁面
            ├── main.ts             #js入口
            └── App.vue
```

2. 基于 domain 領(lǐng)域模式:根據(jù)業(yè)務(wù)模塊集中管理

```
mesh-fe
├── .husky                  #git提交代碼觸發(fā)
│   ├── commit-msg            
│   └── pre-commit                  
├── mesh-server             #依賴的node服務(wù)
│   ├── mock   
│   │   └── data-service   #mock接口返回結(jié)果 
│   └── package.json
├── README.md
├── package.json
├── pnpm-workspace.yaml     #PNPM工作空間
├── .eslintignore           #排除eslint檢查
├── .eslintrc.js            #eslint配置
├── .gitignore
├── .stylelintignore        #排除stylelint檢查
├── stylelint.config.js     #style樣式規(guī)范
├── commitlint.config.js    #git提交信息規(guī)范
├── prettier.config.js      #格式化配置
├── index.html              #入口頁面
└── mesh-client             #不同的web應(yīng)用package
    ├── vite-vue3 
        ├── src                    #按業(yè)務(wù)領(lǐng)域劃分
            ├── assets              #靜態(tài)資源相關(guān)
            ├── components          #公共組件
            ├── domain              #領(lǐng)域
            │   ├── config.ts
            │   ├── service.ts 
            │   ├── store.ts        
            │   ├── type.ts                       
            ├── hooks               #邏輯復用
            ├── layout              #router中使用的父布局組件
            ├── router              #路由配置
            ├── utils
            │   ├── index.ts        
            │   └── request.js     #Axios接口請求封裝
            ├── views               #主要頁面
            ├── main.ts             #js入口
            └── App.vue
```
可以根據(jù)具體業(yè)務(wù)場景,選擇以上 2 種方式其中之一。

三、搭建部分細節(jié)

1.Monorepo+PNPM 集中管理多個應(yīng)用(workspace)

根目錄創(chuàng)建 pnpm-workspace.yaml,mesh-client 文件夾下每個應(yīng)用都是一個 package,之間可以相互添加本地依賴:pnpm install

packages:
  # all packages in direct subdirs of packages/
  - 'mesh-client/*'
  # exclude packages that are inside test directories
  - '!**/test/**'
pnpm install #安裝所有package中的依賴 pnpm install -w axios #將axios庫安裝到根目錄 pnpm --filter | -F #執(zhí)行某個package下的命令 與 NPM 安裝的一些區(qū)別: 所有依賴都會安裝到根目錄 node_modules/.pnpm 下; package 中 packages.json 中下不會顯示幽靈依賴(比如 tslib@types/webpack-dev),需要顯式安裝,否則報錯 安裝的包首先會從當前 workspace 中查找,如果有存在則 node_modules 創(chuàng)建軟連接指向本地 workspace "mock": "workspace:^1.0.0"

2.Vue3 請求接口相關(guān)封裝

request.ts 封裝:主要是對接口請求和返回做攔截處理,重寫 get/post 方法支持泛型

import axios, { AxiosError } from 'axios'
import type { AxiosRequestConfig, AxiosResponse } from 'axios'

// 創(chuàng)建 axios 實例
const service = axios.create({
  baseURL: import.meta.env.VITE_APP_BASE_URL,
  timeout: 1000 * 60 * 5, // 請求超時時間
  headers: { 'Content-Type': 'application/json;charset=UTF-8' },
})

const toLogin = (sso: string) => {
  const cur = window.location.href
  const url = `${sso}${encodeURIComponent(cur)}`
  window.location.href = url
}

// 服務(wù)器狀態(tài)碼錯誤處理
const handleError = (error: AxiosError) => {
  if (error.response) {
    switch (error.response.status) {
      case 401:
        // todo
        toLogin(import.meta.env.VITE_APP_SSO)
        break
      // case 404:
      //   router.push('/404')
      //   break
      // case 500:
      //   router.push('/500')
      //   break
      default:
        break
    }
  }
  return Promise.reject(error)
}

// request interceptor
service.interceptors.request.use((config) => {
  const token = ''
  if (token) {
    config.headers!['Access-Token'] = token // 讓每個請求攜帶自定義 token 請根據(jù)實際情況自行修改
  }
  return config
}, handleError)

// response interceptor
service.interceptors.response.use((response: AxiosResponse) => {
  const { code } = response.data
  if (code === '10000') {
    toLogin(import.meta.env.VITE_APP_SSO)
  } else if (code !== '00000') {
    // 拋出錯誤信息,頁面處理
    return Promise.reject(response.data)
  }
  // 返回正確數(shù)據(jù)
  return Promise.resolve(response)
  // return response
}, handleError)

// 后端返回數(shù)據(jù)結(jié)構(gòu)泛型,根據(jù)實際項目調(diào)整
interface ResponseData {
  code: string
  message: string
  result: T
}

export const httpGet = async (url: string, config?: AxiosRequestConfig) => {
  return service.get>(url, config).then((res) => res.data)
}

export const httpPost = async (
  url: string,
  data?: D,
  config?: AxiosRequestConfig,
) => {
  return service.post>(url, data, config).then((res) => res.data)
}

export { service as axios }

export type { ResponseData }
useRequest.ts 封裝:基于 vue3 Composition API,將請求參數(shù)、狀態(tài)以及結(jié)果等邏輯封裝復用
import { ref } from 'vue'
import type { Ref } from 'vue'
import { ElMessage } from 'element-plus'
import type { ResponseData } from '@/utils/request'
export const useRequest = (
  api: (...args: P[]) => Promise>,
  defaultParams?: P,
) => {
  const params = ref

() as Ref

if (defaultParams) { params.value = { ...defaultParams, } } const loading = ref(false) const result = ref() const fetchResource = async (...args: P[]) => { loading.value = true return api(...args) .then((res) => { if (!res?.result) return result.value = res.result }) .catch((err) => { result.value = undefined ElMessage({ message: typeof err === 'string' ? err : err?.message || 'error', type: 'error', offset: 80, }) }) .finally(() => { loading.value = false }) } return { params, loading, result, fetchResource, } }

API 接口層
import { httpGet } from '@/utils/request'

const API = {
  getLoginUserInfo: '/userInfo/getLoginUserInfo',
}
type UserInfo = {
  userName: string
  realName: string
}
export const getLoginUserInfoAPI = () => httpGet(API.getLoginUserInfo)
頁面使用:接口返回結(jié)果 userInfo,可以自動推斷出 UserInfo 類型,
// 方式一:推薦
const {
  loading,
  result: userInfo,
  fetchResource: getLoginUserInfo,
} = useRequest(getLoginUserInfoAPI)

// 方式二:不推薦,每次使用接口時都需要重復定義type
type UserInfo = {
  userName: string
  realName: string
}
const {
  loading,
  result: userInfo,
  fetchResource: getLoginUserInfo,
} = useRequest(getLoginUserInfoAPI)

onMounted(async () => {
  await getLoginUserInfo()
  if (!userInfo.value) return
  const user = useUserStore()
  user.$patch({
    userName: userInfo.value.userName,
    realName: userInfo.value.realName,
  })
})
3.Mockjs 模擬后端接口返回數(shù)據(jù)
import Mock from 'mockjs'
const BASE_URL = '/api'
Mock.mock(`${BASE_URL}/user/list`, {
  code: '00000',
  message: '成功',
  'result|10-20': [
    {
      uuid: '@guid',
      name: '@name',
      tag: '@title',
      age: '@integer(18, 35)',
      modifiedTime: '@datetime',
      status: '@cword("01")',
    },
  ],
})
四、統(tǒng)一規(guī)范

1.ESLint

注意:不同框架下,所需要的 preset 或 plugin 不同,建議將公共部分提取并配置在根目錄中,package 中的 eslint 配置設(shè)置 extends。

/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')

module.exports = {
  root: true,
  extends: [
    'plugin:vue/vue3-essential',
    'eslint:recommended',
    '@vue/eslint-config-typescript',
    '@vue/eslint-config-prettier',
  ],
  overrides: [
    {
      files: ['cypress/e2e/**.{cy,spec}.{js,ts,jsx,tsx}'],
      extends: ['plugin:cypress/recommended'],
    },
  ],
  parserOptions: {
    ecmaVersion: 'latest',
  },
  rules: {
    'vue/no-deprecated-slot-attribute': 'off',
  },
}

2.StyleLint

module.exports = {
  extends: ['stylelint-config-standard', 'stylelint-config-prettier'],
  plugins: ['stylelint-order'],
  customSyntax: 'postcss-html',
  rules: {
    indentation: 2, //4空格
    'selector-class-pattern':
      '^(?:(?:o|c|u|t|s|is|has|_|js|qa)-)?[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*(?:__[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*)?(?:--[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*)?(?:[.+])?$',
    // at-rule-no-unknown: 屏蔽一些scss等語法檢查
    'at-rule-no-unknown': [true, { ignoreAtRules: ['mixin', 'extend', 'content', 'export'] }],
    // css-next :global
    'selector-pseudo-class-no-unknown': [
      true,
      {
        ignorePseudoClasses: ['global', 'deep'],
      },
    ],
    'order/order': ['custom-properties', 'declarations'],
    'order/properties-alphabetical-order': true,
  },
}

3.Prettier

module.exports = {
  printWidth: 100,
  singleQuote: true,
  trailingComma: 'all',
  bracketSpacing: true,
  jsxBracketSameLine: false,
  tabWidth: 2,
  semi: false,
}

4.CommitLint

module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [
      2,
      'always',
      ['build', 'feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore', 'revert'],
    ],
    'subject-full-stop': [0, 'never'],
    'subject-case': [0, 'never'],
  },
}
五、附錄:技術(shù)棧圖譜

a487d162-05f0-11ee-962d-dac502259ad0.png





審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • ESM
    ESM
    +關(guān)注

    關(guān)注

    0

    文章

    9

    瀏覽量

    9064
  • SRC
    SRC
    +關(guān)注

    關(guān)注

    0

    文章

    61

    瀏覽量

    18022

原文標題:基于vite3的monorepo前端工程搭建

文章出處:【微信號:OSC開源社區(qū),微信公眾號:OSC開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    前端工程師月薪15000元福利好[1-3年經(jīng)驗]

    崗位職責:1、負責公司軟件產(chǎn)品的web前端開發(fā)工作;2、將設(shè)計效果圖進行切圖和div+css重構(gòu);3、負責軟件產(chǎn)品前端架構(gòu)的設(shè)計和搭建,編寫javascript界面交互程序;4、參與
    發(fā)表于 09-30 16:40

    設(shè)計模擬前端需要遵循哪些步驟?

    設(shè)計模擬前端需要遵循哪些步驟?如何設(shè)計一個增益模塊和ADC組合?
    發(fā)表于 04-07 06:04

    關(guān)于虛擬儀器測試環(huán)境VITE的分析

    VITE標準體系結(jié)構(gòu)分析VITE實現(xiàn)體系結(jié)構(gòu)VITE核心信息模型結(jié)構(gòu)
    發(fā)表于 05-12 06:31

    Android 開發(fā)環(huán)境搭建步驟詳細圖解

    Android 開發(fā)環(huán)境搭建步驟詳細圖解
    發(fā)表于 10-24 08:49 ?11次下載
    Android 開發(fā)環(huán)境<b class='flag-5'>搭建</b><b class='flag-5'>步驟</b>詳細圖解

    Monkey測試環(huán)境搭建步驟詳解

    本文全面介紹了Monkey測試環(huán)境搭建步驟
    的頭像 發(fā)表于 01-31 18:47 ?8735次閱讀

    如何搭建寄存器的工程環(huán)境詳細方法步驟說明

    本文檔的主要內(nèi)容詳細介紹的是如何搭建寄存器的工程環(huán)境詳細方法步驟說明。
    發(fā)表于 09-19 08:00 ?0次下載
    如何<b class='flag-5'>搭建</b>寄存器的<b class='flag-5'>工程</b>環(huán)境詳細方法<b class='flag-5'>步驟</b>說明

    物聯(lián)網(wǎng)LoRa系列-3:LoRa終端搭建的總體思路、步驟與架構(gòu)

    搭建的LoRa終端的總體思路與步驟:1. 搭建的LoRa終端的系統(tǒng)需求和目標2. 設(shè)計LoRa終端的目標系統(tǒng)3. 設(shè)計LoRa終端的主機開發(fā)環(huán)境4. 設(shè)計LoRa終端的軟件架構(gòu)5. 構(gòu)
    發(fā)表于 12-07 14:06 ?26次下載
    物聯(lián)網(wǎng)LoRa系列-<b class='flag-5'>3</b>:LoRa終端<b class='flag-5'>搭建</b>的總體思路、<b class='flag-5'>步驟</b>與架構(gòu)

    Go Vite通用的去中心化應(yīng)用平臺

    go-vite.zip
    發(fā)表于 04-22 10:59 ?1次下載
    Go <b class='flag-5'>Vite</b>通用的去中心化應(yīng)用平臺

    搭建基于Vue3+Vite2+Arco+Typescript+Pinia后臺管理系統(tǒng)模板

    今天我們就來快速搭建一個基于Vue3+Vite2+Arco+Typescript+Pinia后臺管理系統(tǒng)模板。這樣可以幫大家快速制作自己的后臺模板
    的頭像 發(fā)表于 03-01 10:09 ?808次閱讀
    <b class='flag-5'>搭建</b>基于Vue<b class='flag-5'>3+Vite</b>2+Arco+Typescript+Pinia后臺管理系統(tǒng)模板

    Vite 4.3正式發(fā)布,前端構(gòu)建工具

    最新發(fā)布的 Vite 4.3 顯著提升了性能。發(fā)布公告寫道,Vite 團隊在這個版本中將工作重心放在提升開發(fā)服務(wù)器的性能上,其中包括簡化解析邏輯、改進熱路徑、實現(xiàn)更智能的緩存以查找 package.json,TS 配置文件和解析的 URL。
    的頭像 發(fā)表于 04-26 14:23 ?1018次閱讀
    <b class='flag-5'>Vite</b> 4.3正式發(fā)布,<b class='flag-5'>前端</b>構(gòu)建工具

    ViteConf 2023:Vite即將Rust化挑戰(zhàn)

    ViteConf 干貨滿滿,尤大的分享中最值得關(guān)注的就要數(shù) Rolldown 了,它為 Vite 現(xiàn)有痛點提供了新的解決方案。
    的頭像 發(fā)表于 10-07 10:28 ?2033次閱讀
    ViteConf 2023:<b class='flag-5'>Vite</b>即將Rust化挑戰(zhàn)

    Vite 5正式發(fā)布,性能大幅提升

    公告指出,Vite 5 的重點是清理 API(刪除已棄用的功能),并精簡了幾個功能以解決長期存在的問題。例如,將 define 轉(zhuǎn)換為使用正確的 AST 替換,而不是使用 regexes。項目團隊表示,他們將繼續(xù)推進實現(xiàn)面向未來的 Vite。
    的頭像 發(fā)表于 11-20 16:20 ?1147次閱讀

    芯片設(shè)計分為哪些步驟?為什么要分前端后端?前端后端是什么意思

    芯片設(shè)計分為哪些步驟?為什么要分為前端后端?前端后端分別是什么意思? 芯片設(shè)計分為前端和后端兩個主要步驟
    的頭像 發(fā)表于 12-07 14:31 ?4005次閱讀

     海外云服務(wù)器搭建pi節(jié)點詳細步驟

     海外云服務(wù)器搭建pi節(jié)點簡單嗎?海外云服務(wù)器搭建pi節(jié)點步驟有哪些?小編為您整理發(fā)布海外云服務(wù)器搭建pi節(jié)點相關(guān)內(nèi)容。
    的頭像 發(fā)表于 02-21 10:16 ?1170次閱讀

    如何搭建3d數(shù)字孿生平臺

    以及部署與維護等關(guān)鍵步驟。在技術(shù)方面,您需要考慮使用三維建模軟件、數(shù)據(jù)庫管理系統(tǒng)、數(shù)據(jù)分析工具、虛擬現(xiàn)實技術(shù)、物聯(lián)網(wǎng)技術(shù)以及前端開發(fā)技術(shù)等來構(gòu)建功能全面的3D數(shù)字孿生平臺。 搭建
    的頭像 發(fā)表于 07-04 15:23 ?427次閱讀