html子应用需手动实现bootstrap/mount/unmount三阶段生命周期,通过domparser解析执行script、容器前缀隔离样式、主应用统一接管路由,并严格清理定时器与事件监听器以防内存泄漏。

HTML 子应用是微前端中最轻量、兼容性最强的接入方式,但也是最容易出问题的——它不带构建时沙箱、无生命周期钩子、样式和脚本天然全局污染。直接用 iframe 是最省事,但路由、通信、性能全崩;用 fetch + innerHTML 看似灵活,却会丢失脚本执行上下文和事件绑定。真正能落地的方案,得绕过浏览器对纯 HTML 的“放养式”处理,主动接管加载、执行、卸载三个环节。
HTML 子应用必须实现 bootstrap/mount/unmount 三阶段
qiankun 或 single-spa 这类框架要求所有子应用暴露标准生命周期函数,而纯 HTML 没有 JS 入口。常见错误是只写一个 index.html 就扔进 registerMicroApps,结果 bootstrap 报错:找不到导出函数。
- 必须在 HTML 中内联或外链一个 JS 脚本,手动挂载到
window上,例如:window.bootstrap = async () => { /* 初始化逻辑,如预加载资源 */ };<br>window.mount = async (props) => {<br> const container = props.container || document.getElementById('sub-app-root');<br> container.innerHTML = '<div>Hello from HTML app</div>';<br> // 手动执行 script 标签(需 parse + eval)<br>};<br>window.unmount = async (props) => {<br> const container = props.container || document.getElementById('sub-app-root');<br> container.innerHTML = '';<br>}; - 避免在
mount中直接document.write或修改document.head,这会污染主应用样式和全局变量 - 如果子应用含第三方 SDK(如支付宝 JSAPI),需在
unmount中显式调用其清理方法,否则下次 mount 会重复初始化
如何安全执行 HTML 中的 inline script 和 external script
HTML 子应用里常带 <script></script> 标签,但直接插入 innerHTML 不会执行。这是浏览器安全策略,不是 bug。强行用 eval 或 new Function 有 XSS 风险,且无法访问模块作用域。
- 推荐做法:用 DOMParser 解析 HTML 字符串,遍历所有
<script></script>,对src属性的用document.createElement('script')动态加载,对 inline 脚本用setTimeout(() => { eval(scriptText) }, 0)延迟执行(确保 DOM 已就位) - 注意 script 执行顺序:HTML 中的
<script defer></script>或<script async></script>行为在动态插入时失效,必须按文档流顺序手动控制 - 若子应用依赖 jQuery 或其他全局库,确保主应用已加载且暴露在
window上,否则unmount后再mount可能报$ is not defined
样式隔离不能只靠 CSS Scoped 或 Shadow DOM
HTML 子应用没有构建时 CSS 处理能力,<style></style> 标签默认全局生效。用 scoped 没用(Vue 特性),用 Shadow DOM 则需手动创建 shadowRoot,但会切断事件冒泡和部分伪类选择器支持。
- 最简方案:给子应用容器加唯一 class 前缀,如
html-subapp-order,所有子应用 CSS 规则强制加上该前缀(可用 PostCSS 插件自动处理构建后的 CSS) - 更稳妥做法:在
mount时动态插入<style></style>并添加data-app-id="order"属性,在unmount时移除对应<style></style>标签,避免残留 - 禁用
!important—— 它会突破前缀隔离,导致样式泄漏;检查子应用是否用了 CSS Custom Properties(:root 变量),它们默认也是全局的
路由与 URL 同步必须由主应用统一接管
HTML 子应用没有路由系统,但它可能通过 window.location.hash 或 history.pushState 修改 URL。一旦多个 HTML 子应用都这么做,就会互相覆盖、丢失状态。
- 主应用必须禁用子应用的
history.pushState和replaceState,重写为props.setActiveApp('order')类型的跨应用通信 - 子应用内所有链接必须用
<a href="#" onclick="jumpTo('/order/detail')>,跳转逻辑由主应用的路由层统一解析 - URL 查询参数(如
?tab=payment)不能由子应用自行读取,应通过props注入,避免location.search在 unmount 后仍被误读
HTML 子应用看似简单,实则把所有“隐式契约”都摊开在你面前:没有构建工具兜底,没有框架帮你管理副作用,连 <script> 执行都要自己手搓。最容易被忽略的是资源清理——DOM 删除了,但定时器、事件监听器、全局变量还挂着,几次切换后内存就悄悄涨上去。上线前务必用 Chrome DevTools 的 Memory tab 对比 mount/unmount 前后的 heap snapshot。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











