Import Maps 必须用 <script type="importmap"> 声明且置于所有 type="module" 脚本之前,映射值须为完整 HTTPS URL 或合法相对路径(如 ./vendor/lodash.min.js),目标资源必须是含 export 的 ESM 模块且响应头为 Content-Type: application/javascript。

Import Maps 能直接把 import { debounce } from 'lodash' 这种裸模块名映射到 CDN URL,但配置错一行就会报 Failed to resolve module specifier 或 TypeError: Cannot resolve module。关键不在“会不会写 JSON”,而在路径格式、协议限制和模块兼容性这三点上。
importmap 必须用 script type="importmap" 声明,且位置不能错
它不是随便丢在 HTML 任意位置的配置块。必须放在 <head> 内,或者至少在所有 <script type="module"> 标签之前——否则浏览器解析 JS 时还没读到映射表,直接报错。
- 错误写法:
<script type="module">import _ from 'lodash'</script>放在<script type="importmap">上面 - 正确顺序:先
<script type="importmap">{ "imports": { ... } }</script>,再任何type="module"脚本 - 不支持
async或defer—— 它必须同步解析,没有加载时机可选
映射值必须是完整 URL 或合法相对路径,不能是裸文件名
"lodash": "lodash.js" 这种写法一定失败。浏览器只接受带协议的 URL(如 https://cdn.skypack.dev/lodash@4.17.21)或以 /、./、../ 开头的路径(如 "lodash": "/js/lodash.esm.js")。
-
"lodash": "node_modules/lodash/index.js"→ ❌ 无协议、无根斜杠,被忽略 -
"lodash": "./vendor/lodash.min.js"→ ✅ 相对路径合法,但要求该文件是 ESM 格式(含export) -
"react": "https://esm.sh/react@18.2.0"→ ✅ 推荐,CDN 返回的是标准 ESM 入口 - HTTP 协议仅限
http://localhost,线上必须 HTTPS,否则被浏览器静默拒绝
目标资源必须是合法 ES 模块,否则运行时报错
即使 URL 可访问、状态码 200,如果响应头没设 Content-Type: application/javascript,或脚本本身没导出(比如 UMD 版本没加 export),依然会卡在 Cannot resolve module。
立即学习“前端免费学习笔记(深入)”;
- 优先选明确标注 ESM 的 CDN:如
https://esm.sh/、https://cdn.skypack.dev/、https://cdn.jsdelivr.net/npm/xxx@y.z.+esm - 避免用
.min.js后缀的压缩版,除非确认它已转为 ESM(很多传统 CDN 的 min 版仍是 IIFE) - 本地调试时,可用
http-server -c-1启服务,避免 Chrome 对file://协议禁用 importmap
scopes 是按加载路径生效的,不是按当前页面 URL
很多人以为 scopes 是“这个页面下才生效”,其实它是看被导入的模块 URL 是否匹配 scope 键名。比如:
{"imports": {"lodash": "/lib/lodash.js"}, "scopes": {"/modules/chart/": {"d3": "https://cdn.skypack.dev/d3@7"}}}只有当某个模块通过 import * as d3 from 'd3' 被加载,且这个 import 语句出现在 /modules/chart/chart.js 这类路径的模块里时,scopes 规则才触发。
-
scopes不影响主页面的type="module"脚本,只影响它动态导入或间接依赖的子模块 - 键名必须是路径前缀,结尾不加
/也能匹配,但建议统一加,避免歧义 - 不要试图用
scopes实现“不同环境不同 CDN”,那更适合服务端渲染时动态注入imports
最容易被忽略的是:importmap 一旦解析完成就不可更改,也没有 API 可以重新注册或 patch。上线后想切 CDN 地址,只能刷新页面或靠服务端输出新配置——它本质上是一次性声明,不是运行时路由表。



















