优秀的编程知识分享平台

网站首页 > 技术文章 正文

揭秘微前端import-html-entry的强大之处

nanyue 2024-12-28 14:32:34 技术文章 3 ℃

概述

import-html-entry 是一个用于动态加载和处理 HTML 和 JavaScript 文件的库,主要应用于微前端架构中。

它通过从远程服务器获取 HTML 内容,解析其中的 JavaScript 和 CSS,支持在主应用中无缝集成和执行。

作为 qiankun 微前端框架的核心依赖之一,import-html-entry 提供了强大的动态加载与执行功能。

qiankun 框架中,它通过 HTML Entry 的方式解决了 JS Entry 的问题,使得集成微应用变得像嵌入 iframe 一样简单。


使用方法

安装

可以通过 npm 或 yarn 安装 import-html-entry:

npm install import-html-entry

或:

yarn add import-html-entry

基本用法

以下是一个简单的示例,演示如何使用 import-html-entry 加载远程 HTML 文件。官方示例中,index.html 使用 import-html-entry 加载 ./template.html:

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
<script type="module">
    window.onerror = (e) => console.log('error', e.message);
    window.onunhandledrejection = (e) => console.log('unhandledrejection', e.reason.message);

    import('./dist/index.js').then(({ importEntry }) => {
        importEntry('./template.html')
            .then((res) => {
                console.log(res);
                return res.execScripts().then((exports) => {
                    console.log(exports);
                });
            })
            .catch((e) => console.log('importEntry failed', e.message));
    });
</script>
</body>
</html>

template.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test</title>
    <link href="https://unpkg.com/antd@3.13.6/dist/antd.min.css" rel="stylesheet">
    <link href="https://unpkg.com/bootstrap@4.3.1/dist/css/bootstrap-grid.min.css" rel="stylesheet">
</head>
<body>
<script src="./a.js"></script>
<script ignore>alert(1)</script>
<script src="./b.js"></script>
<script src="./c.js"></script>
<script src="https://unpkg.com/react@16.4.2/umd/react.production.min.js"></script>
<script src="https://unpkg.com/mobx@5.0.3/lib/mobx.umd.js"></script>
<script src="https://www.baidu.com"></script>
</body>
</html>

import-html-entry 处理后的template.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test</title>
    <style>
        /* antd styles inlined */
    </style>
    <style>
        /* bootstrap styles inlined */
    </style>
</head>
<body>
<!-- script http://127.0.0.1:7001/a.js replaced by import-html-entry -->
<!-- ignore asset js file replaced by import-html-entry -->
<!-- script http://127.0.0.1:7001/b.js replaced by import-html-entry -->
<!-- script http://127.0.0.1:7001/c.js replaced by import-html-entry -->
<!-- script https://unpkg.com/react@16.4.2/umd/react.production.min.js replaced by import-html-entry -->
<!-- script https://unpkg.com/mobx@5.0.3/lib/mobx.umd.js replaced by import-html-entry -->
<!-- script https://www.baidu.com/ replaced by import-html-entry -->
</body>
</html>

经过处理,HTML 文件中的 CSS 被转换为内联样式,而 <script> 标签被注释。

importEntry 返回值包括以下内容:

  1. template:处理后的 HTML 内容。
  2. assetPublicPath:资源路径。
  3. getExternalScripts:返回外部脚本信息的函数。
  4. getExternalStyleSheets:返回外部样式表信息的函数。
  5. execScripts:执行 HTML 中脚本的 JavaScript 执行器,可通过传入代理对象实现 JavaScript 沙箱化。

通过上述处理,import-html-entry 能够访问 HTML 中的 CSS 和 JavaScript 内容,其中 CSS 被内联化,而 JavaScript 可以通过 execScripts 在隔离环境中执行,实现沙箱化效果。


在 qiankun 中的使用

观察 qiankun 源代码中 import-html-entry 的使用:

// src/loader.js 第 266 行
const { template, execScripts, assetPublicPath, getExternalScripts } = await importEntry(entry, importEntryOpts);

// 第 347 行
const scriptExports: any = await execScripts(global, sandbox && !useLooseSandbox, {
    scopedGlobalVariables: speedySandbox ? cachedGlobals : [],
});

// 从模块导出中提取生命周期钩子
const { bootstrap, mount, unmount, update } = getLifecyclesFromExports(
  scriptExports,
  appName,
  global,
  sandboxContainer?.instance?.latestSetProp,
);

可以看到:

  1. 使用 importEntry 获取处理后的 HTML,包括 JS 执行器。
  2. 使用 execScripts 执行脚本,传递全局上下文。
  3. 从模块导出中提取生命周期函数(如 bootstrap、mount、unmount 等)。

核心功能

import-html-entry 的核心功能如下:

  1. 获取并处理 HTML:通过 fetch 获取 HTML 内容,解析模板并提取 HTML、CSS 和 JS,移除外部链接的 CSS 和 JS 文件。
  2. 内嵌 CSS:将 <style> 标签中的 CSS 内联到 HTML。
  3. 执行 JavaScript:支持执行页面级 JavaScript,并加载所有外部 JS 文件,同时确保 JavaScript 在隔离环境中运行,避免污染全局作用域。

在微前端场景下,import-html-entry 能够从指定 URL 加载子应用的 HTML 文件,嵌入对应的 CSS,并在受控环境中执行所有 JavaScript,确保其不干扰全局作用域。


execScripts 的实现

通过 getExecutableScript 实现 JS 沙箱:

function getExecutableScript(scriptSrc, scriptText, opts = {}) {
    const { proxy, strictGlobal, scopedGlobalVariables = [] } = opts;
    const sourceUrl = isInlineCode(scriptSrc) ? '' : `//# sourceURL=${scriptSrc}\n`;

    const scopedGlobalVariableDefinition = scopedGlobalVariables.length
        ? `const {${scopedGlobalVariables.join(',')}}=this;`
        : '';

    const globalWindow = (0, eval)('window');
    globalWindow.proxy = proxy;

    return strictGlobal
        ? `;(function(){with(this){${scopedGlobalVariableDefinition}${scriptText}\n${sourceUrl}}}).bind(window.proxy)();`
        : `;(function(window, self, globalThis){${scriptText}\n${sourceUrl}}).bind(window.proxy)(window.proxy, window.proxy, window.proxy);`;
}

processTpl

通过 processTpl 方法,import-html-entry 实现以下功能:

  • 替换 HTML。
  • 提供 JS 入口点列表。
  • 提供样式表列表。
  • 确定入口文件。

这一切为微前端应用的动态加载与执行提供了高效解决方案。

Tags:

最近发表
标签列表