type="module" 的 script 标签必须用相对或绝对 URL 路径引入模块:import 路径需以 /、./、../ 开头或含协议,不可用 bare specifier;file:// 协议下会因 CORS 和 MIME 类型限制失败,须用本地服务器;路径始终相对于当前 JS 文件而非 HTML 文件。

type="module" 的 script 标签必须用相对或绝对 URL 路径引入模块
浏览器对 <script type="module"> 有严格路径要求:所有 import 语句的模块路径不能是 bare specifier(比如 import { foo } from 'lodash'),必须带扩展名、协议或以 /、./、../ 开头。否则会报 TypeError: Failed to resolve module specifier。
常见错误写法:import utils from 'utils.js'(缺前缀)或 import utils from 'src/utils.js'(没点斜杠)——这些都会失败。
-
import { helper } from './utils.js'✅ 正确,显式指定相对路径 -
import { helper } from '/src/utils.js'✅ 正确,绝对路径(从根目录起) -
import { helper } from 'https://cdn.example.com/lib.js'✅ 正确,完整 URL -
import { helper } from 'utils.js'❌ 报错,不是合法模块说明符 -
import { helper } from 'src/utils.js'❌ 报错,缺少/或./
本地开发时 file:// 协议下 import 会失败
直接双击 HTML 文件打开(URL 是 file:///xxx/index.html),即使路径写对了,import 也会因跨域策略被拒绝,报 Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "" 或 CORS 错误。
这不是代码问题,而是浏览器安全限制:file 协议不支持模块加载所需的 MIME 类型校验和同源检查。
立即学习“前端免费学习笔记(深入)”;
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
- 必须用本地服务器启动,比如
npx serve、python3 -m http.server、VS Code Live Server 插件 - 确认服务返回的
Content-Type是text/javascript(.js 文件)或application/javascript - Chrome 控制台 Network 标签页里点 .js 文件,看 Response Headers 是否含
Content-Type
import 的路径是相对于当前 JS 文件,不是 HTML 文件
很多人以为 import 路径按 <script src="main.js"> 所在 HTML 的位置解析,其实不是。它始终相对于导入该语句的 JS 文件所在路径。
比如:index.html 引入 js/main.js,而 main.js 里写 import { log } from 'utils.js' —— 这个 utils.js 会从 js/ 目录下找,不是从 HTML 所在目录。
- 推荐统一用
./显式声明相对性,避免歧义:import { log } from './utils.js' - 如果
utils.js在上层目录,就写import { log } from '../lib/utils.js' - 不要依赖“当前工作目录”概念,浏览器没有这个上下文
动态 import() 和静态 import 的行为差异
import() 是函数调用,返回 Promise,路径可以是变量拼接;但静态 import 必须是字面量字符串,且构建工具(如 Vite、Webpack)无法在运行时解析变量路径。
所以这种写法永远不行:const name = 'utils'; import(`./${name}.js`) —— 静态分析阶段就报错,连打包都过不了。
- 动态导入可用:
const { log } = await import('./utils.js')(注意 await 在顶层需加type="module"且脚本为 async) - 路径拼接只允许出现在
import()内,且仍要满足 URL 规则(如不能是import(someVar)且someVar是纯字符串变量) - ESM 不支持 Node.js 那样的包名自动解析,没
node_modules查找逻辑


















