phodal / mooa

Mooa 是一个为 Angular 服务的微前端框架。A independent-deployment micro-frontend Framework for Angular from single-spa.

Home Page:http://mooa.phodal.com/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

支持React

beyondxgb opened this issue · comments

为啥不写个支持 React 的,我理解应该都差不多吧,或者设计的时候也支持多个框架,已插件形式扩展

从我的理解上来看,一个用 Angular 的组织、公司,往往不会存在多个框架的情况。

不过,从理论上要在现在的框架上支持 React 会很容易,但是支持了 React 之后,又会有 Vue 等框架的需求。这样一来和 Single-SPA 并没有太大的区别。

你这个应该主要是解决了 Single-SPA 没有独立应用部署的问题,如果在设计上能支持多个框架,应用又能独立部署的话,岂不是完美?

如果要支持 React 的话,需要重新设计。不过,我觉得 Web Components 是一个更好的方案,至少更方案。

现在的问题是,你们项目需要支持 React 吗?

是的,我们团队技术栈是 React,Web Components 可能设计上好一点,但目前应用上还没得到广泛认可,短时推进不了的。

这两天大概看了下 Single-SPA 的源码和 mooa 的源码,实现支持多个框架且能独立部署应该不难,因为顶层主要是路由的控制和应用的生命周期管理,和框架是无关的。

我这两天折腾了下 Single-SPA,它完全能满足独立开发、独立运行、独立部署、技术无关,想了解下当时你是遇到什么问题而做 Mooa ?Single-SPA 其实做的事情好简单,就是路由监听,然后控制应用的生命周期,至于应用是什么,怎么运行,根本不关注。

实现独立部署的关键可以参照它案例里的 loadEmberApp 做法。

@beyondxgb Single-SPA loadEmberApp 是可以独立开发、独立部署,但是这不代表 React 和 Angular 是可以独立开发和独立部署,你可以试试官方的 DEMO:https://github.com/CanopyTax/single-spa-examples。

其中的代码还需要集成构建,所以我不知道 “它完全能满足独立开发、独立运行、独立部署、技术无关” 这个结论是从哪里得来的。入口代码如下所示:

declareChildApplication('navbar', () => import('./navbar/navbar.app.js'), () => true);
declareChildApplication('home', () => import('./home/home.app.js'), () => location.pathname === "" || location.pathname === "/");
declareChildApplication('angularjs', () => import('./angularjs/angularjs.app.js'), pathPrefix('/angularjs'));
declareChildApplication('react', () => import('./react/react.app.js'), pathPrefix('/react'));
declareChildApplication('angular', () => import('./angular/angular.app.js'), pathPrefix('/angular'));
declareChildApplication('vue', () => import('src/vue/vue.app.js'), pathPrefix('/vue'));
declareChildApplication('svelte', () => import('src/svelte/svelte.app.js'), pathPrefix('/svelte'));
declareChildApplication('preact', () => import('src/preact/preact.app.js'), pathPrefix('/preact'));
declareChildApplication('iframe-vanilla-js', () => import('src/vanillajs/vanilla.app.js'), pathPrefix('/vanilla'));
declareChildApplication('inferno', () => import('src/inferno/inferno.app.js'), pathPrefix('/inferno'));
declareChildApplication('cyclejs', () => import('src/cyclejs/cycle.app.js'), pathPrefix('/cycle'));
declareChildApplication('ember', () => loadEmberApp("ember-app", '/build/ember-app/assets/ember-app.js', '/build/ember-app/assets/vendor.js'), pathPrefix('/ember'));

我们的初衷是,我们只需要支持 Angular,我们需要定制生命周期。一旦你们有多应用的时候,你们就会有这样的定制需求。

在基座里面远程加载 app(使用 script 标签 load script),app 暴露根组件即可,打包使用 umd 模式,可以使用 window 去读取这个根组件,

function RootComponent() {
  return (
    <Provider store={store}>
      <ConnectedRouter history={history}>
        <Layout>
          {renderRoutes()}
        </Layout>
      </ConnectedRouter>
    </Provider>
  );
}

加载完后,使用 single-spa-react 包裹一下 app,使得 app 有生命周期:

const app1 = singleSpaReact({
    React,
    ReactDOM,
    rootComponent,
    domElementGetter: () => document.getElementById(appName),
 });

然后注册到 single-spa

registerApplication('app1', app1, pathPrefix('/app1'));

app 那边是独立的工程,只需要在打包的时候把根组件暴露出来即可,可以独立运行,独立部署。基座工程只是负责远程加载 app,注册 app。

registerApplication('app1', () => loadReactApp(
  'app1',
  'https://cdn.abc.com/single-spa-sample/app1/0.0.1/root.js',
  'https://cdn.abc.com/single-spa-sample/app1/0.0.1/bundle.css',
), pathPrefix('/app1'));

registerApplication('app2', () => loadReactApp(
  'app2',
  'https://cdn.abc.com/single-spa-sample/app2/0.0.1/root.js',
  'https://cdn.abc.com/single-spa-sample/app2/0.0.1/bundle.css',
), pathPrefix('/app2'));

registerApplication('app3', () => loadReactApp(
  'app3',
  'https://cdn.abc.com/single-spa-sample/app3/0.0.1/root.js',
  'https://cdn.abc.com/single-spa-sample/app3/0.0.1/bundle.css',
), pathPrefix('/app3'));

类似这样吧,子应用是打包好的,不是和基座工程集成构建,子应用的打包方式是 UMD 的话,可以使用很多方式读取到,然后就可以做很多事情了。

漂亮~。mooa 就是把依赖这一系列的详细设计封装进去了而已。