前端微服务化研究(六):沙盒实现

在写这个之前,我们先说下fetch

fetch

什么是fetch: 在msdn上是这样说的,提供了一个 JavaScript 接口,用于访问和操纵 HTTP 管道的一些具体部分,例如请求和响应。它还提供了一个全局 fetch() 方法,该方法提供了一种简单,合理的方式来跨网络异步获取资源。

这种功能以前是使用 XMLHttpRequest 实现的。Fetch 提供了一个更理想的替代方案,可以很容易地被其他技术使用,例如 Service Workers。Fetch 还提供了专门的逻辑空间来定义其他与 HTTP 相关的概念,例如 CORS 和 HTTP 的扩展。

fetch 与 jQuery.ajax()

当接收到一个代表错误的 HTTP 状态码时,从 fetch() 返回的 Promise 不会被标记为 reject, 即使响应的 HTTP 状态码是 404 或 500。相反,它会将 Promise 状态标记为 resolve (但是会将 resolve 的返回值的 ok 属性设置为 false ),仅当网络故障时或请求被阻止时,才会标记为 reject。

fetch() 可以不会接受跨域 cookies;你也可以不能使用 fetch() 建立起跨域会话。其他网站的 Set-Cookie 头部字段将会被无视。

fetch 不会发送 cookies。除非你使用了credentials 的初始化选项。(自 2017 年 8 月 25 日以后,默认的 credentials 政策变更为 same-origin。Firefox 也在 61.0b13 版本中进行了修改)

fetch简单使用

fetch('http://127.0.0.1:5500/demo1.html')
  .then(function(response) {
    return response.json();
  })
  .then(function(myJson) {
    console.log(myJson);
  });

在这里我为什么说fetch呢?因为接下要使用这个。因为我们都知道,微前端的出现就是为了解决各个项目之间的联系,也就是把各个项目合并到一个项目中,减少开发的时间。所以每个项目都有相应的地址或者入口,比我们公司都是vue的当页面应用,所以整合起来非常简单,我们通过fetch 请求入口地址拿到html,经过处理插入一个项目中就可以实现。如下:
我的一个项目地址是: http://192.168.1.140:7001/

fetch('http://192.168.1.140:7001/')
  .then(function(response) {
    return response.json();
  })
  .then(function(myJson) {
    console.log(myJson);
  });

在这里插入图片描述
在这里插入图片描述
然后通过解析dom,分别请求js和style
scripts

  const scripts = dom.querySelectorAll('script');
  const paromiseArr =
    scripts &&
    Array.from(scripts).map((item) => {
      if (item.src) {
        const url = window.location.protocol + '//' + window.location.host;
        const path = item.src.replace(url, '');
        const needEntryPath = !/(http|https):\/\/([\w.]+\/?)\S*/.test(path);
        return fetch(`${needEntryPath ? entryPath : ''}${item.src}`.replace(url, '')).then(
          function (response) {
            return response.text();
          }
        );
      } else {
        return Promise.resolve(item.textContent);
      }
    });
  const res = await Promise.all(paromiseArr);
  if (res && res.length > 0) {
    res.forEach((item) => {
      const script = document.createElement('script');
      script.innerText = item;
      subapp.appendChild(script);
    });
  }

style

  const arr = [];
  const styles = dom.querySelectorAll('style');
  const links = Array.from(dom.querySelectorAll('link')).filter(
    (item) => item.rel === 'stylesheet'
  );
  const realArr = arr.concat(styles,links)
  const paromiseArr =
    arr &&
    Array.from(realArr).map((item) => {
      if (item.rel) {
        const url = window.location.protocol + '//' + window.location.host;
        const path = item.href.replace(url, '');
        const needEntryPath = !/(http|https):\/\/([\w.]+\/?)\S*/.test(path);
        return fetch(`${needEntryPath ? entryPath : ''}${item.href}`.replace(url, '')).then(
          function (response) {
            return response.text();
          }
        );
      } else {
        return Promise.resolve(item.textContent);
      }
    });
  const res = await Promise.all(paromiseArr);
  if (res && res.length > 0) {
    res.forEach((item) => {
      const style = document.createElement('style');
      style.innerHTML = item;
      subapp.appendChild(style);
    });
  }

完整的

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>demo</title>
</head>
<body>
  <div>
    <!-- <custom-element>sadasdasdasdas</custom-element> -->
    <div id="main-content"></div>
  </div>
  <script>
    fetch('http://192.168.1.140:7001/').then(function(response) {
      return response.text()
    }).then(async function (text) {
      const mainApp = document.querySelector('#main-content');
      let tempNode = document.createElement('div')
      tempNode.innerHTML = text
      mainApp.appendChild(tempNode)
      return { tempNode, mainApp }
    }).then(async function ({ tempNode, mainApp}) {
      await loadScripts()
      await loadStyle()
    })

    async function loadScripts (dom, mainApp) {
        const scripts = tempNode.querySelectorAll('script');
        const paromiseArr =
          scripts &&
          Array.from(scripts).map((item) => {
            if (item.src) {
              const url = window.location.protocol + '//' + window.location.host;
              const path = item.src.replace(url, '');
              const needEntryPath = !/(http|https):\/\/([\w.]+\/?)\S*/.test(path);
              return fetch(`${needEntryPath ? entryPath : ''}${item.src}`.replace(url, '')).then(
                function (response) {
                  return response.text();
                }
              );
            } else {
              return Promise.resolve(item.textContent);
            }
          });
        const res = await Promise.all(paromiseArr);
        if (res && res.length > 0) {
          res.forEach((item) => {
            const script = document.createElement('script')
            script.innerText = item
            mainApp.appendChild(script)
          })
        }
    }
    async function loadStyle (dom, mainApp) {
      const scripts = dom.querySelectorAll('script');
      const paromiseArr =
        scripts &&
        Array.from(scripts).map((item) => {
          if (item.src) {
            const url = window.location.protocol + '//' + window.location.host;
            const path = item.src.replace(url, '');
            const needEntryPath = !/(http|https):\/\/([\w.]+\/?)\S*/.test(path);
            return fetch(`${needEntryPath ? entryPath : ''}${item.src}`.replace(url, '')).then(
              function (response) {
                return response.text();
              }
            );
          } else {
            return Promise.resolve(item.textContent);
          }
        });
      const res = await Promise.all(paromiseArr);
      if (res && res.length > 0) {
        res.forEach((item) => {
          const script = document.createElement('script');
          script.innerText = item;
          mainApp.appendChild(script);
        });
      }
    }
  </script>
</body>
</html>

初步思路是这样的实现的的原理;
更完整的请看这篇的实现

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

禅思院

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值