低代码平台-远程加载组件

881 阅读1分钟

前言

我 si 在做 low-code 平台时候,用户可以在平台查询物料、使用物料等,当使用某个组件时候就需要远程加载组件

远程组件加载

概述

加载远程 js 资源并渲染成组件

过程

  • 通过物料 cli 的 sdk 启动一个物料项目
  • 物料开发人员编写组件打包成(umd 规范)
  • cli 工具将组件上传到物料平台
  • 物料平台提供一个组件接口
  • 浏览器端调用该接口,获取其中的内容
  • 将内容渲染出来

方案

script 加载

function loadScript(url) {
  return new Promise((resolve, reject) => {
    const script = document.createElement("script");
    script.setAttribute("src", url);
    script.addEventListener("load", (res) => {
      const component = window["xx"]; // res.  library
      resolve(component);
    });
    script.onerror = reject;
  });
}

const MyComponent = () => {
  useEffect(() => {
    const url = "https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.js";
    loadScript(url);
  }, []);
  return <div></div>;
};

优点

  • 比较简单

缺点

  • 组件都会挂载到 window 上造成变量污染
  • 组件都会挂载到 window 上影响加载性能

沙箱隔离

function sandboxBlock(code) {
  const obj = {};
  // 代理了window对象
  const proxyWindow = new Proxy(window, {
    get(target, key) {
      return target[key] || obj[key];
    },
    set(target, key, value) {
      // new function 运行 set的值放在obj中
      return (obj[key] = value);
    },
  });
  window.proxyWindow = proxyWindow;

  const codeTel = `
    (function (window) {
      with (window) {
        ${code}
      }
    }).call(window.proxyWindow, window.proxyWindow)
  `;
  new Function(codeTel)();

  const targetKey = Object.keys(obj)[0];
  const target = obj[targetKey];

  return target.default ? target.default : target;
}
function loadScript(url) {
  return fetch(url)
    .then((response) => response.text())
    .then((code) => {
      const component = sandboxBlock(code);
      return component;
    });
}

const MyComponent = () => {
  useEffect(() => {
    const url = "https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.js";
    loadScript(url);
  }, []);
  return <div></div>;
};

优点

  • 自执行函数隔离出一个 js 运行的环境
  • 不会去污染 window

es6 import

import("https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.js").then(
  (mod) => {}
);

简单实现的

参考