微服务实践和总结

H5原生组件web Component

Web Component 是一种用于构建可复用用户界面组件的技术,开发者可以创建自定义的 HTML 标签,并将其封装为包含逻辑和样式的独立组件,从而在任何 Web 应用中重复使用。

javascript 复制代码
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>web Component原生组件</title>
  </head>
  <body>
    <m-button type="primary">webComponent</m-button>

    <template id="m-btn">
      <button class="m-button">
        <slot>Default</slot>
      </button>
    </template>

    <template id="m-btn">
      <style type="text/css">
        .m-button {
          width: 100%;
          border: 1px solid #ebebeb;
        }
      </style>

      <div class="m-collapse">
        <slot></slot>
      </div>
    </template>

    <script type="text/javascript">
      class MButton extends HTMLElement {
        constructor() {
          super()

          let btnTmpl = document.getElementById('m-btn') // 定义模板并获取模板

          let shadow = this.attachShadow({ mode: 'open' }) // 配置 devtools 是否可查看 DOM 结构,open / close
          let cBtnTmpl = btnTmpl.content.cloneNode(true) // copy 模板便于重用

          cBtnTmpl.querySelector('.m-button').addEventListener('click', this.onClick)

          shadow.appendChild(cBtnTmpl) // 模板挂载 Shadow DOM
        }

        static get observedAttributes() {
          return ['type'] // 监控 type 属性是否改变
        }

        connectedCallback() {
          // 组件首次挂载时调用
        }

        attributeChangedCallback(key, oldValue, newValue) {
          // 组件更新时调用,key 为属性名,oldValue, newValue 为属性值
        }

        disconnectedCallback() {
          // 组件移除时调用
        }
      }
    </script>
  </body>
</html>

Shadow DOM

Shadow DOM 是 DOM nodes 的附属树。这种 Shadow DOM 子树可以与某宿主元素相关联,但并不作为该元素的普通子节点,而是会形成其自有的作用域;Shadow DOM 中的根及其子节点也不可见。

  • 不使用Shadow DOM
javascript 复制代码
<!DOCTYPE html>
    <html lang="en">
    <head><meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Web Components</title>
    <style>
        h1 {
            font-size: 20px;
            color: yellow;
        } 
    </style>
    </head>
    <body>
    <div></div>
    <hello-world></hello-world>
    <h1>Hello World! 外部</h1>
    <script type="module">
     class HelloWorld extends HTMLElement {
            constructor() {
                super();
                // 关闭 shadow DOM
                // this.attachShadow({ mode: 'open' });

                const d = document.createElement('div');
                const s = document.createElement('style');
                s.innerHTML = `h1 {
                            display: block;
                            padding: 10px;
                            background-color: #eee;
                        }`
                d.innerHTML = `
                    <h1>Hello World! 自定义组件内部</h1>
                `;

                this.appendChild(s);
                this.appendChild(d);
            }

            tag = 'hello-world'

            say(something) {
                console.log(`hello world, I want to say ${this.tag} ${something}`)
            }
        }

        window.customElements.define('hello-world', HelloWorld);
        const hw = document.querySelector('hello-world'); 
        hw.say('good');
 </script>
 </body>
 </html>
  • 使用 Shadow DOM
javascript 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Web Components</title>
<style>
 h1 {
    font-size: 20px;
    color: yellow;
} </style>
</head>
<body>
    <div></div>
    <hello-world></hello-world><h1>Hello World! 外部</h1>
    <script type="module"> class HelloWorld extends HTMLElement {
            constructor() {
                super();
                this.attachShadow({ mode: 'open' });
                this.shadowRoot.innerHTML = `
                    <style>
                        h1 {
                            font-size: 30px;
                            display: block;
                            padding: 10px;
                            background-color: #eee;
                        }
                    </style><h1>Hello World! 自定义组件内部</h1>
                `;
            }

            tag = 'hello-world'

            say(something) {
                console.log(`hello world, I want to say ${this.tag} ${something}`)
            }
        }

        window.customElements.define('hello-world', HelloWorld);
        const hw = document.querySelector('hello-world'); 
        hw.say('good'); 
        </script>
</body>
</html>

HTML templates 和 slot

元素允许开发者在 HTML 中定义一个模板,其中可以包含任意的 HTML 结构、文本和变量占位符。此元素及其内容不会在 DOM 中呈现,但仍可使用 JavaScript 去引用它。

微前端

回顾微前端的历史,最早的时候我们是利用 iframe 嵌入一个网页,这就是微前端的雏形。虽然接入时方便快捷,但它也存在一系列缺点,如:

  • 路由状态丢失,刷新一下,iframe 的 url 状态就丢失了
  • dom 割裂严重,弹窗只能在 iframe 内部展示,无法覆盖全局
  • 通信非常困难,只能通过 postmessage 传递序列化的消息
  • 白屏时间太长,对于有性能要求的应用来说无法接受

微前端的特点

路由隔离、js隔离、css隔离、预加载机制、通信机制、多微应用激活

javascript 复制代码
import microApp from '@micro-zoe/micro-app';
microApp.start();export function MyPage () {
 return (<div>    
      <h1>子应用</h1>  
       <micro-app 
           name='app1' // name(必传):应用名称  
           url='http://localhost:3000/' // url(必传):应用地址,会被自动补全为http://localhost:3000/index.html       
           baseroute='/my-page' // baseroute(可选):基座应用分配给子应用的基础路由,就是上面的 `/my-page`
        ></micro-app>    
   </div>  )}

js隔离(沙箱)

javascript 复制代码
export class SnapShot { 
proxy: Window & typeof globalThis 
constructor () { 
    this.proxy = window 
} 
// 沙箱激活 
active () { 
    // 创建一个沙箱快照 
    this.snapshot = new Map() 
    // 遍历全局环境 
    for (const key in window) { 
        this.snapshot[key] = window[key] 
    } 
} 
// 沙箱销毁 
inactive () { 
    for (const key in window) { 
         if (window[key] !== this.snapshot[key]) { 
             // 还原操作 
             window[key] = this.snapshot[key] 
         } 
    } }
 }

microApp 使用过程中碰到的问题

  • webpack-dev-server中添加headers解决父应用引入子应用不同域名跨域问题
javascript 复制代码
  headers: {
    'Access-Control-Allow-Origin': '*',
  }

原理解析

当调用 microApp.start() 后,会注册一个名为 micro-app 的自定义 webComponent 标签。我们可以从 中拿到子应用的线上入口地址

相关推荐
Java程序之猿12 小时前
微服务分布式(一、项目初始化)
分布式·微服务·架构
Yvemil714 小时前
《开启微服务之旅:Spring Boot Web开发举例》(一)
前端·spring boot·微服务
Yvemil718 小时前
《开启微服务之旅:Spring Boot Web开发》(二)
前端·spring boot·微服务
维李设论18 小时前
Node.js的Web服务在Nacos中的实践
前端·spring cloud·微服务·eureka·nacos·node.js·express
jwolf220 小时前
基于K8S的微服务:一、服务发现,负载均衡测试(附calico网络问题解决)
微服务·kubernetes·服务发现
Yvemil71 天前
《开启微服务之旅:Spring Boot Web开发举例》(二)
前端·spring boot·微服务
一个儒雅随和的男子1 天前
微服务详细教程之nacos和sentinel实战
微服务·架构·sentinel
Yvemil71 天前
《开启微服务之旅:Spring Boot Web开发》(三)
前端·spring boot·微服务
Java程序之猿1 天前
微服务分布式(二、注册中心Consul)
分布式·微服务·consul
Hello Dam1 天前
面向微服务的Spring Cloud Gateway的集成解决方案:用户登录认证与访问控制
spring cloud·微服务·云原生·架构·gateway·登录验证·单点登录