(via Jimmy Lv 🐵)
微前端 - 将微服务理念扩展到前端开发
(via Jimmy Lv 🐵)
假设服务边界已经被正确地定义为可独立运行的业务领域,并确保在微服务设计中遵循诸多最佳实践。
微前端(Micro Frontends)这个术语是微服务的衍生物。同时构建多个自包含的和松耦合的 UI 组件(服务),其中每个组件负责特定的 UI 元素和功能。
🔨 Creating small apps (rather than components) 🔨
# src/App.js
export default () =>
<header>
<h1>Logo</h1>
......
</header>;
# server.js
const renderedApp = renderToString(React.createElement(App, null));
# server.js
Promise.all([
getContents('https://microfrontends-header.herokuapp.com/'),
getContents('https://microfrontends-products-list.herokuapp.com/'),
getContents('https://microfrontends-cart.herokuapp.com/')
]).then(responses =>
res.render('index', { header: responses[0], productsList: responses[1], cart: responses[2] })
).catch(error =>
res.send(error.message)
)
);
# views/index.ejs
<head>
<meta charset="utf-8">
<title>Microfrontends Homepage</title>
</head>
<body>
<%- header %>
<%- productsList %>
<%- cart %>
</body>
Problem: Some apps may take longer to load
<body>
<iframe width="100%" height="200" src="https://microfrontends-header.herokuapp.com/"></iframe>
<iframe width="100%" height="200" src="https://microfrontends-products-list.herokuapp.com/"></iframe>
<iframe width="100%" height="200" src="https://microfrontends-cart.herokuapp.com/"></iframe>
</body>
var script = document.createElement('script')
script.setAttribute('src', nonExecutableScript.src)
script.setAttribute('type', 'text/javascript')
element.appendChild(script)
This basically loads the apps through ajax and insert their content inside those divs
. It also has to clone each script tag manually for them to work.
Note: to avoid problems with Javascript and CSS loading order, I suggest you to evolve this to a solution similar to facebook's bigpipe, returning a JSON like { html: ..., css: [...], js: [...] }
so you can have full control of it.
# src/index.js
class Header extends HTMLElement {
attachedCallback() {
ReactDOM.render(<App />, this.createShadowRoot());
}
}
document.registerElement('microfrontends-header', Header);
<body>
<microfrontends-header></microfrontends-header>
<microfrontends-products-list></microfrontends-products-list>
<microfrontends-cart></microfrontends-cart>
</body>
Web Components 是一个 Web 标准,所以像 Angular,React,Preact,Vue 或 Hyperapp 这样的主流 JavaScript 框架都支持它们。
- 自定义元素
- Shadow DOM
- HTML 导入
- HTML 模板元素
<link rel="import" href="/components/tc-books/tc-books.html" />
<link rel="import" href="/components/tc-books/tc-book-form.html" />
# angularComponent.ts
const event = new CustomEvent('addToCart', { detail: item });
window.dispatchEvent(event);
# reactComponent.js
componentDidMount() {
window.addEventListener('addToCart', (event) => {
this.setState({ products: [...this.state.products, event.detail] });
}, false);
}
可以在一个页面将多个不同的框架整合,甚至在切换的时候都不需要刷新页面 (支持 React, Vue, Angular 1, Angular 2, etc)
import * as singleSpa from 'single-spa'
const appName = 'app1'
const loadingFunction = () => import('./app1/app1.js')
const activityFunction = (location) => location.hash.startsWith('#/app1')
singleSpa.declareChildApplication(appName, loadingFunction, activityFunction)
singleSpa.start()
# single-spa-examples.js
declareChildApplication('navbar', () => import('./navbar/navbar.app.js'), () => true);
declareChildApplication('home', () => import('./home/home.app.js'), () => location.hash === "" || location.hash === "#");
declareChildApplication('angular1', () => import('./angular1/angular1.app.js'), hashPrefix('/angular1'));
declareChildApplication('react', () => import('./react/react.app.js'), hashPrefix('/react'));
declareChildApplication('angular2', () => import('./angular2/angular2.app.js'), hashPrefix('/angular2'));
declareChildApplication('vue', () => import('src/vue/vue.app.js'), hashPrefix('/vue'));
declareChildApplication('svelte', () => import('src/svelte/svelte.app.js'), hashPrefix('/svelte'));
declareChildApplication('preact', () => import('src/preact/preact.app.js'), hashPrefix('/preact'));
declareChildApplication('iframe-vanilla-js', () => import('src/vanillajs/vanilla.app.js'), hashPrefix('/vanilla'));
declareChildApplication('inferno', () => import('src/inferno/inferno.app.js'), hashPrefix('/inferno'));
declareChildApplication('ember', () => loadEmberApp("ember-app", '/build/ember-app/assets/ember-app.js', '/build/ember-app/assets/vendor.js'), hashPrefix('/ember'));
start();
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react.min.js" crossorigin="anonymous"></script>
所谓架构,其实是解决人的问题;所谓敏捷,其实是解决沟通的问题;所谓精益,其实是在讨论如何榨干劳动力;
- https://medium.com/@tomsoderlund/micro-frontends-a-microservice-approach-to-front-end-web-development-f325ebdadc16
- https://medium.com/@_rchaves_/building-microfrontends-part-i-creating-small-apps-710d709b48b7
- http://allegro.tech/2016/03/Managing-Frontend-in-the-microservices-architecture.html
- https://technologyconversations.com/2015/08/09/developing-front-end-microservices-with-polymer-web-components-and-test-driven-development-part-55-using-microservices/
- https://technologyconversations.com/2015/08/09/including-front-end-web-components-into-microservices/
- https://inbox.google.com/u/1/search/microfrontend
- https://inbox.google.com/u/1/search/micro%20frontend
- https://medium.com/@_rchaves_/building-microfrontends-bonus-part-rewriting-an-app-with-elm-97ddce415ff4
- https://m.signalvnoise.com/the-majestic-monolith-29166d022228
- https://medium.com/@_rchaves_/building-microfrontends-part-v-communication-between-apps-34ae3649d610
- https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent
- https://medium.com/@_rchaves_/building-microfrontends-part-iv-using-cdns-tech-radar-for-consensus-7dd658c1edb7
- https://medium.com/@_rchaves_/building-microfrontends-part-iii-public-path-problem-1ce823be24c9
- https://medium.com/@_rchaves_/building-microfrontends-part-ii-joining-apps-together-dfa1b6f17d3e
- https://www.upwork.com/blog/2017/05/modernizing-upwork-micro-frontends/
- https://www.upwork.com/blog/2017/01/upwork-modernization/
- https://engineering.hellofresh.com/front-end-microservices-at-hellofresh-23978a611b87
- https://news.ycombinator.com/item?id=13009285
- https://www.thoughtworks.com/radar/techniques/micro-frontends
- http://www.agilechamps.com/microservices-to-micro-frontends/
- https://www.tikalk.com/js/introduction-to-micro-frontends/
- https://github.com/CanopyTax/single-spa
- http://www.infoq.com/cn/news/2015/08/netflix-falcor
- http://insights.thoughtworks.cn/frontend-future-radar/
- https://blog.prototypr.io/luke-wroblewski-introduced-skeleton-screens-in-2013-through-his-work-on-the-polar-app-later-fd1d32a6a8e7
- https://micro-frontends.org/
- https://blog.fundebug.com/2017/08/02/micro_frontend_development/
- https://www.quora.com/How-is-JavaScript-used-within-the-Spotify-desktop-application-Is-it-packaged-up-and-run-locally-only-retrieving-the-assets-as-and-when-needed-What-JavaScript-VM-is-used/answer/Mattias-Petter-Johansson