importmap是一种针对web页面去控制imports行为的新方式,潜在地可以使你摈弃掉你的构建系统。
当Es modules在Ecmascript 2015中第一次被引进并作为标准化js模块系统的一种方式,它是通过在import语句中强制指定相对或绝对路径来实现的。
ES6 案例参考:
import dayjs from "https://cdn.skypack.dev/dayjs@1.10.7"; // ES modules
console.log(dayjs("2024-01-25").format("YYYY-MM-DDTHH:mm:ssZ[Z]"));
执行结果:
这与其他的通用模块系统(像是CommonJs)的工作模式有细微的差别,并且在使用类似webpack的模块bunlder时使用了更简单的语法:
const dayjs = require('dayjs') // CommonJS
import dayjs from 'dayjs'; // webpack
在这些系统中,import说明符通过Node.js运行时或相关的构建工具映射到特定(和版本化)文件。用户只需在import语句中应用最简单的说明符(通常是包名),就可以自动解决模块解析问题。
由于开发人员已经熟悉从npm导入包的这种方式,因此需要一个构建步骤来确保以这种方式编写的代码可以在浏览器中运行。import-maps解决了这个问题。本质上,它允许将import说明符映射到相对或绝对URL,这有助于在不应用构建步骤的情况下控制模块。
说人话就:是 importmap 给你创建了一个快捷键地址,或者用Linux的软连接功能相似。
<div style="margin-bottom:10px;">
<label>时间解析结果:</label><span id="time"></span>
</div>
<script type="importmap">
{
"imports": {
"dayjs": "https://cdn.skypack.dev/dayjs@1.10.7"
}
}
</script>
<script type="module">
import dayjs from "https://cdn.skypack.dev/dayjs@1.10.7"; // ES modules
let result = dayjs("2024-01-25").format("YYYY-MM-DDTHH:mm:ssZ[Z]");
let $time = document.querySelector('#time');
$time.innerHTML = result;
</script>
importmap是通过HTML文档中的
在script标记中,JSON对象用于为文档中脚本所需的模块指定所有必要的映射。典型importmap的结构如下所示:
<script type="importmap">
{
"imports": {
"react": "https://cdn.skypack.dev/react@17.0.1",
"react-dom": "https://cdn.skypack.dev/react-dom",
"square": "./modules/square.js",
"lodash": "/node_modules/lodash-es/lodash.js"
}
}
</script>
<script type="importmap" src="importmap.json"></script>
指定mapping后,可以在import语句中使用import说明符,如下所示:
<script type="module">
import { cloneDeep } from 'lodash';
const objects = [{ a: 1 }, { b: 2 }];
const deep = cloneDeep(objects);
console.log(deep[0] === objects[0]);
</script>
应该注意,import map中的映射不会影响URL,例如<script>标记的src属性。因此,如果您使用类似
将说明符映射到整个包
除了将说明符映射到模块之外,还可以将一个说明符映射到包含多个模块的包。这是通过使用以斜杠结尾的说明符键和路径来完成的。
<script type="importmap">
{
"imports": {
"lodash/": "/node_modules/lodash-es/"
}
}
</script>
此操作允许您导入指定路径中的任何模块,而不是整个主模块,这将导致浏览器下载所有组件模块。
<script type="module">
import toUpper from 'lodash/toUpper.js';
import toLower from 'lodash/toLower.js';
console.log(toUpper('hello'));
console.log(toLower('HELLO'));
</script>
映射也可以基于任意条件在脚本中动态构建,并且该功能可以用于基于特征检测有条件地导入模块。下面的示例根据IntersectionObserver API是否受支持,选择要在lazyload说明符下导入的正确文件。
<script>
const importMap = {
imports: {
lazyload: 'IntersectionObserver' in window
? './lazyload.js'
: './lazyload-fallback.js',
},
};
const im = document.createElement('script');
im.type = 'importmap';
im.textContent = JSON.stringify(importMap);
document.currentScript.after(im);
</script>
如果要使用此方法,请确保在创建和插入import maps脚本标记之前执行此操作(如上所述),因为修改现有的导入映射对象不会产生任何效果。
通过Hash映射来提高脚本的缓存
实现静态文件长期缓存的一种常见技术是在文件的名称中使用文件内容的哈希值,以便在文件内容发生更改之前,文件仍保留在浏览器缓存中。发生这种情况时,文件将获得一个新名称,以便最近更新立即反映在应用程序中。
对于bundler脚本的传统方式,如果更新几个模块所依赖的依赖项,则此技术可能会失败。这将导致依赖于该依赖项的所有文件被更新,这将迫使浏览器重新下载它们,即使只更改了一个字符的代码。
Import Maps允许通过重新映射技术分别更新每个依赖项,从而解决了这个问题。假设您需要从名为post.bundle8cb615d12a121f6693aa.js的文件中导入一个方法,您可以有一个如下所示的importmap:
<script type="importmap">
{
"imports": {
"post.js": "./static/dist/post.bundle.8cb615d12a121f6693aa.js",
}
}
</script>
相较于如下的书写方式:
import { something } from './static/dist/post.bundle.8cb615d12a121f6693aa.js'
你可以像下面这样写:
import { something } from 'post.js'
当更新文件时,只需要更新import map。由于对其导出的引用没有更改,因此由于hash变化而更新的脚本再次下载时,它们将保持缓存在浏览器中。
<script type="importmap">
{
"imports": {
"post.js": "./static/dist/post.bundle.6e2bf7368547b6a85160.js",
}
}
</script>
使用同一个模块的不同版本
在importmap
中使用同一个模块的不同版本是很容易的一件事,你只需要在mapping中申明不同的说明符即可,像这样:
<script type="importmap">
{
"imports": {
"lodash@3/": "https://unpkg.com/lodash-es@3.10.1/",
"lodash@4/": "https://unpkg.com/lodash-es@4.17.21/"
}
}
</script>
你同样可以通过不同作用域来设定同一个说明符作为同一个包的不同版本,这允许您在给定范围内更改import说明符的含义。
<script type="importmap">
{
"imports": {
"lodash/": "https://unpkg.com/lodash-es@4.17.21/"
},
"scopes": {
"/static/js": {
"lodash/": "https://unpkg.com/lodash-es@3.10.1/"
}
}
}
</script>
通过这个mapping,任何在/static/js路径下面使用了lodash/说明符的引用都会关联到3.10.1的版本,其他的则关联到4.17.21的版本。
NPM包与Import Maps一起使用
正如我在本文中所演示的,使用ES模块的任何NPM包的生产版本都可以通过ESM、Unpkg和Skypack等CDN在Import Maps中使用。即使NPM上的软件包不是为ES模块系统和本地浏览器导入行为而设计的,Skypack和ESM等服务也可以将其转换为可在import map中使用的软件包。您可以使用Skypack主页上的搜索栏来查找浏览器优化的NPM包,这些包可以立即使用,而无需修改构建步骤。
代码检测Import Maps支持
只要判断HTMLScriptElement.supports()方法,就可以在浏览器中检测Import Mpas支持。以下代码段可用于此目的:
if (HTMLScriptElement.supports && HTMLScriptElement.supports('importmap')) {
// import maps is supported
}
http://blog.xqlee.com/article/2408051059449542.html