使用 Vue.js,React.js 及 Hypernova 构建微前端服务

使用Vue.js,React.js和Hypernova 构建微前端服务

使用 Vue.js,React.js 及 Hypernova 构建微前端服务_第1张图片
如果大家不熟悉Hypernova,则可以阅读本文。

软件架构的演变

使用 Vue.js,React.js 及 Hypernova 构建微前端服务_第2张图片
在软件开发的早期,前端和后端代码是由同一团队使用相同的运行时环境和部署过程来维护的,如今,我们将这些代码称为整体应用程序。
随着系统变得越来越复杂,我们开始将代码分成两个小组,分别由两个具有专门技能的团队维护:前端和后端,后端团队可以专注于构建弹性和高可用性的系统,而前端团队可以专注于浏览器的兼容性, UI设计和UX。但这还不够,随着复杂性的增长,我们开始将后端的业务逻辑拆分为更多可维护的服务,这就是微服务的出现。
微服务提高了团队所有权,使团队可以专注于特定的业务领域,无论其他服务的构建方式如何,都可以选择最佳的技术堆栈来解决问题,微前端将微服务的概念扩展到了前端世界。

什么是微前端?

Micro-frontends背后的想法是将网站或Web应用程序视为独立团队拥有的功能的组合。每个团队都有自己关心和专长的特定业务或任务领域。一个团队具有跨职能,并从数据库到用户界面端到端地开发功能。

设计原则

  • 团队所有权:整个团队负责开发属于特定业务领域的一组功能,包括开发,测试和部署过程。
  • 不可知的技术:无论使用什么框架,团队都可以选择Vue.js或React.js之类的任何框架。
    与自定义API相比,本机浏览器功能更受青睐:使用浏览器事件进行通信,而不是构建全局的PubSub系统。如果确实需要构建跨团队的API,请尝试使其尽可能简单。
  • 弹性站点:即使JavaScript失败或尚未执行,您的功能也应该很有用。使用通用渲染和渐进增强来改善可感知的性能。

我们要建造什么?

使用 Vue.js,React.js 及 Hypernova 构建微前端服务_第3张图片

我们有两个微前端,第一个负责使用React.js渲染Navbar,第二个负责使用Vue.js渲染产品列表。
两者都是同构Web应用程序,因此视图是在服务器端呈现的,并在客户端进行了水合处理,以使它们在客户端具有动态性。

此仓库中提供了代码示例的代码。

https://github.com/marconi1992/hypernova-micro-frontends

该项目包含三个文件夹:

  • hypernova-server-vue:包含使用Vue.js构建的产品列表组件。
  • hypernova-server-react:包含使用React.js构建的Navbar组件
  • hypernova-aggregator:向提供数据的超新星服务器请求视图,并在HTML文档中组成所有视图。
    CSS文件由聚合器分发,因为它通常负责品牌和外观。

Hypernova Vue

我们在内部有 hypernova-server-vue 一个超新星服务器的入口点 src/index.js

您可以使用yarn dev或运行它 npm run dev

index.js

import hypernova from 'hypernova/server'
import {
      renderVue, Vue } from 'hypernova-vue'
import express from 'express'
import path from 'path'

import ProductList from './components/ProductList.vue'

hypernova({
     
  devMode: true,
  getComponent (name, context) {
     
    if (name === 'ProductList') {
     
      return renderVue(name, Vue.extend(ProductList))
    }
  },
  port: 3030,

  createApplication () {
     
    const app = express()

    app.use(express.static(path.join(process.cwd(), 'dist')))

    return app
  }
})

getComponent 提供正确的成分与它的装饰 renderVue 功能 hypernova-vue

ProductList.vue

<template>
  <div class="k-product-list">
    <h2 class="k-product-list__header">{
     {
     title}}</h2>
    <ul>
      <li v-for="(item, idx) in items" :key="idx" class="k-product-item" @click="select(item)">
        <img :src="item.imageUrl" class="k-product-item__image">
        <h4 class="k-product-item__title">{
     {
      item.title }}</h4>
      </li>
    </ul>
    <button @click="addItem">Add Item</button>
  </div>
</template>

<script>
export default {
     
  props: {
     
    title: {
     
      type: String,
      required: true
    },
    items: {
     
      type: Array,
      default: () => []
    }
  },
  methods: {
     
    addItem() {
     
      this.items.push({
      title: `Product ${
       this.items.length + 1}`, imageUrl: 'https://via.placeholder.com/400' })
    },
    select(item) {
     
      const event = new CustomEvent('itemSelected', {
      detail: item });
      document.dispatchEvent(event)
    }
  }
}
</script>

这是一个简单的vue组件,可接收诸如之类的道具titleitems但是如您所见,它具有一个名为的方法select,该方法可创建CustomEvent并使用文档引用进行分派。通信微前端的机制与微服务非常相似,只是微前端使用DOM API作为发布/订阅。

client.js

import {
      renderVue, Vue } from 'hypernova-vue'
import ProductList from './components/ProductList.vue'

renderVue('ProductList', Vue.extend(ProductList))()

client.js脚本是我们客户端水合的入口点。

Hypernova React

我们具有hypernova-server-reacthypernova-server-vue相似的设置

您可以使用yarn dev或运行它npm run dev

index.js

import express from 'express';
import path from 'path';
import hypernova from 'hypernova/server';
import {
      renderReact } from 'hypernova-react';

import Header from './components/Header';

hypernova({
     
  devMode: true,
  getComponent(name) {
     
    if (name === 'Header') {
     
      return renderReact(name, Header);
    }

    return null;
  },
  port: 3031,

  createApplication() {
     
    const app = express();

    app.use(express.static(path.join(process.cwd(), 'dist')));

    return app;
  },
});

如您所见,入口点与入口点非常相似,但是它使用renderReacthypernova-react代替功能。

Header.jsx

import React from 'react';
import PropTypes from 'prop-types';

import NavBar from './NavBar';

class Header extends React.Component {
     
  constructor(props) {
     
    super(props);
    this.state = {
     
      itemsSelected: 0,
      item: null,
    };
    this.itemSelected = this.itemSelected.bind(this);
  }

  componentDidMount() {
     
    document.addEventListener('itemSelected', this.itemSelected);
  }

  componentWillUnmount() {
     
    document.removeEventListener('itemSelected', this.itemSelected);
  }

  itemSelected({
      detail: item }) {
     
    const {
      itemsSelected } = this.state;
    this.setState({
      itemsSelected: itemsSelected + 1, item });
  }

  render() {
     
    const {
      title, links } = this.props;
    const {
      itemsSelected, item } = this.state;
    return (
      <header className="k-header">
        <div className="k-header__brand">{
     title}</div>
        {
      item && <span className="k-header__last-item">{
     `Last Item: ${
       item.title}`}</span> }
        <span className="k-header__space" />
        <span>{
     `Items Clicked: ${
       itemsSelected}`}</span>
        <NavBar links={
     links} />
      </header>
    );
  }
}

Header.propTypes = {
     
  title: PropTypes.string.isRequired,
  links: NavBar.propTypes.links,
};

Header.defaultProps = {
     
  links: [],
};

export default Header;

Header.jsx部件订阅该itemSelected事件componentDidMount的方法,因此,每一个时间itemSelected事件被调度,则增加itemsSelected的状态变量,并存储选择的最后一项。

client.js

import {
      renderReact } from 'hypernova-react';

import Header from './components/Header';

renderReact('Header', Header)();

Hypernova Aggregator

聚合器是一个基本的快速应用程序,它使用axios向超新星服务器请求视图,并使用插值法将结果HTML放入模板中,并从每个微前端添加必要的客户端脚本。

您可以使用yarn start或运行它npm run start

index.js

const express = require('express')
const path = require('path')
const {
      getContent } = require('./services/content')
const {
      getLayout } = require('./services/layout')

const app = express()

app.use(express.static(path.join(__dirname, 'public')))

app.get('/', async (req, res) => {
     
  const promises = [getContent(), getLayout()]
  const [content, {
      header }] = await Promise.all(promises)
  const html = `
    
    
    
      
      
      
      Document
      
    
    
      ${
       header.html}
      ${
       content.html}
      
      
    
    
  `

  return res.send(html)
})

app.listen(8080, () => console.log('Aggregator Running'))

最后一步是在浏览器中打开http://localhost:8080/,您将看到呈现的页面,您可以通过查看页面源代码来确认是服务器端呈现的。

使用 Vue.js,React.js 及 Hypernova 构建微前端服务_第4张图片

结语

正如您已经注意到的,使用超新星可以实现微前端的主要设计原则,我们为每个微前端使用超新星服务器来推广团队所有权和技术不可知论原则 ,以便呈现与某个业务领域或功能相关的组件。此外,我们推广具有同构Web应用程序的弹性站点原理,即使javascript脚本失败,该应用程序也将可用,最后,我们使用DOM事件推广本机浏览器功能以传达我们的微前端

参考资料:https://medium.com/js-dojo/micro-frontends-using-vue-js-react-js-and-hypernova-af606a774602

你可能感兴趣的:(vue,javascript,react,vue,javascript,微前端)