手把手教你写一个简易的微前端框架​

举报
i-WIFI 发表于 2024/10/15 20:35:59 2024/10/15
【摘要】 功能支持不同框架的子应用支持子应用 HTML 入口支持沙箱功能,子应用 window 作用域隔离、元素隔离支持子应用样式隔离支持各应用之间的数据通信Examples所有示例均在 examples 目录下。运行示例安装pnpm install --frozen-lockfile && pnpm install:all运行开发环境pnpm dev:all访问 ​​http://localhost...

功能

  • 支持不同框架的子应用
  • 支持子应用 HTML 入口
  • 支持沙箱功能,子应用 window 作用域隔离、元素隔离
  • 支持子应用样式隔离
  • 支持各应用之间的数据通信

Examples

所有示例均在 examples 目录下。

运行示例

安装

pnpm install --frozen-lockfile && pnpm install:all

运行开发环境

pnpm dev:all

访问 ​​http://localhost:8000​​,即可查看多个 spa 子应用的示例。

使用

安装

npm i mini-single-spa
# or
pnpm i mini-single-spa
# or
yarn add mini-single-spa

主应用

在主应用上注册子应用

import { registerApplication, start } from 'mini-single-spa'

registerApplication({
    name: 'vue',
    pageEntry: 'http://localhost:8001',
    activeRule: pathPrefix('/vue'),
    container: $('#subapp-viewport')
})

registerApplication({
    name: 'react',
    pageEntry: 'http://localhost:8002',
    activeRule:pathPrefix('/react'),
    container: $('#subapp-viewport')
})

start()

首先使用 ​​registerApplication()​​​ 注册所有的子应用,然后执行 ​​start()​​ 启动。

子应用

子应用必须向外暴露 ​​mount()​​​ 和 ​​unmount()​​​ 两个函数,并将它们挂在全局的子应用名称 ​​window.__SINGLE_SPA__​​ 下:

mount: (props: AnyObject) => Promise<any>
unmount: (props: AnyObject) => Promise<any>

window.__SINGLE_SPA__= {
    mount,
    unmount
}

​mount()​​​ 在子应用每次挂载时启用,​​unmount()​​ 在子应用每次卸载时使用。

子应用跨域和资源路径

子应用需要开启 cors 和指定生成的资源路径,假如你使用 ​​vue-cli​​ 进行开发,可以这样配置:

module.exports = {
    devServer: {
        port: 8001, // 设置子应用访问端口
        headers: {
            'Access-Control-Allow-Origin': '*' // 解决跨域问题
        }
    },
    publicPath: "//localhost:8001/", // 资源路径前缀
}

全局状态、全局事件

在父子应用上均可以使用 ​​window.spaGlobalState​​ 来设置、监听全局状态:

// 父应用
window.spaGlobalState.set('msg', '父应用在 spa 全局状态上新增了一个 msg 属性')

// 子应用(全局状态、事件不会生成快照和恢复,所以要在 mount() 调用后使用)
window.spaGlobalState.onChange((state, operator, key) => {
    alert(`vue 子应用监听到 spa 全局状态发生了变化: ${JSON.stringify(state)},操作: ${operator},变化的属性: ${key}`)
})

也可以使用全局事件:

// 父应用
window.spaGlobalState.emit('testEvent', '父应用发送了一个全局事件: testEvent')

// 子应用
window.spaGlobalState.on('testEvent', () => alert('vue 子应用监听到父应用发送了一个全局事件: testEvent'))

注意,子应用设置的全局状态、事件会在卸载时清除,并且不会保存快照。所以建议将状态、事件相关操作放在 ​​mount()​​ 函数执行时或之后。

全局状态、事件 API

// 状态相关
set(key: string, value: any): void;
get(key: string): any;
getAll(): AnyObject;
delete(key: string): void;
clear(): void;
onChange(callback: Callback): void;

// 事件相关
on(event: string, callback: Callback): void;
off(event: string, callback: Callback): void;
emit(event: string, ...args: any): void;
once(event: string, callback: Callback): void;

registerApplication(Application)

​registerApplication(Application)​​ 接收的参数如下:

interface Application {
    /**
     * app 名称
     */
    name: string
    /**
     * app 匹配规则,值为 true 时加载 app
     * 例如传入 /vue,当 url 的路径变为 /vue 时,激活当前子应用。
     * 如果 activeRule 为函数,则会传入 location 作为参数,activeRule(location) 返回 true 时,激活当前子应用。
     */
    activeRule: Function | string
    /**
     * 父应用传过来的自定义属性
     */
    props: Function | AnyObject
    /**
     * app 挂载的 dom
     */
    container: HTMLElement
    /**
     * app 访问入口,一个 URL 链接
     */
    pageEntry: string
    /**
     * enabled: 是否开启 js 作用域隔离、元素隔离,默认开启
     * css: 是否开启样式隔离,默认关闭
     */
    sandboxConfig: { enabled: boolean, css: boolean }
    /**
     * app 生命周期钩子,加载页面资源前触发,只会触发一次
     */
    beforeBootstrap?: () => void
    /**
     * app 生命周期钩子,页面入口的资源被加载并执行后触发,只会触发一次
     */
    bootstrapped?: () => void
    /**
     * app 生命周期钩子,挂载前触发
     */
    beforeMount?: () => void
    /**
     * app 生命周期钩子,挂载后触发
     */
    mounted?: () => void
    /**
     * app 生命周期钩子,卸载前触发
     */
    beforeUmount?: () => void
    /**
     * app 生命周期钩子,卸载后触发
     */
    unmounted?: () => void
    /**
     * js 代码的 loader,每次获取到 js 代码后会传给 loader() 并将返回值作为新的代码
     */
    loader?: (code: string) => string
}
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。