笔者认为,前端行业如今处于一个分岔口:html
其中 WebApp 随着各行各业业务的不断发展,仅仅 SPA 应用已经很难知足现有的迭代开发;各种微服务方案开始被提上议程,其中以 web-components 为基础的微服务方案关注度较高。前端
barm 是一个渐进式、微服务胶水方案,基于 web-components,而且对 React 开发者友好。react
这意味着 barm 必须知足如下条件:git
由于 barm 定位是一个前端微服务的胶水方案,因此它不该该特别依赖于编译环境;github
为此,barm 使用 html 字符串解析,不须要配置 JSX 解析的 babel,咱们来看一个例子:web
注册 web-componentredux
import { html, Component, define } from 'barm';
class User extends Component {
render = () => {
return html` <div>page-user</div> `;
};
}
define('page-user')(User);
复制代码
渲染到页面设计模式
const pageUser = document.createElement('page-user');
document.body.append(pageUser);
复制代码
barm 每一个组件都是一个 web-component, 遵循 react API 及生命周期数组
注册一个组件:前端框架
import { define, html, Component } from 'barm';
class Home extends Component {
state = {
num: 0,
};
handleAddNum = () => {
this.setState(({ num }) => {
return {
num: num + 1,
};
});
};
render = () => {
return html` <div> <div>page-home: ${this.state.num}</div> <button onclick=${this.handleAddNum}>add num</button> </div> `;
};
}
define('page-home')(Home);
复制代码
在其余组件内使用以前注册的组件
import { html, Component, define } from 'barm';
class User extends Component {
render = () => {
return html` <div> <div>render-other-component</div> <page-home /> </div> `;
};
}
define('page-user')(User);
复制代码
import { html, Component, define } from 'barm';
class User extends Component {
renderBody = ({ name }) => {
return html` <div>render-${name}</div> `;
};
render = () => {
return html` <div> <${this.renderBody} name="hello" /> </div> `;
};
}
define('page-user')(User);
复制代码
咱们将一步步演示如何实现 react 的全部设计模式:
import { html, define } from 'barm';
define('page-user')(() => {
return html` <div> <div>page-user</div> </div> `;
});
复制代码
函数组件的第二个参数是一个 hooks,它会暴露一个 Class Component 完整的生命周期及类成员变量给到函数组件;
函数组件能够借此实现全部类组件的功能:
import { html, define, useHooks } from 'barm';
define('render-hooks')((props, hooks) => {
if (!hooks.isInited) {
hooks.state = {
name: '',
};
hooks.componentDidMount = () => {
//
};
hooks.handleOnInput = e => {
hooks.setState({ name: e.target.value });
};
}
return html` <div> <div>${hooks.state.name}</div> <input placeholder="test-hooks" oninput=${hooks.handleOnInput} /> </div> `;
});
复制代码
React hooks 的一个特色就是能够将生命周期的逻辑抽离并复用,在 barm 中咱们也能够实现同质效果;
barm 的 hooks 实现和官方的有出入,这是由于 react-hooks 是将状态捆绑在 React Firber 上,这将要求整个项目上下文仅有 1 个 react 对象,barm 是一个前端微服务框架,更适合使用类组件的方式将每一个状态隔离在各自组件中,因此继续沿用类组件的生命周期:
import { html, define, useHooks } from 'barm';
// 将逻辑抽离到公共区域,以复用
const useSetName = useHooks(hooks => {
if (!hooks.isInited) {
hooks.state = {
name: '',
};
hooks.componentDidMount = () => {
//
};
hooks.handleOnInput = e => {
hooks.setState({ name: e.target.value });
};
}
});
define('render-hooks')((props, hooks) => {
useSetName(hooks);
return html` <div> <div>${hooks.state.name}</div> <input placeholder="test-hooks" oninput=${hooks.handleOnInput} /> </div> `;
});
复制代码
import { html, define } from 'barm';
define('render-props-button')(({ children }) => {
return html` <button>${children('button-name')}</button> `;
});
define('page-user')(() => {
return html` <div> <div>page-user</div> <render-props-button> ${name => html` <span>${name}</span> `} </render-props-button> </div> `;
});
复制代码
HOC(高阶函数)是 React 早起的一种生命周期抽象的设计模式, 虽然咱们有了 hooks\renderProps 等同类的抽象行为,不过 Barm 也一样支持 HOC
import { html, define, Component } from 'barm';
define('the-button')(props => {
return html` <button ...${props}>hello-hoc</button> `;
});
function withLogAtDidMount() {
return (name, connectName) => {
define(name)(
class extends Component {
componentDidMount = () => {
console.log('hoc-log');
};
render = () => {
return html` <${connectName} ...${this.props} /> `;
};
},
);
};
}
withLogAtDidMount()('hoc-button', 'the-button');
define('page-hoc')(() => {
return html` <div> <div>page-hooks</div> <hoc-button style="font-size: 20px;" /> </div> `;
});
复制代码
barm 虽然使用了 web-components 可是并无使用 shadow-dom
这是由于 barm 每一个组件都是一个 web-component,shadow-dom 的样式隔离对于不少业务情景并没有必要,现实中咱们使用 BEM 已经可以很好的隔离样式污染和更好的共享样式,将来能够考虑添加一个属性以决定是否开启 shadow-dom。
barm 立志于建立一个微服务胶水方案,意味着它建立的组件很容易的在各框架内使用;
以 react 为例子, 假定咱们使用 barm 建立了一个 page-home web-component, 咱们在 react 使用它和使用 原生 DOM 元素相似:
import React from 'react';
import 'page-home';
export function HomePage() {
return (
<div> <page-home name="home" /> </div> ); } 复制代码
barm 除了能够很轻松的在各前端框架内使用,还须要知足自身的独立发布、独立部署,因此它须要一些必备生态:状态管理和路由;
barm 实现了 barm-redux 和 barm-redux-route,其中 route 组件是和状态管理捆绑的,每当路由发生变化,咱们能够派发事件变动名,若要更简化的路由组件可使用 vanilla-route