npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

mfy

v0.4.1

Published

简易的无侵入式微前端框架

Downloads

23

Readme

麦饭(MFY)

简易的无侵入式微前端框架。

不需要对原有应用做任何修改,就可以被融入到新的技术体系中,麦饭的目标,是让开发者以最简单的开发方式,以低廉的成本完成技术迁移。抑或,将你的巨无霸应用得以拆分为多个子应用,让你的开发团队专注于特定的功能应用上,而不受技术栈的影响。虽然小巧,但精悍无比,花5分钟试用它,你一定会爱上麦饭。

除了拥有其他微前端框架几乎所有功能之外,与其他微前端框架的不同点(亮点):

  • 支持子应用嵌套,子应用里面还可以嵌套子应用
  • 支持子应用被挂载的DOM节点被删掉之后又挂载回来,例如使用v-if控制一块区域的隐现
  • 支持路由映射,不需要对子应用进行修改的情况下,把外层的url映射为内层url
  • 动画过渡效果

快速体验小DEMO

安装

npm i mfy

或者直接通过cdn加载麦饭。

<script src="https://unpkg.com/mfy"></script>

快速上手

麦饭总共只有4个接口函数,你可以在5分钟内接入它。

首先,在你需要加载子应用的位置使用<mfy-app>标签占位:

<mfy-app name="some"></mfy-app>

然后注册和启动同名的子应用:

import { importSource, registerMicroApp } from 'mfy'

const app = registerMicroApp({
  name: 'some', // 对应<mfy>标签的name属性值
  source: () => importSource('./apps/some/index.html'),
  autoMount: true, // 自动完成挂载
})

好了,你当前的应用成功加载了子应用。如果没有父子通信的需要,你甚至不需要在子应用中改任何一处。

如果你的子应用足够简单,不需要复杂的通信和路由等,可以直接传入src属性省去registerMicroApp这一步。

<mfy-app name="simple" src="./apps/simple-app.html" mode="shadow"></mfy-app>

此时,name 还是必须的,它保证你的一个页面内的子应用是唯一的,src传入后你就不需要(也不可以)再用registerMicroApp进行注册,同时可以传入mode来选择模式。这种效果有点像直接使用iframe一样简单。

接口

麦饭的四个接口,importSourceregisterMicroApp为子应用的加载和挂载服务,connectScope为父子应用通信服务,registerRouter为路由映射服务。

importSource(relativePath)

导入资源,传入子应用的html入口文件的相对路径,改相对路径是指从当前能被访问到的url到子应用入口文件url地址的相对路径。

importSource('./apps/some/index.html')

在麦饭中,资源加载具有缓存,同一个文件不会加载第二次,而是直接使用缓存,因此你不需要担心统一资源反复加载的问题。一般而言,importSource只会作为registerMicroAppsource参数中使用。

registerMicroApp(options)

注册一个微应用,使html中的<mfy-app>对应name的应用生效。

配置参数如下:

{
  name: string, 对应<mfy-app>的name属性,当前环境中,不允许多次注册同名应用
  source: 资源,只能使用importSource进行导入,直接导入,资源会立即加载,如果接收函数,资源会在bootstrap的时候加载
  mode: iframe|shadow|none, 默认none。子应用的环境隔离类型,默认不做脚本执行环境隔离
  placeholder: html字符串,可选,当资源还没有下载完时,可以用这个字符串渲染,字符串内应该包含样式
  onLoad(): 资源加载好时被调用
  onBootstrap(): 子应用启动时被调用
  onMount(): 子应用被挂载时调用
  onUnmount(): 子应用被卸载时调用
  onDestroy(): 子应用对应的<mfy-app>标签从文档中移除时调用
  onMessage(data): 子应用向当前环境发送消息时调用
  autoBootstrap: 自动启动该子应用
  autoMount: 自动挂载该子应用,包含了autoBootstrap的效果
  hoistCssRules(rule): 哪些样式要被挂载到当前环境的head中实现全局样式,返回样式的字符串文本cssText
  injectCss: string, 注入样式,用以覆盖子应用原本的样式(以style的形式放在子应用head区末尾)
  injectJs: string, 注入JS脚本(以script的形式放在子应用body区末尾)
  viewport: string|stirng[], element selector, 例如 'body > .main-content',表示在子应用加载完之后,将会以 'body > .main-content' 的长宽作为子应用的显示区域,如果是数组的话,第一个作为可视区域依据,其他的都被保留在视口中
}

大多数配置项都是可选的,只有name和source是必须传的。

const app = registerMicroApp(...)

它会返回一个注册好的app对象,该app是和对应的<mfy-app>绑定的。对于一个app而言,它需要被执行两个步骤,才会在界面上展示出来:bootstrap+mount。

app.bootstrap()

bootstrap方法用于启动该app,启动之后,会进行资源加载、环境创建等工作。为了根据实际需要进行这些消耗内存的操作,你可以在不同的时间点上启动app。

app.mount()

mount方法用于将app的内容渲染到界面上,调用之后,你可以通过开发者工具看到<mfy-app>内部发生了变化。

app.unmount()

unmount方法用于将渲染到界面上的内容移除,调用之后,你可以通过开发者工具看到<mfy-app>内部发生了变化。

另外,<mfy-app>在文档中有可能会因为其他程序的操作,比如vue或react的更新操作,会从文档中被移除,一个<mfy-app>标签被移除之后,并不代表这个app被销毁了,这个app仍然存在于内存中,当对应的<mfy-app>重新回到文档中时,它会自动重建环境,并根据销毁前的状态决定是否挂载app。

connectScope(window)

麦饭中,通过scope完成父子应用的通信。一个子应用一定运行在一个由麦饭创建的环境中,这个环境就是scope,一个scope内,可能运行着多个子应用。每一个子应用又包含了一个自己的内部环境scope,在这个scope中,可能又会有新的子应用挂载进来,这样,app+scope就形成了一个树状结构。scope的主要功能,是为父子应用提供通信。

const scope = connectScope(window)

scope.emit({ type: 'event', message: 'ok' }) // 向父应用发送消息
scrope.listen((data) => { // 接收到来自父应用发送的消息
  const { type } = data
  // ...
})
scope.watch(name, (data) => { // 接收到来自子应用发送的消息,name为子应用的名称
  // ..
})
scope.send(name, data) // 向单个子应用发送消息
scope.dispatch({ type: 'event', message: 'gogo' }) // 向所有子应用广播消息(不包含孙应用)
scope.broadcast({ type: 'xx', message: 'oo' }) // 向整个应用树广播消息,自顶向下进行广播

参数window虽然是可选的,但是,我们应该尽可能都传入,因为在沙箱中,window所代表的意思并不完全相同,如果不传,麦饭会自己经过推理得到一个scope,但是这个scope有可能并不正确,特别是在使用type="module"的代码块中。如果你直接传入true代表读取rootScope。

麦饭并不提供全局状态共享的能力,因为应用之间不应该直接共享状态,共享状态导致状态的不可预测性,不利于子应用开发团队专注完成子应用的功能开发。但是,父子通信的能力,实际上提供了传递状态的能力,在必要的时候,可以通过通信机制传递状态。

registerRouter(options)

注册一个路由管理器。通过该方法,你可以把多个子应用放在一个路由管理器下面,用以规定这个子应用在什么路由状态下执行mount/unmount操作。另外,路由系统还提供了路由映射功能,浏览器的url并非直接被子应用识别,子应用识别到的url,来自路由管理器map的结果。我们来看下options都可以进行哪些配置:

{
  routes: [
    {
      app: 对应的app对象
      match: (data) => true|false, 用以决定是否匹配到当前app的函数,当该函数返回true时,app会被mount
      map: (data) => url字符串,用于将外部信息映射为子应用的url,即使子应用是用vue-router等进行路由管理的,也不需要对子应用的路由系统进行修改,我们用map就可以处理好子应用接收到的url信息
      reactive: (data) => {}, 当子应用内部的url被子应用内的程序修改时,该函数被执行,从而可以让外部环境记录子应用的url,从而即使用户直接刷新浏览器,也不会丢失子应用的url
    }
  ]
  autoBoostrap: 是否自动启动路由监听
  transition: fade|slide, 子应用mount/unmount时的过渡动画效果
  onChange(): url发生变化时被被调用
  onEnter(): 有app被mount时被调用
  onLeave(): 有app被unmount时被调用
}

和app的启动一样,你也可以主动调用router.bootstrap()来启动路由监听。

注意点

  • 麦饭不支持跨域拉取资源,因此,请将你的所有应用部署在主应用域名下。
  • 不管是父级应用,还是子应用,麦饭的所有接口函数,必须在脚本顶层执行,不能异步执行上面的任何一个函数(app.bootstrap等对象方法可以异步执行)
  • 不支持子应用通过<script type="module">执行脚本,直接在浏览器中运行的ES脚本目前还不支持创建环境,所以不支持

对于 <scirpt type="module"> 的代码块,麦饭会把它转为常规的代码块,并将原本的 import from 用 import() 代替。并且要求所有模块依赖中没有副作用,也就是不会在模块中修改window等全局变量,而是只导出接口。

License

MIT.