直接用HTML模板生成器会出问题,因其未区分服务端可渲染部分与客户端强依赖部分,导致高并发下首屏白屏、资源404、脚本错乱;需通过命名空间变量、外链JS、全局资产变量等实现安全拆分。

为什么直接用 HTML 模板生成器会出问题
高并发大促页不是静态页面,模板化快拆的前提是:HTML 必须可预测、可隔离、可降级。很多团队用 html-webpack-plugin 或自研模板引擎批量生成,结果在秒杀开始后出现首屏白屏、资源 404、内联脚本执行错乱——根本原因是模板没区分「服务端可渲染部分」和「客户端强依赖部分」。
典型错误包括:__INIT_DATA__ 变量被多实例覆盖、data-spm 埋点 ID 重复、<link rel="preload"> 路径硬编码导致 CDN 切换失败。
- 所有动态插入的 JS 变量必须带命名空间,比如用
window.__PAGE_DATA__而非window.data -
<script>标签禁止内联复杂逻辑,只允许初始化或 JSON 注入;业务逻辑必须走src外链且带版本哈希 - 预加载资源路径统一走
__ASSET_BASE__全局变量,由 Node 中间层注入,不写死/static/或https://cdn.example.com/
如何用 Webpack + EJS 实现安全的模板拆分
不用 SSR 框架也能做可靠模板拆分,关键是把「结构骨架」和「数据驱动块」物理隔离。我们用 webpack-plugin-ejs 替代原生 html-webpack-plugin,配合三类模板文件:
-
layout.ejs:只含<html>结构、基础 meta、全局 CSS/JS 引入(无任何业务逻辑) -
block/banner.ejs:纯 HTML 片段,只接受传入的bannerList数组,不调用任何函数 -
page/goods-list.ejs:组合 layout + 多个 block,通过<% include('../block/banner.ejs') %>引入,不写 JS
关键约束:block/*.ejs 文件禁止出现 <script>、onclick、eval() 类代码;所有交互行为由外链 JS 通过 data-* 属性驱动。
立即学习“前端免费学习笔记(深入)”;
大促期间 HTML 必须关闭的三个特性
不是功能越多越好,高并发下某些“优化”反而成瓶颈:
- 禁用
defer和async在关键资源上——<script src="vendor.js" defer>在 Chrome 低版本中会阻塞 DOM 解析,改用<script src="vendor.js"></script>并确保它在<head>最前 - 移除所有
<picture>和srcset——CDN 对不同 DPR 的 URL 分发策略在流量洪峰时容易超时,统一用<img src="x1.jpg">+ CSS 缩放 - 关闭
gzip的dynamic模式(如 Nginx 的gzip_vary on)——Vary 头导致 CDN 缓存分裂,同一 URL 出现上百种缓存变体
上线前必须验证的 HTML 渲染一致性
模板生成的 HTML 在本地开发、测试环境、线上 CDN 三处必须完全一致,否则会出现「我本地能跑,线上白屏」。验证重点不是内容,而是结构特征:
- 检查
<body>内是否只存在一个id="app",且没有其他id与框架冲突(如 Vue 的id="root") - 运行
document.querySelectorAll('[data-spm]').length,确保值等于设计埋点数,且每个data-spm值唯一 - 用 Puppeteer 截取首屏 HTML 快照,对比三环境 diff,重点关注
<link href>、<script src>的路径是否都带完整版本号(如v=2.3.1)
最常被忽略的是:Node 中间层模板渲染时用了 JSON.stringify(data) 直接插入 HTML,但 data 里含 < 或 & 字符,导致 HTML 结构被截断。必须用 escapeHtml() 工具函数转义。



















