Closed beyondxgb closed 5 years ago
从我的理解上来看,一个用 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 就是把依赖这一系列的详细设计封装进去了而已。
为啥不写个支持 React 的,我理解应该都差不多吧,或者设计的时候也支持多个框架,已插件形式扩展