你以为 npm 包只能在 Node.js 里用?今天 Import Maps 把这件事彻底变了
写完这句 import React from "react",你在浏览器里直接打开——它会报一个错:import raw specifier must be a URL。因为裸的 specifier(就是这种不带路径的模块名)在浏览器眼里什么都不是,这是 Node.js 和构建工具做的事情,和浏览器没关系。
这件事今天被 Import Maps 彻底变了。
一个 JSON 块,把裸 specifier 变成真实 URL
Import Maps 就是 HTML 里的一个 <script type="importmap">,里面是一段 JSON,告诉浏览器:「看到 react 这个名字,就去加载这个 URL」。
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react@18.3.1",
"react-dom/client": "https://esm.sh/react-dom@18.3.1/client"
}
}
</script>
<script type="module">
import { useState } from "react";
import { createRoot } from "react-dom/client";
// 正常写你的代码
</script>
版本号直接钉死在 URL 里。升级就是改一个字符串,不用动任何一行业务代码。
配 esm.sh,npm 包直接在浏览器里跑
Import Maps 的最佳拍档是 esm.sh——这个 CDN 会自动把 npm 包转成浏览器能直接加载的 ES Module,不需要你做任何转换:
- 写
https://esm.sh/react@19.2.4就是 React 19 - 写
https://esm.sh/preact@10.22.1就是 Preact - 写
https://esm.sh/date-fns@3.6.0/format就是 date-fns 的某个子路径
配好 import map 之后,你的项目里可以完全不需要 Node.js、不需要 npm install、不需要 Vite、不需要 webpack。浏览器自己会解析、会加载、会缓存。
三步解析规则,最长匹配优先
Import Maps 的 specifier 解析走三步:
- 如果是相对或绝对 URL(
./x.js或https://...),直接走 URL 解析,不查 import map - 如果有 scope 匹配(按加载模块的路径),用 scope 里的映射,路径最长优先
- 都不匹配,走顶层
imports,也是最长 key 优先
这意味着:
{
"imports": {
"lodash": "https://esm.sh/lodash-es@4.17.21",
"lodash/": "https://esm.sh/lodash-es@4.17.21/"
}
}
import _ from "lodash" 加载完整文件;import get from "lodash/get" 自动拼接成 https://esm.sh/lodash-es@4.17.21/get,一行不用改。
同一个包,两个版本,不同路径各用各的
scopes 字段解决了包版本的世纪难题:
{
"imports": {
"lodash": "https://esm.sh/lodash-es@4.17.21"
},
"scopes": {
"/legacy/": {
"lodash": "https://esm.sh/lodash@3.10.1"
}
}
}
从 /legacy/ 路径加载的模块用 lodash 3,其他地方全部用 lodash 4。浏览器自己会分流,不用任何构建配置,不需要两个 node_modules。
浏览器自己会查完这张图再加载
Import Map 加载后,在第一个模块被解析之前就固定了。解析之后这张图就是只读的,改了也没用——这是 spec 的设计,不是 bug,设计意图是防止运行时意外修改导致不确定行为。
@esm.sh/import-map 这个包(2026 年 2 月发布,npmx 收录)把 import map 做成了可编程的 API,支持从 JSON/HTML 解析、自动从 esm.sh 抓依赖生成 scope、自动补 SRI 完整性校验:
import { ImportMap } from "@esm.sh/import-map";
const im = new ImportMap();
await im.addImport("react-dom@19/client");
const raw = im.raw;
// 自动生成完整 scope 和 integrity 字段
jspm.io/generator 可以直接贴 package.json 的依赖列表,生成完整 import map 给你复制进 HTML,不用手写。
适合的场景 vs 不适合的场景
适合:
- 内部工具、仪表盘,不想配置一整套构建链
- 纯前端的 POC,原型阶段快速验证
- 小工具类页面,依赖不多,不需要 tree-shaking
不适合:
Import Maps 本身不做打包、不压缩、不 tree-shaking。生产级应用如果在乎 bundle 体积,Vite/Webpack 的构建优化它替代不了。
什么时候该用?
三个问题帮你判断:
- 依赖是 pure ESM 包(大多数新包都是)吗? → 可以用
- 你的页面需要支持的最低浏览器是什么? → 现代浏览器(Chrome 89+/Safari 15.4+/Firefox 108+)直接原生支持
- 你需要 tree-shaking 吗? → 需要就走构建工具,不需要就走 Import Maps
大多数内部工具和 Dashboard 三个问题答案都是「No」,这时候 Import Maps 是最干净的选择。
评论区
登录后可评论。