筆者認爲,前端行業如今處於一個分岔口: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