微前端(wujie)源码解析-3.wujie-vue

wujie-vue2源码解析

前言

在前面的文章中,我们对无界的使用方式和整体架构进行了分析,wujie-vue2、wujie-vue3、wujie-react作为无界架构中的重要一环,起到了桥梁的作用,对不同框架做了适配,今天我们就来分析一下wujie-vue2的源码,看看它是如何实现的

整体架构

当我们使用无界时,通常是这样使用的:

vue 复制代码
<WujieVue width="100%" height="100%" name="vue2" :url="'//localhost:7200/'" :sync="true"></WujieVue>

wujie-vue2的整体架构如下图所示:

wujie-vue2依赖wujie,并且以插件的形式暴露出一个组件,这样我们在开发的时候就可以使用这个组件了

目录结构

我们先来看下wujie-vue2的目录结构

lua 复制代码
├── package.json
├── webpack.config.js
├── index.js

还有一些其他的文件,这里就不一一列举了,我们主要看下index.js文件,这个文件是wujie-vue2的入口文件。

核心代码

我们首先看下wujie-vue2的入口文件index.js的输入输出

js 复制代码
import Vue from "vue";
import { bus, preloadApp, startApp as rawStartApp, destroyApp, setupApp } from "wujie";

const wujieVueOptions = {
 // code...
};

const WujieVue = Vue.extend(wujieVueOptions);

WujieVue.setupApp = setupApp;
WujieVue.preloadApp = preloadApp;
WujieVue.bus = bus;
WujieVue.destroyApp = destroyApp;
WujieVue.install = function (Vue) {
Vue.component("WujieVue", WujieVue);
};

export default WujieVue;

这段代码比较简单,我们来分析下:

  1. 首先我得依赖了vue以及wujie
  2. 定义了一个wujieVueOptions对象,这个对象是wujie-vue2的配置项,我们后面会详细分析
  3. 通过Vue.extend方法创建了一个WujieVue组件,这个组件就是我们在开发的时候使用的组件
  4. WujieVue组件上挂载了一些方法,包括注册组件、预加载、事件通信、销毁
  5. 最后挂载了一个install方法,这个方法我们比较熟悉,就是vue插件的安装方法,让后将WujieVue暴露出去

现在我们分析下wujie-vue2的配置项wujieVueOptions

js 复制代码
const wujieVueOptions = {
    name: "WujieVue",
    props: {
       width: { type: String, default: "" },
       height: { type: String, default: "" },
       name: { type: String, default: "" },
       loading: { type: HTMLElement, default: undefined },
       url: { type: String, default: "" },
       sync: { type: Boolean, default: undefined },
       prefix: { type: Object, default: undefined },
       alive: { type: Boolean, default: undefined },
       props: { type: Object, default: undefined },
       attrs: {type: Object, default: undefined},
       replace: { type: Function, default: undefined },
       fetch: { type: Function, default: undefined },
       fiber: { type: Boolean, default: undefined },
       degrade: { type: Boolean, default: undefined },
       plugins: { type: Array, default: null },
       beforeLoad: { type: Function, default: null },
       beforeMount: { type: Function, default: null },
       afterMount: { type: Function, default: null },
       beforeUnmount: { type: Function, default: null },
       afterUnmount: { type: Function, default: null },
       activated: { type: Function, default: null },
       deactivated: { type: Function, default: null },
       loadError: { type: Function, default: null },
    },
    data() {
       return {
          startAppQueue: Promise.resolve(),
       };
    },
    mounted() {
       bus.$onAll(this.handleEmit);
       this.execStartApp();
       this.$watch(
          () => this.name + this.url,
          () => this.execStartApp()
       );
    },
    methods: {
       handleEmit(event, ...args) {
          this.$emit(event, ...args);
       },
       async startApp() {
          try {
             // $props 是vue 2.2版本才有的属性,所以这里直接全部写一遍
             await rawStartApp({
                name: this.name,
                url: this.url,
                el: this.$refs.wujie,
                loading: this.loading,
                alive: this.alive,
                fetch: this.fetch,
                props: this.props,
                attrs: this.attrs,
                replace: this.replace,
                sync: this.sync,
                prefix: this.prefix,
                fiber: this.fiber,
                degrade: this.degrade,
                plugins: this.plugins,
                beforeLoad: this.beforeLoad,
                beforeMount: this.beforeMount,
                afterMount: this.afterMount,
                beforeUnmount: this.beforeUnmount,
                afterUnmount: this.afterUnmount,
                activated: this.activated,
                deactivated: this.deactivated,
                loadError: this.loadError,
             });
          } catch (error) {
             console.log(error);
          }
       },
       execStartApp() {
          this.startAppQueue = this.startAppQueue.then(this.startApp);
       },
       destroy() {
          destroyApp(this.name);
       },
    },
    beforeDestroy() {
       bus.$offAll(this.handleEmit);
    },
    render(c) {
       return c("div", {
          style: {
             width: this.width,
             height: this.height,
          },
          ref: "wujie",
       });
    },
};

整体上看,这个配置项就是一个vue组件的配置项,我们在开发的时候,可以通过这些配置项来配置我们的组件

我们还是以上文提到的例子为入手点,从组件实际使用时的生命周期的角度来分析下:

  1. 当我们使用该组件的时候,props会传入一些参数,例如:width、height、name、url等等,这几个参数都比较好理解,width、height是组件的宽高,name是组件的名称,url是组件的地址
  2. render函数会渲染一个div,这个div的宽高就是我们传入的width和height,这个div的ref是wujie
  3. 当组件挂载到页面上的时候,会执行mounted钩子函数,这个钩子函数中,做了三件事情:
    1. 监听了bus的所有事件,当bus触发事件的时候,会执行handleEmit方法,这个方法会将bus的事件转化为vue的事件,然后触发vue的事件
    2. 执行了execStartApp方法,这个方法会执行startApp方法,继而会执行rawStartApp方法,这个方法是重点,我们以后会分析,这个函数最终会渲染一个子应用
    3. 添加watch监听了nameurl的变化,当nameurl发生变化的时候,会重新执行execStartApp方法,完成组件的重新渲染
  4. 当组件销毁的时候,会执行beforeDestroy钩子函数,钩子函数会移除bus的所有事件监听

总结

wujie-vue2的源码简单清晰,主要是对wujie的封装,最终暴露出一个我们大家都认识的组件,我们在开发的时候,只需要像正常使用一个组件一样使用它就可以了,非常方便。在wujie-vue3,wujie-react中,也是类似的封装逻辑,大家有兴趣可以自行了解。

下期预告:我们将开始分析wujie-core的源码,敬请期待。

今天的分享就到这里,感谢大家的阅读,如果大家喜欢我的文章,可以给个star,你们的支持是我写作的最大动力,谢谢大家!

相关推荐
恋猫de小郭34 分钟前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅7 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60618 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅8 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅9 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment9 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅9 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊9 小时前
jwt介绍
前端