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

项目示例:

相关文章
相关标签/搜索