不用 bundler 也能管 npm 包依赖了——Import Maps 把 ESM 这件事还给了浏览器
写了八年 import,今天发现浏览器自己就能把「去哪找这个包」这件事管了——不用任何构建工具,不用装 node_modules,一个 HTML 文件直接跑。
Import Maps 干的就是这个:让你在 HTML 里声明一套映射表,告诉浏览器「这个包名对应哪个 URL」。浏览器在遇到 import react from ‘react’ 这种裸标识符的时候,直接查表,不走任何打包流程。
核心链路:声明式依赖映射
script type=”importmap”>
{
“imports”: {
“react”: “https://esm.sh/react@18.2.0/“,
“react-dom”: “https://esm.sh/react-dom@18.2.0/“,
“lodash”: “https://esm.sh/lodash@4.17.21/“
}
}
/script>
script type=”module”>
import React from ‘react’;
import ReactDOM from ‘react-dom’;
import from ‘lodash’;
console.log(React, ReactDOM, .VERSION);
/script>
就这些。没有 webpack,没有 Vite,没有 esbuild。浏览器原生解析 ESM,直接从 CDN 拿模块。
为什么这事以前做不到
ESM 的规范里,裸标识符(不带路径的包名)本身就没有定义解析规则——这是故意的,设计者把这件事留给了运行时环境。Node.js 用自己的 node_modules 有一套规则,浏览器里没有。
Import Maps 补的就是这个空白。规范里,裸标识符通过 imports 字段映射到具体 URL,浏览器遇到 import ‘react’ 这样的语句,查到 https://esm.sh/react@18.2.0/,直接去加载。
scopes:分域控制
一个 Map 不够用?scopes 让你按路径分域控制:
script type=”importmap”>
{
“imports”: {
“utils”: “./utils.js”
},
“scopes”: {
“/admin/”: {
“utils”: “https://cdn.example.com/admin-utils.js“
},
“/user/”: {
“utils”: “https://cdn.example.com/user-utils.js“
}
}
}
/script>
/admin/ 路径下的 import ‘utils’ 会用 admin-utils.js,/user/ 下会用 user-utils.js。不同子应用、不同模块域,可以用不同的实现。
完整性校验:integrity
CDN 模块最怕被篡改。Import Maps 支持 integrity 元数据:
script type=”importmap”>
{
“imports”: {
“react”: “https://esm.sh/react@18.2.0/“
},
“integrity”: {
“https://esm.sh/react@18.2.0/“: “sha384-oqVuAfXRKap…”
}
}
/script>
加载时浏览器会自动校验,不匹配就报错。生产环境建议都配上。
哪些场景真正用得上
内部工具和小页面最合适。写一个数据可视化页面,不用搭环境、配构建、写 webpack.config.js,直接一个 HTML 文件加 Import Maps,三分钟能跑起来。
原型验证也一样。想试一个库的效果,不用 npm install,直接 importmap 声明,浏览器里看结果。
服务端直出 HTML 的场景可以用。比如 PHP/JAVA 后端渲染的页面,要加一点前端交互,直接用 Import Maps 引入 ESM 模块,比传统 script 标签更规范。
生产级大型应用还是建议用 bundler。Import Maps 不做代码分割、不做 tree shaking、不压缩、不分析依赖——它只是把模块解析还给浏览器,不是完整的构建流程。
浏览器支持情况
主流浏览器都已经支持:Chrome 89+、Firefox 108+、Safari 16.4+。移动端也没问题。可以直接用,不用担心兼容性。
如果要做降级,可以检测 HTMLScriptElement.supports:
if (HTMLScriptElement.supports && HTMLScriptElement.supports(‘importmap’)) {
// 使用 Import Maps
} else {
// 降级:用 require.js 或 system.js
}
下一步
下次写内部工具或者 demo 页面,试试不用任何 bundler,直接 Import Maps 跑起来。感受一下浏览器原生处理 ESM 是什么体验。如果项目需要代码分割或者多文件合并,还是回到 Vite,但 Import Maps 补的是「不需要构建」那个空白。
这个 API 的核心价值在于把「去哪找模块」这件事从 bundler 手里还给了浏览器——以前这种事必须靠构建工具,现在 HTML 自己就能声明了。
评论区
登录后可评论。