新星微前端MicroApp的基础教程

news2025/2/26 20:07:44

目录

什么是微前端?

使用场景

microApp介绍

概念图

micorApp的优势

microApp项目的应用

基座

基座路由

子应用

react项目中路由位置进行使用

跨域的问题

react项目中跨域

vue项目中跨域

micorApp基础介绍

micorApp传值(重要)

基座—>子应用发送数据

子应用获取—>基座数据

子应用—>基座发送数据

基座获取—>子应用数据

全局数据通信

  接收数据

JS沙箱

注意:

解决方式:

样式隔离

所有应用中禁用样式

在某个应用里禁止

在某个文件里禁用

在某一行禁用

元素隔离

预加载

使用方式

插件系统

官方定义

个人理解

适用场景

使用方式

例子

子午线埋点插件


什么是微前端?

微前端是一种类似于微服务的架构,是一种由独立交付的多个前端应用组成整体的架构风格,将前端应用分解成一些更小、更简单的能够独立开发、测试、部署的应用,而在用户看来仍然是内聚的单个产品。

简单来说:就是一个项目里可以内嵌多个子项目,子项目可以单独开发、部署并且技术框架无关。

使用场景

  • 大规模企业级 Web 应用开发;

  • 跨团队及企业级应用协作开发;

  • 俗称屎山的项目,就是用的技术比较老然后还堆叠了很多业务要重构需要花很大成本;

microApp介绍

看官方文档发现上来microApp就表明来意,`microApp`并没有延续single-spa的思路

micro-app借鉴了WebComponent的思想,通过CustomElement结合自定义的ShadowDom,将微前端封装成一个类WebComponent组件,从而实现微前端的组件化渲染。并且由于自定义ShadowDom的隔离特性,是目前市面上接入微前端成本最低的方案。

概念图

它在 基座应用子应用 之间充当桥梁胶水的作用。

micorApp的优势

  • 使用简单。 将功能封装到 WebComponent 中

  • 零依赖。 无依赖、更高的扩展性

  • 兼容所有框架 技术栈无关

microApp项目的应用

基座

通过micro-app标签可以渲染出一个子应用,它又三个参数

  • name:名称(必填)

  • url:子应用页面地址(必填)

  • baseurl:baseurl是基座应用分配给子应用的路由前缀(可选)

    注意:

    • 1、如果基座是history路由,子应用是hash路由,不需要设置基础路由baseroute

    • 2、如果子应用只有一个页面,没有使用react-routervue-router之类,也不需要设置基础路由baseroute

<div>
            <h1>React项目</h1>
            {/* 端口号通过.env进行设置 */}
            {/* name必填、url必填、baseroute选填 */}
            <micro-app
                name="app1"
                url="http://localhost:3001/"
                baseroute="/app1"
            ></micro-app>
</div>

基座路由

  • 1、基座是hash路由,子应用也必须是hash路由

  • 2、基座是history路由,子应用可以是hash或history路由

    注意:官方推荐使用history的路由

  <Routes>
        {/* 在'/'的时候我就渲染AppLayout组件 */}
        <Route
          path="/*"
          element={
            <AppLayout>
              {/* 如果AppLayout组件的路径事/app1/的话就加载AppOne */}
              <Routes>
                <Route path="/app1/*" element={<AppOne />} />
                <Route path="/app2/*" element={<AppTwo />} />
              </Routes>
            </AppLayout>
          }
        />
  </Routes>

子应用

通常基座应用和子应用各有一套路由系统,为了防止冲突,基座需要分配一个路由给子应用,称之为基础路由,子应用可以在这个路由下渲染,但不能超出这个路由的范围,这就是基础路由的作用。

如下: window.MICRO_APP_BASE_URL是由基座应用下发的路由前缀,在非微前端环境下,这个值为undefined

使用:

react项目中路由位置进行使用

root.render(
    <React.StrictMode>
        <BrowserRouter basename={window.__MICRO_APP_BASE_ROUTE__ || "/"}>
            <App />
        </BrowserRouter>
    </React.StrictMode>
);
vue项目中路由位置进行使用

const router = createRouter({
    routes,
    history: createWebHistory(
        window.__MICRO_APP_BASE_ROUTE__ || process.env.BASE_URL
    ),
});
export default router;
或者
const router = new VueRouter({
  mode: 'history',
  // __MICRO_APP_BASE_ROUTE__ 为micro-app传入的基础路由
  base: window.__MICRO_APP_BASE_ROUTE__ || process.env.BASE_URL,
  routes,
})

跨域的问题

react项目中跨域

module.exports = {
    devServer: (_) => {
        const config = _;
        config.headers = {
            "Access-Control-Allow-Origin": "*",
        };
        return config;
    },
};

vue项目中跨域

module.exports = {
    devServer: {
        port: 3002,
        headers: {
            "Access-Control-Allow-Origin": "*",
        },
    },
};

micorApp基础介绍

micorApp传值(重要)

每个应用的路由实例都是不同的,应用的路由实例只能控制自身,无法影响其它应用,包括基座应用无法通过控制自身路由影响到子应。

常见的问题如:开发者想通过基座应用的侧边栏跳转,从而控制子应用的页面,这其实是做不到的,只有子应用的路由实例可以控制自身的页面

基座—>子应用发送数据

方式1: 通过data属性发送数据
<micro-app
  name='my-app'
  url='xx'
  data={data} // data只接受对象类型,采用严格对比(===),当传入新的data对象时会重新发送
/>
方式2: 手动发送数据
microApp.setData('my-app', {type: '新的数据'})

子应用获取—>基座数据

方式2:监听基座传来的数据
监听数据
window.microApp?.addDataListener(dataListener:function类型)
// 解绑指定函数
window.microApp?.removeDataListener(dataListener)
// 清空当前子应用的所有绑定函数(全局数据函数除外)
window.microApp?.clearDataListener()
方式2:主动获取数据
window.microApp?.getData() // 返回data数据
​
应用
if (window.__MICRO_APP_BASE_ROUTE__) {
    // @ts-ignore
    window.microApp.addDataListener((data) => {
      // 当基座下发跳转指令时进行跳转
      if (data.path) {
        navigate(data.path);
      }
    });
  }

子应用—>基座发送数据

window.microApp?.dispatch({type: '子应用发送的数据'})

基座获取—>子应用数据

方式1: 监听自定义事件
<micro-app
  name='my-app'
  url='xx'
  data={data}
  onDataChange={(e) => console.log(e.detail.data)}
/>
方式2: 手动绑定监听函数
microApp.addDataListener(appName: string, dataListener: Function)
// 解绑监听my-app子应用的函数
microApp.removeDataListener(appName: string, dataListener: Function)
// 清空所有监听appName子应用的函数
microApp.clearDataListener(appName: string)
方式3:主动获取数据
microApp.getData(appName) // 返回子应用发送的data数据

数据在event.detail.data字段中,子应用每次发送数据都会重新触发事件  onDataChange函数在子应用卸载时会自动解绑,不需要手动处理

全局数据通信

发送数据
基座
microApp.setGlobalData({type: '全局数据'})
子应用
window.microApp?.setGlobalData({type: '全局数据'})

  接收数据

microApp.addGlobalDataListener(dataListener: Function, autoTrigger?: boolean)
// 解绑指定函数
microApp.removeGlobalDataListener(dataListener)
// 清空基座应用绑定的全局数据函数
microApp.clearGlobalDataListener()

JS沙箱

使用Proxy拦截了用户全局操作的行为,防止对window的访问和修改,避免全局变量污染。micro-app中的每个子应用都运行在沙箱环境,以获取相对纯净的运行空间。

官方建议:沙箱是默认开启的,正常情况下不建议关闭,以避免出现不可预知的问题。

注意:

子应用在沙箱环境下如何获取真实的window

1、new Function("return window")() 或 Function("return window")()

2、(0, eval)('window')

3、window.rawWindow

子应用抛出错误:xxx未定义

xxx is not defined

nxxx is not a function

Cannot read properties of undefined

这种原因事在js中var name或者function事顶级变量并会泄露为全局变量,可以通过window.name或者name方式去访问;但是在微前端中顶级变量不会泄露为全局变量,所以会报错;

解决方式:

将 var name 或 function name () {} 修改为 window.name = xx或者使用插件系统的方式的方式

样式隔离

MicroApp的样式隔离是默认开启的,开启后会以<micro-app>标签作为样式作用域,利用标签的name属性为每个样式添加前缀,将子应用的样式影响禁锢在当前标签区域。

.test {
  color: red;
}
​
/* 转换为 */
micro-app[name=xxx] .test {
  color: red;
}

官方建议:但基座应用的样式依然会对子应用产生影响,如果发生样式污染,推荐通过约定前缀或CSS Modules方式解决。

所有应用中禁用样式

这主要通过start方法进行全局配置,设置后所有应用的样式隔离都会停止。

import microApp from '@micro-zoe/micro-app'
​
microApp.start({
  disableScopecss: true, // 默认值false
})

如果希望在某个子应用中不受全局配置控制,可以设置disableScopecss='false'

<micro-app name='xx' url='xx' disableScopecss='false'></micro-app>

在某个应用里禁止

设置后,当前应用的所有css都不会进行样式隔离。

<micro-app name='xx' url='xx' disableScopecss 或 disable-scopecss></micro-app>

在某个文件里禁用

可以在你的css文件中使用以下格式的注释来禁用样式隔离:

/* ! scopecss-disable */
.test1 {
  color: red;
}
/* ! scopecss-enable */

如果想在整个文件范围内禁用样式隔离,将 /* ! scopecss-disable */ 注释放在文件顶部:

/* ! scopecss-disable */
...

在某一行禁用

在文件中使用以下格式的注释在某一特定的行上禁用样式隔离:

/* ! scopecss-disable-next-line */
.test1 {
  color: red;
}
​
.test2 {
  /* ! scopecss-disable-next-line */
  background: url(/test.png);
}

元素隔离

大栗子:基座应用和子应用都有一个元素`<div id='root'></div>`,此时子应用通过`document.querySelector('#root')`获取到的是自己内部的`#root`元素,而不是基座应用的。

元素隔离的概念来自ShadowDom,即ShadowDom中的元素可以和外部的元素重复但不会冲突,micro-app模拟实现了类似ShadowDom的功能,元素不会逃离<micro-app>元素边界,子应用只能对自身的元素进行增、删、改、查的操作。

预加载

预加载是指在应用尚未渲染时提前加载资源并缓存,从而提升首屏渲染速度。

预加载并不是同步执行的,它会在浏览器空闲时间,依照开发者传入的顺序,依次加载每个应用的静态资源,以确保不会影响基座应用的性能。

microApp.preFetch(Array<app>|Function=>Array<app>

preFetch接受app数组或一个返回app数组的函数,app的值如下:

app: {
  name: string, // 应用名称,必传
  url: string, // 应用地址,必传
  disableScopecss?: boolean // 是否关闭样式隔离,非必传
  disableSandbox?: boolean // 是否关闭沙盒,非必传
}

使用方式

import microApp from '@micro-zoe/micro-app'
​
// 方式一
microApp.preFetch([
  { name: 'my-app', url: 'xxx' }
])
​
// 方式二
microApp.preFetch(() => [
  { name: 'my-app', url: 'xxx' }
])
​
// 方式三
microApp.start({
  preFetchApps: [
    { name: 'my-app', url: 'xxx' }
  ],
})

插件系统

官方定义

微前端的使用场景非常复杂,没有完美的沙箱方案,所以我们提供了一套插件系统,它赋予开发者灵活处理静态资源的能力,对有问题的资源文件进行修改。插件系统的主要作用就是对js进行修改,每一个js文件都会经过插件系统,我们可以对这些js进行拦截和处理,它通常用于修复js中的错误或向子应用注入一些全局变量。

个人理解

由于沙箱系统的并不是特别完美,而且还必须需要,所以出现了一套插件系统!主要的作用就是操作js,每个js文件都会经过js进行处理和拦截,可以用来修复js的错误!

适用场景

通常我们无法控制js的表现,比如在沙箱中:

顶层的变量是无法泄漏为全局变量的(如 var xx = , function xxx 定义变量,无法通过window.xx 访问),导致js报错,此时开发者可以通过插件对js进行修改处理。

使用方式

import microApp from '@micro-zoe/micro-app'
//基座
microApp.start({
  plugins: {
    // 全局插件,作用于所有子应用的js文件
    global?: Array<{
      // 可选,强隔离的全局变量(默认情况下子应用无法找到的全局变量会兜底到基座应用中,scopeProperties可以禁止这种情况)
      scopeProperties?: string[],
      // 可选,可以逃逸到外部的全局变量(escapeProperties中的变量会同时赋值到子应用和外部真实的window上)
      escapeProperties?: string[],
      // 可选,传递给loader的配置项
      options?: any,
      // 必填,js处理函数,必须返回code值
      loader?: (code: string, url: string, options: any) => code 
    }>
  
    // 子应用插件
    modules?: {
      // appName为应用的名称,这些插件只会作用于指定的应用
      [appName: string]: Array<{
        // 可选,强隔离的全局变量(默认情况下子应用无法找到的全局变量会兜底到基座应用中,scopeProperties可以禁止这种情况)
        scopeProperties?: string[],
        // 可选,可以逃逸到外部的全局变量(escapeProperties中的变量会同时赋值到子应用和外部真实的window上)
        escapeProperties?: string[],
        // 可选,传递给loader的配置项
        options?: any,
        // 必填,js处理函数,必须返回code值
        loader?: (code: string, url: string, options: any) => code 
      }>
    }
  }
})

例子

操作顶层的变量是无法泄漏为全局变量的eg:var name ===>window.name

import microApp from '@micro-zoe/micro-app'
​
microApp.start({
  plugins: {
    modules: {
      'appName1': [{
        loader(code, url, options) {
          if (url === 'xxx.js') {
            code = code.replace('var abc =', 'window.abc =')
          }
          return code
        }
      }],
      'appName2': [{
        scopeProperties: ['key', 'key', ...], // 可选
        escapeProperties: ['key', 'key', ...], // 可选
        options: 配置项, // 可选
        loader(code, url, options) { // 必填
          console.log('只适用于appName2的插件')
          return code
        }
      }]
    }
  }
})

子午线埋点插件

子午线埋点文件中使用function定义将函数泄漏为全局变量,这在沙箱中是不允许的,所以我们需要将其修改为 window.xx = funnction xx 的形式进行适配。

# 安装子午线埋点插件
npm i @micro-zoe/plugin-painful-joya -S 
import microApp from '@micro-zoe/micro-app'
import painfulJoya from '@micro-zoe/plugin-painful-joya'

// 设置为全局插件,作用于所有子应用
microApp.start({
  plugins: {
    global: [painfulJoya],
  }
})

// 或者设置为某个子应用的插件,只作用于当前子应用
microApp.start({
  plugins: {
    modules: {
      'appName': [painfulJoya],
    }
  }
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/407924.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue 2项目如何升级到Vue 3?

应不应该从 Vue 2 升级到 Vue 3 应不应该升级&#xff1f;这个问题不能一概而论。 首先&#xff0c;如果你要开启一个新项目&#xff0c;那直接使用 Vue 3 是最佳选择。后面课程里&#xff0c;我也会带你使用 Vue 3 的新特性和新语法开发一个项目。 以前我独立使用 Vue 2 开…

【vue】vuex常见面试题

【vue】vuex常见面试题 文章目录【vue】vuex常见面试题一、vuex简介对vuex的理解各模块在流程中的功能&#xff1a;Vuex实例应用二、常见面试题1.Vuex 为什么要分模块并且加命名空间2.Vuex和单纯的全局对象有什么区别&#xff1f;3.为什么 Vuex 的 mutation 中不能做异步操作&a…

css宽高自适应

1. 宽高自适应 举个例子看看什么是宽高自适应&#xff0c; &#xff08;1&#xff09;先正常创建一个div标签&#xff0c;有宽和高&#xff1a; 结果&#xff1a; &#xff08;2&#xff09;去掉div的宽度&#xff0c;观察结果 结果&#xff1a; 结果占满了整个屏幕&#xff0…

HTML表格样式

9675人阅读 行跟列背景颜色的选择&#xff0c;合并等 列的颜色选择代码 <colgroup span"1" bgcolor"lightgreen"></colgroup> <colgroup span"1" bgcolor"lightyellow"></colgroup> <colgroup span"…

一大波 ChatGPT 开源项目,诞生了!

公众号关注 “GitHubDaily”设为 “星标”&#xff0c;每天带你逛 GitHub&#xff01;大家好&#xff0c;我是小 G。本月初 ChatGPT 问世&#xff0c;犹如平地惊雷般&#xff0c;在技术圈中引起了广泛讨论。作为全球最大的开发者社区&#xff0c;GitHub 平台也在近期诞生了多个…

Ant vue中表单验证(动态校验、部分校验)

前提&#xff1a;写了超级复杂的表单&#xff0c;其中涉及了很多表单验证的地方&#xff0c;现一一记录一下&#xff1b; ant-vue 版本1.7.8 vue 版本2.6.11 校验的原理大体相似&#xff0c;灵活应用&#xff01;&#xff01; 1.动态校验 需求&#xff1a; 1根据读写方式去动态…

Css display 属性详解

css display - 块和内联元素 块级元素(block)块元素是一个元素&#xff0c;占用了全部宽度&#xff0c;在前后都是换行符;总是独占一行&#xff0c;表现为另起一行开始&#xff0c;而且其后的元素也必须另起一行显示内联元素(inline)内联元素只需要必要的宽度&#xff0c;不强…

react简单入门--常用hook中useMemo的使用(详细版)

前言&#xff1a; 作用&#xff1a; 首先useMemo它使用来做缓存用的&#xff0c;只有当一个依赖项改变的时候才会发生变化&#xff0c;否则拿缓存的值&#xff0c;就不用在每次渲染的时候再做计算 场景&#xff1a; 既然是用作缓存来用&#xff0c;那场景就可能有&#xff1a…

vue3的bpmn使用

目录 1.前言 2.安装相关依赖 3.组件部分的template部分 4.组件中的script 5.style代码 6.父组件中的使用场景 7.注意事项 1.前言 由于此次处于自己做项目阶段&#xff0c;基本上只要项目中需要使用到流程这一方面的东西&#xff0c;就需要用到bpmn以及后端的activity流…

VUE3 之 render 函数的使用 - 这个系列的教程通俗易懂,适合自学

目录 1. 概述 2. render 函数 3. 综述 4. 个人公众号 1. 概述 老话说的好&#xff1a;不用想的太多、太远&#xff0c;做好当天的事&#xff0c;知道明天要做什么就可以了。 言归正传&#xff0c;今天我们来聊聊 VUE 中 render 函数的使用。 2. render 函数 2.1 一个简单…

前缀和与对数器与二分法

1. 前缀和 假设有一个数组&#xff0c;我们想大量频繁的去访问L到R这个区间的和&#xff0c;我们该怎么快速的得出。 如果我们每次都遍历一遍累加这样就太慢了。我们可以开辟一个数组&#xff0c;把每个位置的和加在一起存进去。 如果我们要找的L到R中&#xff0c;L是0。那么…

Echarts地图的基本使用方法

echarts使用地图的基本使用方法 引入echarts 第一步&#xff1a;引入js文件 下载的最新完整版本 echarts.min.js 即可 <script src"echarts.min.js"> </script>第二步&#xff1a;指定DOM元素作为图表容器 创建一个DOM来作为绘制图表的容器 <di…

理解vuex实现的原理

一、vuex是什么&#xff1f; Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态&#xff0c; 这个状态管理应用包含以下几个部分&#xff1a; state&#xff0c;驱动应用的数据源&#xff1b;view&#xff0c;以声明方式将 stat…

【工具】Vue中生成二维码组件——vue-qr

【工具】Vue中生成二维码组件——vue-qr npm地址——https://www.npmjs.com/package/vue-qr 注&#xff1a;不支持IE浏览器 效果 1、安包 npm install vue-qr --save 2、引入 // vue2.0 import VueQr from vue-qr // vue3.0 import VueQr from vue-qr/src/packages/vue-qr.…

3分钟搞懂阿里云服务器安装Nginx并配置静态访问页面

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【Bug 终结者】 &#xff0c;【CSDN新星创作者】&#x1f3c6;&#xff0c;阿里云技术博主&#x1f3c6;&#xff0c;51CTO人气博主&#x1f3c6;&…

怎么让 echarts 图表动起来?定时器解决它 —— 大屏展示案例(动态仪表盘、动态柱状图)

该案例为了实现效果采用的是随机生成数据&#xff0c;比较适用于偏向展示效果的静态页面如门户网站的首页、登录页等等。颜色样式自调。 需要注意在有些项目中仪表盘可能无法正常显示&#xff0c;这是因为你在项目中引入的 echarts 版本太低&#xff0c;需要引入新版本 echarts…

一个简单的springboot+Vue前后端框架搭建

前言 根据网上的一些教程试着搭建了一个简单的前后端分离的用户管理系统。该系统使用Vue框架编写前端代码&#xff0c;Springboot编写后端代码&#xff0c;Mysql作为数据库存储系统的数据。本文着重介绍整个项目的搭建流程以及附加一些在搭建过程的想法和注意事项。 一、Vue及…

【vue+router】解决路由重复警告:[vue-router] Duplicate named routes definition

vue页面动态添加路由&#xff0c;但加载页面会报警告&#xff1a; [vue-router] Duplicate named routes definition: { name: "xxx", path: "xxx" }这个问题解释为&#xff1a;路由命名重复 网上有一些大神剔除原有路由的做法&#xff1a; 1、古墩古墩 …

vue中computed的详细讲解

vue中computed的详细讲解1.定义2.用法3.computed的响应式依赖(缓存)4.应用场景1.定义 computed是vue的计算属性&#xff0c;是根据依赖关系进行缓存的计算&#xff0c;只有在它的相关依赖发生改变时才会进行更新 2.用法 一般情况下&#xff0c;computed默认使用的是getter属性…

Vue组件传值(props属性,父到子,子到父,兄弟传值)

文章目录[TOC](文章目录)前言一、props是什么&#xff1f;使用规则二、父传子 props实现步骤代码实现效果展示二.子传父 $emit实现步骤代码实现效果展示三.兄弟传值 EventBus实现步骤代码实现效果展示总结前言 Vue是数据驱动视图更新的框架, 平时写业务时,都会把页面不同模块拆…