Vesselize - 一個能夠與 Vue.js 及 React 無縫集成的 JavaScript IoC 容器

筆者目前是一個 Vue.js 和 React 都在用的前端打工人,像 Vue Composition API 和 React Hooks 這些技術真的是拯救人生啊,感受前端的開發體驗愈來愈像絲綢般順滑。html

另外一方面呢,因爲目前的項目裏面有着很是複雜的數據處理邏輯,因此咱們封裝了不少可複用的 Service 類。可是有一點不太方便的是,必須在業務組件或者 Service 裏面手動建立它們所依賴的 Service 實例。受 Angular、Nest 以及 Spring 這些框架的啓發,開始嘗試在 Vue.js 和 React 應用中經過依賴注入的方式解決這個問題。前端

Vesselize (文檔:vesselize.js.org)就是筆者最近業餘時間寫的一個 JavaScript IoC 容器,目前已經在項目中正式使用。能夠直接在 Vue.js 或 React 應用中,直接經過相似 useInstance('ServiceName') 的 API 來解決對服務實例的依賴。此次造輪子的過程當中學到了很多新知識,分享出來但願對你們有所幫助。vue

下面的內容是它的基本概念級入門指南。react

Vesselize 核心概念

Providers

Provider 一般是能夠被實例化的 JavaScript 構造器函數,此外也能夠是任意的工廠方法及已經聲明好的值。它們會被註冊到容器裏面,用於依賴注入及查找。git

Container

Container 的職責是用於初始化實例並解決他們的依賴關係。github

Context

默認狀況下,容器建立的實例都是單例的。經過指定一個 Context 對象,咱們能夠建立一個跟該上下文綁定的實例。vue-router

Vue.js 應用集成 Vesselize 入門指南

下面咱們經過代碼的形式展現如何在 Vue.js 應用中集成 Vesselize。npm

安裝

yarn add @vesselize/vue
# OR
npm i @vesselize/vue
複製代碼

建立 Providers

假設應用中須要如下三個服務:json

  • UserAPI 用於請求接口數據
  • UserService 調用 UserAPI 獲取數據並進行業務邏輯的處理
  • AuthService 用於判斷用戶的角色,好比是否爲管理員
// file: api/UserAPI.js
class UserAPI {
  async fetchUser(id) {
    return fetch(`/path/to/user/${id}`).then(res => res.json());
  }
}

// file: services/UserService.js
class UserService {
  userAPI = null;

  async getUser(id) {
    const user = await this.userAPI.fetchUser(id);
        
    // 數據處理邏輯...
        
    return user;
  }
    
    // 經過 Vesselize 容器注入 userAPI 實例
  setVesselize(vesselize) {
    this.userAPI = vesselize.get('UserAPI');
  }
}

// file: services/AuthService.js
class AuthService {
  constructor(maxAdminUserId) {
    this.maxAdminUserId = maxAdminUserId;
  }

  isAdmin(user) {
    return user.id <= this.maxAdminUserId;
  }
}
複製代碼

建立 VueVesselize 插件

下面的代碼經過 createVesselize 方法建立 Vue.js 插件,同時它也是一個容器實例。api

import { createVesselize } from '@vesselize/vue';
import UserAPI from './api/UserAPI';
import UserService from './services/UserService';
import RoleAuthService from './services/RoleAuthService';

const vesselize = createVesselize({
  providers: [
    {
      token: 'UserAPI',
      useClass: UserAPI
    },
    {
      token: 'UserService',
      useClass: UserService
    },
    {
      token: 'AuthService',
      useFactory() {
        const maxAdminUserId = 1;

        return new AuthService(maxAdminUserId);
      }
    }
  ]
});
複製代碼

註冊 VueVesselize 插件

import { createApp } from 'vue';
import router from './router';
import store from './store';
import vesselize from './vesselize';
import App from './App.vue';

const app = createApp(App)
  .use(store)
  .use(router)
  .use(vesselize);

app.mount('#app');
複製代碼

在組件中獲取服務實例

經過 useInstance 這個 Composition API,咱們能夠在組件中很方便地獲取組件實例。

<template>
  <div>Profile</div>
  <p>{{ JSON.stringify(user) }}</p>
  <p>Role: {{ isAdmin ? 'Administrator' : 'User' }}</p>
</template>

<script> import { computed, ref, watchEffect } from 'vue';
import { useRoute } from 'vue-router';
import { useInstance } from '@vesselize/vue';

export default {
  setup() {
    const route = useRoute();
    const userId = computed(() => route.params.id);
    const user = ref({});
    const isAdmin = ref(false);
    // 經過 Vue Composition API 獲取組件實例
    const userService = useInstance('UserService');
    const authService = useInstance('AuthService');

    watchEffect(() => {
      if (userId.value) {
        userService.getUser(userId.value).then((data) => {
          user.value = data;
          isAdmin.value = authService.isAdmin(data);
        });
      }
    });

    return {
      user,
      isAdmin,
    };
  },
}; </script>
複製代碼

最後,若是你想直接在項目中嘗試,能夠看一下這個示例項目:vesselize-vue-starter.

React 應用集成 Vesselize 入門指南

仍是上面的例子,咱們看一下如何在 React 中實現。

安裝

yarn add @vesselize/react
# OR
npm i @vesselize/react
複製代碼

建立 Providers

與上面同樣也是須要 UserAPI, UserService, AuthService 三個服務。

組合 Providers

咱們先將全部的 Provider 組合爲一個數組:

import UserAPI from './api/UserAPI';
import UserService from './services/UserService';
import RoleAuthService from './services/RoleAuthService';

const providers = [
  {
    token: 'UserAPI',
    useClass: UserAPI
  },
  {
    token: 'UserService',
    useClass: UserService
  },
  {
    token: 'AuthService',
    useFactory() {
      const maxAdminUserId = 1;

      return new AuthService(maxAdminUserId);
    }
  }
];

export default providers;
複製代碼

添加組件 VesselizeProvider

經過 Vesselize 提供的 VesselizeProvider 來包裹項目的 App 組件,同時傳入組合好的全部 Provider。

import { VesselizeProvider } from '@vesselize/react';
import providers from './providers';
import UserProfile from './components/UserProfile';

function App() {
  return (
    <VesselizeProvider providers={providers}>
      <UserProfile />
    </VesselizeProvider>
  );
}

export default App;
複製代碼

在組件中獲取服務實例

經過 useInstance 這個 hook, 能夠很是便捷地獲取到服務實例。

import { useParams }  from 'react-router-dom'
import { useState, useEffect } from 'react';
import { useInstance } from '@vesselize/react';

function UserProfile() {
  const { id } = useParams();
  const [user, setUser] = useState({});
  const [isAdmin, setIsAdmin] = useState(false);
  // 經過 hook 獲取組件實例
  const userService = useInstance('UserService');
  const authService = useInstance('AuthService');

  useEffect(() => {
    userService.getUser(id).then((data) => {
      setUser(data);
      setIsAdmin(authService.isAdmin(data));
    });
  }, [id, userService, authService]);

  return (
    <div>
      <span>{JSON.stringify(user)}</span>
      <p>Role: {isAdmin ? 'Administrator' : 'User'}</p>
    </div>
  );
}

export default UserProfile;
複製代碼

最後,若是你想直接在項目中嘗試,能夠看一下這個經過 create-react-app 建立的示例項目: vesselize-react-starter.

寫在最後

在創造 Vesselize 的過程當中,我學習到了不少東西。本文將它分享出來,也但願對你有所幫助。

感謝你的閱讀,祝你生活愉快!

附錄

Github 代碼倉庫: github.com/vesselize

文檔及使用指南: vesselize.js.org

項目示例:

相關文章
相關標籤/搜索