data-env 属性必须写在 标签上,因为 document.documentelement 指向该元素,只有此处设置才能在 dom 加载瞬间被可靠读取,避免 ssr 或微前端场景下读取为空、行为不可控等问题。

data-env 属性必须写在 html> 标签上
因为 document.documentElement 指向的就是 元素,只有写在这里,dataset.env 才能在 DOM 加载完成瞬间被读取。写在
常见错误包括:
- 把
data-env="test"放在<div id="app"> 里——子应用或早期脚本根本拿不到 <li>用 JS 动态设置:<code>document.body.dataset.env = 'prod'——首屏 CSS、预加载逻辑已执行完毕 - 多个
data-env并存(比如 和 都有)——dataset.env只取第一个匹配的,行为不可控 - Django 模板:
- Nginx sub_filter:
sub_filter '' ''; - Next.js App Router:在
src/app/layout.tsx中用process.env.NODE_ENV注入属性(需配置output: 'export'或使用dynamic: 'force-static')
服务端渲染时由模板引擎注入,不是 JS 替换
构建时静态替换(如 Webpack 的 html-webpack-plugin)只适用于纯前端打包场景;一旦走 SSR(Django、Next.js、Nuxt),就必须靠服务端模板变量注入,否则构建产物无法区分环境。
可靠做法:
严禁在 HTML 模板里写 <script>document.documentElement.dataset.env = ...</script> —— 这等于把环境判断延迟到 JS 执行后,破坏了 CSS 层和资源预加载的环境感知能力。
JS 读取后必须校验值合法性
document.documentElement.dataset.env 返回的是字符串,但不保证是预期值。用户可手动修改 DOM,CDN 缓存错发、构建脚本漏替换都会导致值为 undefined、"dev "(带空格)、"staging"(未在白名单中)等非法状态。
安全读取模式:
const env = document.documentElement.dataset.env?.trim();
if (!['dev', 'test', 'prod'].includes(env)) {
throw new Error(`Invalid environment: ${env}`);
}
注意点:
- 不用
|| 'prod'默认兜底——掩盖配置错误 - 不缓存到模块顶层变量——SSR 渲染时 Node 环境和浏览器环境共享同一份代码,
env值可能错乱 - 微前端子应用不能自己读
dataset.env,必须由主应用通过 props 或全局事件透传
CSS 用属性选择器控制环境相关样式,别用 class
写 [data-env="test"] .debug-toolbar { display: block; } 是安全且语义清晰的;而写 .env-test .debug-toolbar 会污染 class 命名空间,且无法与 HTML 层的环境标识形成强绑定。
关键限制:
- CSS 层只能做显隐、颜色、尺寸等视觉控制,**不能用来隔离敏感逻辑**——DOM 仍在源码里,测试用的 mock 接口地址、调试按钮的
onclick行为必须从 HTML 中彻底移除,而不是靠display: none隐藏 - 不要在 CSS 中依赖
process.env.NODE_ENV——纯 CSS 文件不支持构建时变量替换,Vite/Webpack 的 DefinePlugin 对它无效 - CDN 缓存必须按
data-env值做 cache key 分片,否则data-env="test"的 HTML 被缓存并返回给生产流量,后果严重











