HTML4不支持type="module"等HTML5脚本属性,导致无法使用ES模块、动态模块加载及跨域错误堆栈等现代功能,必须依赖打包工具;HTML5才正确定义并启用这些特性。

HTML4 中 script 标签不支持 type="module"
HTML4 规范下, 只认 type="text/javascript"(或省略),浏览器遇到 type="module" 会直接忽略或报解析错误。即使你写了 ES6 模块语法(如 import / export),在非 HTML5 文档中也不会执行——不是语法报错,而是根本没被当作 JS 加载。
实际影响:
- 无法使用原生模块机制,必须靠打包工具(如 Webpack)转成 IIFE 或 UMD
-
defer行为不统一:HTML4 不规范支持defer,部分老浏览器会忽略它,脚本仍阻塞解析 - 没有
crossorigin属性,无法正确获取跨域脚本的错误堆栈(error.stack为空)
HTML5 新增的 script 属性直接影响 API 可用性
HTML5 明确定义了多个 属性,它们不是“锦上添花”,而是启用某些现代 API 的前提条件:
-
type="module":开启 ES 模块系统 → 启用import.meta.url、顶层 await(仅模块内)、静态 import 分析 -
async+type="module":模块可异步加载且不阻塞,但注意:模块默认defer,加async会改变执行时机 -
crossorigin="anonymous":允许跨域脚本触发window.onerror并提供完整错误信息,否则error.filename和error.lineno均为0 -
referrerpolicy="no-referrer":影响fetch()和XMLHttpRequest发出时的Referer头,进而影响某些后端鉴权逻辑
HTML5 才支持 script 动态创建时的模块加载
在 HTML5 环境中,你可以用 JS 动态插入模块脚本,而 HTML4 下这会直接失败:
立即学习“前端免费学习笔记(深入)”;
const script = document.createElement('script');
script.type = 'module';
script.src = './utils.js';
document.head.appendChild(script);
关键点:
- 动态创建的
type="module"脚本会被浏览器识别并按模块规则加载(有作用域隔离、自动defer) - HTML4 下该
script元素会被当成普通脚本处理,但import语句会立即抛SyntaxError: Unexpected token 'import' - 若需兼容旧环境,不能依赖
document.createElement('script').type = 'module',应检测HTMLScriptElement.prototype.type是否支持 module
API 调用范围差异本质是执行上下文不同
HTML4 的 总是在全局作用域执行;HTML5 的模块脚本则自带模块作用域 —— 这导致同一段代码在两种环境下调用 API 的行为可能完全不同:
-
console.log(this):HTML4 中是window,HTML5 模块中是undefined(严格模式下) -
var x = 1:HTML4 中挂到window.x,HTML5 模块中仅在模块内可见 -
fetch()、localStorage等 API 虽然都存在,但模块中若未显式声明import,就无法访问其他模块导出的封装逻辑(比如一个封装了fetch重试机制的apiClient) - Service Worker 注册只接受 HTTPS + HTML5 页面,且注册脚本本身也必须是模块或传统脚本,但模块内调用
navigator.serviceWorker.register()是完全合法的
最易被忽略的是:很多构建工具(如 Vite、Webpack)默认生成 HTML5 文档类型,但开发者常误以为“只要用了 import 就是模块”,却忘了检查页面是否真的以 开头、 是否被正确解析 —— 缺一不可。











