html代码质量直接影响微前端子应用挂载、样式隔离与事件绑定,必须导出生命周期函数、配置umd输出、使用相对路径、封闭shadow dom、避免硬编码id及内联脚本执行。

HTML 代码质量在微前端里不是“写得语义化就行”,而是直接影响子应用是否能被正确挂载、样式是否穿透、事件是否丢失、甚至整个容器崩溃。不处理好,qiankun 启动后白屏、mount 报错、document.getElementById 返回 null 都是常态。
子应用 HTML 必须导出生命周期函数,否则根本无法接入
主应用(如 qiankun)加载子应用时,只认 bootstrap、mount、unmount 这三个函数。它们不是可选钩子,是强制接口。
- Vue CLI 默认构建不暴露这些函数——必须在
main.js外层手动包裹导出逻辑,不能只调用createApp().mount() - React 项目不能用
ReactDOM.render()一次性挂载,要改成接受容器节点参数的函数式挂载,例如:export function mount(props) { ReactDOM.createRoot(props.container).render(<app></app>); } - Webpack 构建需显式设置:
output.library: 'app-name'和output.libraryTarget: 'umd',否则主应用无法通过import()或全局变量访问子应用模块 - 子应用
public/index.html中所有资源路径(js、css)必须用相对路径,或由主应用注入的__webpack_public_path__动态修正,否则加载 404
HTML 模板不能靠 <template></template> 自动隔离,必须配合 attachShadow({ mode: 'closed' })
<template></template> 标签只是静态占位符,不解析、不执行、不隔离。把它克隆进 light DOM 后,所有 class、id、<style></style> 全部裸露,照样被主应用 CSS 穿透。
- 常见错误:子应用模板里写
<div class="header">,结果被主应用的 <code>.header { margin-top: 20px }改了间距 - 必须从
tmpl.content克隆,禁用innerHTML—— 否则<input checked>、<select></select>的状态全丢 - 克隆后挂载前,必须先调用
this.attachShadow({ mode: 'closed' }),再用shadowRoot.appendChild(fragment);延迟到connectedCallback再调用,等于污染已发生 -
mode: 'open'允许任意脚本读写shadowRoot,等于放弃隔离能力;CI/CD 应强制检查所有attachShadow调用是否含{ mode: 'closed' } - 子应用 HTML 中直接写了
<style>body { margin: 0 }</style>—— 这段 CSS 会逃逸到全局作用域 - 用了
styled-components或emotion,其运行时注入的<style></style>不受沙箱管控 - 子应用加载后又动态
appendChild新的<style></style>或<link>,沙箱无法感知 - Ant Design 等组件库的
Modal默认挂载到document.body,脱离子应用容器,样式和事件都错乱 - 解决方式不是关沙箱,而是:启用
getPublicPath()+ 使用 CSS Modules / scoped style + 所有弹窗类组件显式指定getContainer到子应用根节点 - 禁止在模板中写死
id属性,改用data-id或动态生成唯一值,例如:data-id="${Date.now()}-${Math.random().toString(36).substr(2, 9)}" - 模板内含
<script>console.log('init')</script>?克隆后插入 DOM 也不会执行——脚本只在初始解析时触发,必须用沙箱重绑定后执行 - 挂载时禁用
innerHTML +=,否则已绑定的事件监听器会被销毁;应统一用container.appendChild(fragment) - 所有
<style></style>内容需提取为CSSStyleSheet实例,再通过shadowRoot.adoptedStyleSheets = [sheet]注入;直接赋值shadowRoot.innerHTML = htmlString会绕过封装,带来 XSS 风险
内联 <style></style> 和动态插入节点会逃逸沙箱,必须拦截处理
qiankun 默认的样式沙箱(snapshot + style 标签增删)对以下情况完全无效:
HTML 中硬编码 id 是危险操作,必须改用动态唯一标识
多个子应用共用同一份 HTML 模板,但各自填充后若保留 id="modal",会导致 document.getElementById('modal') 返回错对象,JS 逻辑直接失效。
真正卡住微前端落地的,往往不是 JS 生命周期或路由同步,而是 HTML 层面那些看似“无关紧要”的细节:一个没处理的 id、一段漏拦截的内联 <style></style>、一次错误的 cloneNode 调用,就足以让整个子应用不可用。它不像 JS 错误有堆栈可查,而是静默污染、偶发失效、难以复现。











