最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一步一步了解Monorepo各包間正確的通信方式

 更新時間:2026年04月07日 10:15:24   作者:在西安牧羊的牛油果  
Monorepo通過單一倉庫管理多項目,提升代碼復(fù)用與開發(fā)效率,這篇文章主要介紹了Monorepo各包間正確的通信方式,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下

概述

Monorepo(Monolithic Repository)指的是把多個包(項目)的代碼,統(tǒng)一放在同一個代碼倉庫里進(jìn)行管理的一種倉庫組織方式。適合多個項目強(qiáng)相關(guān)且有大量共享代碼的中大型項目。使用 Monorepo 管理項目的好處非常明顯,它不用發(fā) npm 包,不用來回同步版本,改完公共庫,所有項目立即可用,使得共享代碼更簡單。 Monorepo 是存放多個包的倉庫,包之間的通信方式至關(guān)重要,接下來我們以一個交易項目為例,一步一步了解 Monorepo 各包間正確的通信方式。

交易平臺項目簡述

該項目是一個給用戶提供股票交易服務(wù)的平臺。項目包括交易(Trade)、資產(chǎn)(Portfolios)、行情(Quotes)、市場(Market)等模塊。項目還有提供公共方法、UI、數(shù)據(jù)等公共模塊。

交易平臺各包之間的通信問題

包之間的依賴關(guān)系不合理

包之間出現(xiàn)循環(huán)依賴問題,業(yè)務(wù)包依賴業(yè)務(wù)包。

├── @repo/shared ←→ @repo/trade (循環(huán)依賴)
├── @repo/account → @repo/trade (不合理)
├── @repo/quote → @repo/trade (不合理)
├── @repo/portfolios → @repo/trade (不合理)
└── ...

封裝性破壞:直接訪問包內(nèi)部實現(xiàn)

直接導(dǎo)入其他包的內(nèi)部路徑

  // packages/shared/utils/order.ts
  import { EOrderVerify } from '@repo/trade/data';
  import { canFillSearch } from '@repo/trade/utils';
  // packages/shared/reports/modules/trade.ts
  import { ECondOrderVerifyParaKey } from '@pkg/trade/data/sensors';
  import { getIsEntrustType } from '@pkg/trade/utils/type';
  import { useIndexSession, useNightTradeSession } from '@repo/trade/utils/hooks';

緊耦合:直接依賴應(yīng)用層 stores

// packages/shared/utils/order.ts
import { useConfigStore } from '@/stores/config';
import { useMarketStore } from '@/stores/market.ts';
import { usePasswordStore } from '@/stores/password';
import { useTradeStore } from '@/stores/trade';
import { useUserStore } from '@/stores/user';
// packages/trade/utils/verify.ts
import { EStatementType } from '@/stores/quote-statement.ts';
// packages/portfolios/components/orders/index.vue
import { useMarketStore } from '@/stores/market';
import { useOrderStore } from '@/stores/order';

項目包間正確通信方式

一、依賴層次原則

1.1 依賴層次結(jié)構(gòu)

┌─────────────────────────────────────┐
│         apps/web (應(yīng)用層)            │
│  依賴所有業(yè)務(wù)包,負(fù)責(zé)組裝和路由      │
└─────────────────────────────────────┘
              │
              ├─────────────────────────────────────┐
              │                                     │
┌─────────────▼──────────────┐  ┌──────────────────▼──────────────┐
│   業(yè)務(wù)包 (Business)        │  │   基礎(chǔ)包 (Foundation)            │
│  - trade                   │  │  - shared (不依賴其他業(yè)務(wù)包)     │
│  - account                 │  │  - data-center                  │
│  - quote                   │  │  - ui                            │
│  - portfolios              │  │                                  │
│  - company                 │  │                                  │
│  - market                  │  │                                  │
│  - ...                     │  │                                  │
└────────────────────────────┘  └──────────────────────────────────┘

1.2 依賴規(guī)則

允許的依賴方向

  1. 應(yīng)用層 → 所有包
  2. 業(yè)務(wù)包 → 基礎(chǔ)包(shared, data-center, ui)
  3. 基礎(chǔ)包 → 只依賴更底層的基礎(chǔ)包或外部庫
  4. shared 包 → 不依賴任何業(yè)務(wù)包

 禁止的依賴方向

  1. 基礎(chǔ)包 → 業(yè)務(wù)包(如 shared → trade)
  2. 業(yè)務(wù)包 → 業(yè)務(wù)包(如 account → trade)
  3. 循環(huán)依賴(如 shared ↔ trade)

1.3 依賴層次示例

// ? 正確:業(yè)務(wù)包依賴基礎(chǔ)包
// packages/trade/package.json
{
  "dependencies": {
    "@repo/shared": "workspace: " ,
 "@repo/data-center" :  "workspace: ",
    "@repo/ui": "workspace:*"
  }
}
// ? 錯誤:基礎(chǔ)包依賴業(yè)務(wù)包
// packages/shared/package.json
{
  "dependencies": {
    "@repo/trade": "workspace:*"  // ? 不應(yīng)該依賴業(yè)務(wù)包
  }
}

二、通信模式

2.1 事件通信模式(Event Bus)

適用場景

  1. 包間的松耦合通信
  2. 一對多的通知場景
  3. 異步事件通知

實現(xiàn)方式

  1. 定義事件類型(在 shared 包中)
// packages/shared/events/index.ts
import mitt from 'mitt';
export const enum EEventBusType {
  ORDER_SUCCESS = 'orderSuccess',
  USER_LOGIN_SUCCESS = 'userLoginSuccess',
  // ...
}
export type TEvents = {
  [EEventBusType.ORDER_SUCCESS]?: {
    orderId: string;
    orderType: string;
  };
  [EEventBusType.USER_LOGIN_SUCCESS]?: unknown;
};
export const eventBus = mitt<TEvents>();
export default eventBus;
  1. 發(fā)送事件(在 trade 包中)
// packages/trade/order/index.vue
import eventBus, { EEventBusType } from '@repo/shared/events';
// 下單成功后發(fā)送事件
const handleOrderSuccess = () => {
  eventBus.emit(EEventBusType.ORDER_SUCCESS, {
    orderId: '123',
    orderType: 'limit'
  });
};
  1. 監(jiān)聽事件(在 portfolios 包中)
// packages/portfolios/components/orders/index.vue
import eventBus, { EEventBusType } from '@repo/shared/events';
import { onMounted, onUnmounted } from 'vue';
const orderChangeCallBack = (data: any) => {
  // 處理訂單變化
  refreshOrderList();
};
onMounted(() => {
  eventBus.on(EEventBusType.ORDER_SUCCESS, orderChangeCallBack);
});
onUnmounted(() => {
  eventBus.off(EEventBusType.ORDER_SUCCESS, orderChangeCallBack);
});

優(yōu)點

  1. 解耦:發(fā)送者和接收者不需要直接依賴
  2. 靈活:可以動態(tài)添加/移除監(jiān)聽器
  3. 支持一對多通信

注意事項

  1. 事件類型定義應(yīng)在 shared 包中,確保類型安全
  2. 及時清理事件監(jiān)聽器,避免內(nèi)存泄漏
  3. 事件名稱應(yīng)清晰明確,避免命名沖突

2.2 服務(wù)模式(Singleton Service)

適用場景

  1. 提供統(tǒng)一的數(shù)據(jù)訪問接口
  2. 跨包共享服務(wù)實例
  3. 需要單例模式的服務(wù)

實現(xiàn)方式

  1. 定義服務(wù)(在 data-center 包中)
// packages/data-center/core/index.ts
import { Singleton } from '@repo/shared/utils/singleton';
export class DataCenter extends Singleton {
  static tag = 'DataCenter';
  async getStockInfo(code: string) {
    // 獲取股票信息
  }
  async getQuotes(codes: string[]) {
    // 獲取行情數(shù)據(jù)
  }
}
// 2. 導(dǎo)出服務(wù)
export { DataCenter } from './core';
  1. 使用服務(wù)(在任何包中)
// packages/trade/utils/stock.ts
import { DataCenter } from '@repo/data-center';
const getStockData = async (code: string) => {
  const dataCenter = DataCenter.getInstance();
  return await dataCenter.getStockInfo(code);
};

優(yōu)點

  1. 統(tǒng)一接口:所有包通過相同的接口訪問服務(wù)
  2. 單例保證:確保全局只有一個實例
  3. 易于測試:可以 mock 服務(wù)接口

注意事項

  1. 服務(wù)接口應(yīng)穩(wěn)定,避免頻繁變更

  2. 服務(wù)應(yīng)在 shared 或 data-center 等基礎(chǔ)包中

  3. 避免在服務(wù)中直接依賴業(yè)務(wù)包

2.3 共享類型和接口

適用場景

  1. 包間傳遞數(shù)據(jù)
  2. 定義公共接口
  3. 類型約束

實現(xiàn)方式

  1. 定義共享類型(在 shared 包中)
// packages/shared/types/order.ts
export interface IOrderForm {
  stockCode: string;
  stockName: string;
  entrustType: EEntrustType;
  // ...
}
export interface IMaxAvailableAsset {
  cashAvailable: number;
  marginAvailable: number;
  // ...
}
  1. 使用共享類型(在 trade 包中)
// packages/trade/order/index.vue
import type { IOrderForm } from '@repo/shared/types/order';
const form: IOrderForm = {
  stockCode: 'AAPL',
  stockName: 'Apple Inc.',
  // ...
};
  1. 使用共享類型(在 portfolios 包中)
// packages/portfolios/components/orders/index.vue
import type { IOrderForm } from '@repo/shared/types/order';
const displayOrder = (order: IOrderForm) => {
  // 使用共享類型
};

優(yōu)點

  1. 類型安全:TypeScript 提供編譯時類型檢查
  2. 一致性:確保數(shù)據(jù)結(jié)構(gòu)一致
  3. 可維護(hù)性:類型定義集中管理

注意事項

  1. 共享類型應(yīng)在 shared 包中定義
  2. 避免在業(yè)務(wù)包中定義共享類型
  3. 類型定義應(yīng)向后兼容

2.4 公共 API 導(dǎo)出模式

適用場景

  1. 包需要對外暴露功能
  2. 隱藏內(nèi)部實現(xiàn)細(xì)節(jié)
  3. 提供穩(wěn)定的接口

實現(xiàn)方式

  1. 建立公共 API(在 trade 包中)
// packages/trade/index.ts
// 導(dǎo)出常量
export { EOrderVerify, EOrderErrorCode } from './data/constant';
// 導(dǎo)出工具函數(shù)
export { canFillSearch, getOpenAccountUrl } from './utils';
// 導(dǎo)出類型
export type { IOrderForm, IAttachedOrder } from './types';
// 導(dǎo)出組件(如果需要)
export { default as OrderPanel } from './order/index.vue';
  1. 使用公共API(在其他包中)
// ? 正確:通過公共API導(dǎo)入
import { getOpenAccountUrl } from '@repo/trade';
// ? 錯誤:直接訪問內(nèi)部實現(xiàn)
import { getOpenAccountUrl } from '@repo/trade/utils';

優(yōu)點

  1. 封裝性:隱藏內(nèi)部實現(xiàn)
  2. 穩(wěn)定性:公共API相對穩(wěn)定
  3. 可維護(hù)性:內(nèi)部重構(gòu)不影響外部使用

注意事項

  1. 每個包都應(yīng)建立 index.ts 作為公共 API 入口

  2. 只導(dǎo)出需要對外暴露的功能

  3. 避免導(dǎo)出內(nèi)部實現(xiàn)細(xì)節(jié)

2.5 依賴注入模式

適用場景

  1. 需要解耦 stores 依賴
  2. 提高可測試性
  3. 支持不同的實現(xiàn)

實現(xiàn)方式

  1. 定義接口(在 shared 包中)
// packages/shared/interfaces/stores.ts
export interface IUserStore {
  logined: boolean;
  customerInfo: any;
  goLogin: () => void;
}
export interface IConfigStore {
  urlsConfig: {
    acOpen: string;
  };
}
  1. 通過參數(shù)注入(在 shared 包中)
// packages/shared/utils/order.ts
import type { IUserStore, IConfigStore } from '@repo/shared/interfaces/stores';
export const preVerify = async (
  userStore: IUserStore,
  configStore: IConfigStore
) => {
  if (!userStore.logined) {
    userStore.goLogin();
    return false;
  }
  // ...
};
  1. 在應(yīng)用層注入依賴(在 apps/web 中)
// apps/web/src/views/trade/index.vue
import { preVerify } from '@repo/shared/utils/order';
import { useUserStore } from '@/stores/user';
import { useConfigStore } from '@/stores/config';
const userStore = useUserStore();
const configStore = useConfigStore();
const handlePreVerify = async () => {
  await preVerify(userStore, configStore);
};

優(yōu)點

  1. 解耦:包不直接依賴 stores
  2. 可測試:可以輕松 mock 依賴
  3. 靈活:支持不同的實現(xiàn)

注意事項

  1. 接口定義應(yīng)在 shared 包中

  2. 依賴注入會增加調(diào)用復(fù)雜度

  3. 適合復(fù)雜場景,簡單場景可直接使用

2.6 API Linker 模式

適用場景

  1. 通過 URL 參數(shù)調(diào)用 API
  2. 跨頁面通信
  3. 外部系統(tǒng)集成

實現(xiàn)方式

  1. 注冊 API(在 trade 包中)
// packages/trade/utils/api-linker.ts
import apiLinker from '@repo/shared/app/router/api-linker';
apiLinker.registerLinkerApi({
  openTradePanel: async (params: { stockCode: string }) => {
    // 打開交易面板
  },
  submitOrder: async (params: IOrderForm) => {
    // 提交訂單
  }
});
  1. 創(chuàng)建 API 鏈接(在其他包中)
// packages/company/components/stock-card/index.vue
import apiLinker from '@repo/shared/app/router/api-linker';
const openTrade = (stockCode: string) => {
  const url = apiLinker.createApiLink('/trade', {
    apiNames: ['openTradePanel'],
    apiOptions: {
      openTradePanel: { stockCode }
    }
  });
  window.open(url);
};

優(yōu)點

  1. 跨頁面通信
  2. 支持外部系統(tǒng)集成
  3. 解耦頁面間依賴

三、最佳實踐

3.1 包內(nèi)導(dǎo)入規(guī)則

正確:包內(nèi)使用相對路徑

// packages/trade/utils/verify.ts
import { EOrderVerify } from '../data/constant';
import { canFillSearch } from './common';
錯誤:包內(nèi)使用包名路徑
import { EOrderVerify } from '@repo/trade/data/constant';
// 討論:是否可以使用 @pkg/trade
import { EOrderVerify } from ' @pkg/trade/data/constant';

正確:跨包使用包名路徑

// packages/account/index.vue
import { getOpenAccountUrl } from '@repo/trade';
import { eventBus } from '@repo/shared/events';

3.2 類型定義規(guī)則

正確:共享類型在 shared 包中

// packages/shared/types/order.ts
export interface IOrderForm {
  // ...
}

正確:業(yè)務(wù)特定類型在業(yè)務(wù)包中

// packages/trade/types/condition.ts
export interface IConditionOrder {
  // ...
}

3.3 常量定義規(guī)則

正確:通用常量在 shared 包中

// packages/shared/constant/order.ts
export enum EEntrustType {
  LIMIT = 1,
  MARKET = 2,
}

正確:業(yè)務(wù)特定常量在業(yè)務(wù)包中

// packages/trade/data/constant.ts
export enum EOrderVerify {
  NOT_LOGIN = 'not_login',
  // ...
}

3.4 工具函數(shù)規(guī)則

正確:通用工具函數(shù)在 shared 包中

// packages/shared/utils/order.ts
export const isTrue = (flag: any) => {
  // 通用邏輯
};

正確:業(yè)務(wù)特定工具函數(shù)在業(yè)務(wù)包中

// packages/trade/utils/verify.ts
export const verifyOrder = (order: IOrderForm) => {
  // 業(yè)務(wù)特定邏輯
};

四、通信模式選擇指南

場景推薦模式示例
通知其他包某個事件發(fā)生事件通信訂單成功、登錄成功
獲取共享數(shù)據(jù)服務(wù)模式獲取股票信息、行情數(shù)據(jù)
傳遞數(shù)據(jù)共享類型訂單表單、用戶信息
調(diào)用其他包功能公共 API工具函數(shù)、組件
需要解耦 stores依賴注入驗證函數(shù)、工具函數(shù)
跨頁面通信API Linker打開交易面板

五、重構(gòu)建議

5.1 解決循環(huán)依賴

步驟1:識別共享內(nèi)容

// 找出 shared 包中使用的 trade 包內(nèi)容
// packages/shared/utils/order.ts
import { EOrderVerify } from '@repo/trade/data';  // 需要移到shared
import { canFillSearch } from '@repo/trade/utils'; // 需要移到shared

步驟2:遷移到 shared 包

// packages/shared/constant/order.ts
export enum EOrderVerify {
  NOT_LOGIN = 'not_login',
  // ...
}
// packages/shared/utils/order.ts
export const canFillSearch = async (params: any) => {
  // 實現(xiàn)邏輯
};

步驟3:更新引用

// packages/trade/utils/verify.ts
// 從 shared 包導(dǎo)入
import { EOrderVerify } from '@repo/shared/constant/order';
import { canFillSearch } from '@repo/shared/utils/order';

步驟4:移除依賴

// packages/shared/package.json
{
  "dependencies": {
    // 移除 "@repo/trade": "workspace:*"
  }

5.2 建立公共 API

步驟1:在各包的根目錄創(chuàng)建 index.ts

// packages/trade/index.ts
// 導(dǎo)出常量
export * from './data/constant';
// 導(dǎo)出工具函數(shù)
export { canFillSearch } from './utils/verify';
export { getOpenAccountUrl } from './utils/config';
// 導(dǎo)出類型
export type { IOrderForm } from './types';
// 導(dǎo)出組件(可選)
export { default as OrderPanel } from './order/index.vue';

步驟2:更新引用

// packages/account/index.vue (account 包)
// 其他包通過 trade 包的公共 API 訪問
import { getOpenAccountUrl } from '@repo/trade';

5.3 解耦 stores 依賴

步驟1:定義接口

// packages/shared/interfaces/stores.ts
export interface IUserStore {
  logined: boolean;
  customerInfo: any;
  goLogin: () => void;
}

步驟2:修改函數(shù)簽名

// packages/shared/utils/order.ts
import type { IUserStore } from '@repo/shared/interfaces/stores';
export const preVerify = async (userStore: IUserStore) => {
  if (!userStore.logined) {
    userStore.goLogin();
    return false;
  }
// ... 

步驟3:在應(yīng)用層注入

// apps/web/src/views/trade/index.vue
import { preVerify } from '@repo/shared/utils/order';
import { useUserStore } from '@/stores/user';
const userStore = useUserStore();
await preVerify(userStore);

六、檢查清單

在添加新的包間通信時,請檢查:

  • 是否遵循依賴層次原則?
  • 是否避免了循環(huán)依賴?
  • 是否使用了合適的通信模式?
  • 共享類型是否在 shared 包中?
  • 是否建立了公共 API?
  • 是否避免了直接訪問內(nèi)部實現(xiàn)?
  • 是否避免了直接依賴 stores?
  • 事件監(jiān)聽器是否及時清理?

七、總結(jié)

正確的包間通信應(yīng)該是:

  1. 遵循依賴層次:基礎(chǔ)包不依賴業(yè)務(wù)包

  2. 使用合適的通信模式:根據(jù)場景選擇事件、服務(wù)、類型等

  3. 建立公共 API:通過 index.ts 導(dǎo)出,隱藏內(nèi)部實現(xiàn)

  4. 共享類型和常量:在 shared 包中定義

  5. 解耦 stores:通過依賴注入或接口

  6. 及時清理資源:事件監(jiān)聽器等

遵循這些原則,可以確保包間的松耦合、高內(nèi)聚,提高代碼的可維護(hù)性和可測試性。

總結(jié)

到此這篇關(guān)于Monorepo各包間正確的通信方式的文章就介紹到這了,更多相關(guān)Monorepo包通信方式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

淳安县| 开封市| 衡水市| 榆树市| 安塞县| 庄浪县| 平度市| 涟源市| 平定县| 花莲市| 长春市| 永靖县| 密山市| 红原县| 乳山市| 宕昌县| 枣庄市| 阳城县| 班戈县| 如皋市| 凌云县| 宜兴市| 汝南县| 始兴县| 谢通门县| 武平县| 宁强县| 顺平县| 噶尔县| 宣恩县| 东丰县| 广河县| 扶绥县| 霸州市| 璧山县| 新宁县| 乐至县| 咸丰县| 海宁市| 宜宾市| 阿城市|