浅尝微前端(无界)

1、基本使用

vue3项目作为父应用

// 下载wujie
// npm install wujie-vue3
// 引入
import WujieVue from 'wujie-vue3'
// ...
// 使用插件
app.use(WujieVue)

const { setupApp, preloadApp } = WujieVue

// 注册子应用
setupApp({
  name: 'react-app',  // 子应用名称
  url: 'http://127.0.0.1:3000/', // 子应用项目地址
  alive: true,  // 是否开启保活模式
})

setupApp({
  name: 'vue-app',
  url: 'http://127.0.0.1:3001/',
  alive: true
})

无界的三种运行模式
1.保活模式
    设置alive为true,子应用只会被渲染一次,内部的数据和路由的状态不会随着页面切换而丢失。
2.单例模式
    子应用的alive为false且进行了生命周期改造时进入单例模式。在单例式下,改变 url 子应用的路由会发生跳转到对应路由。所有的子应用共享一个Wujie实例。
3.重建模式
    子应用既没有设置为保活模式,也没有进行生命周期的改造则进入了重建模式。每次切换子应用时都会销毁原本的应用创建新的应用。

组件内使用无界

<WujieVue 
    width="100%" 
    height="100%" 
    :name="vue-app" 
  ></WujieVue>

无界的应用通信系统
1.使用props
主应用注入数据

<WujieVue
    width="100%"
    height="100%"
    :name="vue-app"
    :props="{name: 'wujie', age: 18}"
  ></WujieVue>

子应用接收

console.log('vue',window.$wujie.props) // {name: 'wujie', age: 18}

2.window通信
父应用传输数据

window.document.querySelector("iframe[name=wujie-vue]").contentWindow.peiqi

子应用接收数据

console.log('vue', window.parent) // {peiqi: 'hello word'}

3.使用eventBus
父应用使用方式:

// 引入bus
import WujieVue from "wujie-vue";
const { bus } = WujieVue;
// 主应用监听事件
bus.$on("事件名字", function (arg1, arg2, ...) {});
// 主应用发送事件
bus.$emit("事件名字", arg1, arg2, ...);
// 主应用取消事件监听
bus.$off("事件名字", function (arg1, arg2, ...) {});

子应用使用:

// 子应用监听事件
window.$wujie?.bus.$on("事件名字", function (arg1, arg2, ...) {});
// 子应用发送事件
window.$wujie?.bus.$emit("事件名字", arg1, arg2, ...);
// 子应用取消事件监听
window.$wujie?.bus.$off("事件名字", function (arg1, arg2, ...) {});

2、原理解析,实现vue3版本的wujie

实现一个WujieVue组件,接受相关属性(只实现了部分属性,其它的大同小异)
src/index.ts文件

// 引入wujie和vue
import { defineComponent, h, getCurrentInstance, onMounted, watch, onBeforeUnmount } from 'vue'
import type { PropType } from 'vue'
import { Props } from './type'
import { startApp, bus } from 'wujie'

// 定义组件
const wujie = defineComponent({
  props: {
    width: { type: String, default: "" },
    height: { type: String, default: "" },
    name: { type: String, default: "", required: true },
    loading: { type: HTMLElement, default: undefined },
    url: { type: String, default: "", required: true },
    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 as PropType<Props['replace']>, default: undefined },
    fetch: { type: Function as PropType<Props['fetch']>, default: undefined },
    fiber: { type: Boolean, default: undefined },
    degrade: { type: Boolean, default: undefined },
    plugins: { type: Array as PropType<Props['plugins']>, default: null },
    beforeLoad: { type: Function as PropType<Props['beforeLoad']>, default: null },
    beforeMount: { type: Function as PropType<Props['beforeMount']>, default: null },
    afterMount: { type: Function as PropType<Props['afterMount']>, default: null },
    beforeUnmount: { type: Function as PropType<Props['beforeUnmount']>, default: null },
    afterUnmount: { type: Function as PropType<Props['afterUnmount']>, default: null },
    activated: { type: Function as PropType<Props['activated']>, default: null },
    deactivated: { type: Function as PropType<Props['deactivated']>, default: null },
  },
  setup(props, { emit }) {
    const instance = getCurrentInstance();
    const init = () => {
      // 微前端初始化方法
      startApp({
        name: props.name,
        url: props.url,
        el: instance?.refs.wujie as HTMLElement,
        loading: props.loading,
        alive: props.alive,
        fetch: props.fetch,
        props: props.props,
        attrs: props.attrs,
        replace: props.replace,
        sync: props.sync,
        prefix: props.prefix,
        fiber: props.fiber,
        degrade: props.degrade,
        plugins: props.plugins,
        beforeLoad: props.beforeLoad,
        beforeMount: props.beforeMount,
        afterMount: props.afterMount,
        beforeUnmount: props.beforeUnmount,
        afterUnmount: props.afterUnmount,
        activated: props.activated,
        deactivated: props.deactivated,
      })
    }

    watch([props.name, props.url], () => {
      init()
    })

    const handleEmit = (event: string, ...args: any[]) => {
      emit(event, ...args)
    }

    onMounted(() => {
      bus.$onAll(handleEmit)
      init()
    })

    onBeforeUnmount(() => {
      bus.$offAll(handleEmit)
    })

    return () => h('div', {
      style: {
        height: props.height,
        width: props.width,
      },
      ref: 'wujie'
    })
  }
})
// app.use()时会执行wujie的install方法注册全局组件
wujie.install = (app: any) => {
  app.component('WujieVue', wujie)
}

export default wujie

src/type.ts

import type { plugin } from 'wujie'
type lifecycle = (appWindow: Window) => any;
interface Props {
    /** 唯一性用户必须保证 */
    name: string;
    /** 需要渲染的url */
    url: string;
    /** 需要渲染的html, 如果用户已有则无需从url请求 */
    html?: string;
    /** 渲染的容器 */
    loading?: HTMLElement;
    /** 路由同步开关, false刷新无效,但是前进后退依然有效 */
    sync?: boolean;
    /** 子应用短路径替换,路由同步时生效 */
    prefix?: { [key: string]: string };
    /** 子应用保活模式,state不会丢失 */
    alive?: boolean;
    /** 注入给子应用的数据 */
    props?: { [key: string]: any };
    /** js采用fiber模式执行 */
    fiber?: boolean;
    /** 子应用采用降级iframe方案 */
    degrade?: boolean;
    /** 自定义运行iframe的属性 */
    attrs?: { [key: string]: any };
    /** 自定义降级渲染iframe的属性 */
    degradeAttrs?: { [key: string]: any };
    /** 代码替换钩子 */
    replace?: (codeText: string) => string;
    /** 自定义fetch,资源和接口 */
    fetch?: (input: RequestInfo, init?: RequestInit) => Promise<Response>;
    /** 子应插件 */
    plugins: Array<plugin>;
    /** 子应用生命周期 */
    beforeLoad?: lifecycle;
    /** 没有做生命周期改造的子应用不会调用 */
    beforeMount?: lifecycle;
    afterMount?: lifecycle;
    beforeUnmount?: lifecycle;
    afterUnmount?: lifecycle;
    /** 非保活应用不会调用 */
    activated?: lifecycle;
    deactivated?: lifecycle;
};
 
export { Props }

webpack.config.js

const { Configuration } = require('webpack')
const path = require('path')

/**
 * @type {Configuration} // webpack 配置的智能提示
 */
const config = {
  entry: './src/index.ts',
  output: {
    filename: 'index.js',
    path: path.resolve(__dirname, 'lib'),
    library: 'wujievue',
    libraryTarget: 'umd',
    umdNamedDefine: true
  },
  // 这两个文件不用打包到index.js文件中
  externals: {
    vue: 'vue',
    wujie: 'wujie'
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: 'swc-loader' // swc 打包速度相比于babel更快
      }
    ]
  },
  mode: 'none',
}

module.exports = config

无界官网: 无界

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值