新出了一个系列:Vue2与Vue3 技巧小册

有梦想,有干货,微信搜索 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。
本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。

当ES模块第一次在ECMAScript 2015中被引入,作为在JavaScript中标准化模块系统的一种方式时,它是通过在import语句中指定相对或绝对路径来实现的。

import dayjs from "https://cdn.skypack.dev/dayjs@1.10.7"; // ES modulesconsole.log(dayjs("2019-01-25").format("YYYY-MM-DDTHH:mm:ssZ[Z]"));

这与模块在其他通用模块系统中的工作方式略有不同,例如CommonJS,以及在使用webpack这样的模块捆绑器时,使用的是更简单的语法。

const dayjs = require('dayjs') // CommonJSimport dayjs from 'dayjs'; // webpack

在这些系统中,通过Node.js运行时或相关的构建工具,导入指定器被映射到一个特定(和版本)的文件。用户只需要在导入语句中应用裸露的模块指定符(通常是包名),围绕模块解析的问题就会被自动解决。

由于开发者已经熟悉了这种从npm导入包的方式,所以需要一个构建步骤来确保以这种方式编写的代码能够在浏览器中运行。这个问题由import maps解决了。从本质上讲,它允许将导入指定器映射到相对或绝对的URL上,这有助于控制模块的解析,而不需要应用构建步骤。

import maps 是怎么工作的

<script type="importmap">
{"imports": {"dayjs": "https://cdn.skypack.dev/dayjs@1.10.7",}
}
</script>
<script type="module">import dayjs from 'dayjs';console.log(dayjs('2019-01-25').format('YYYY-MM-DDTHH:mm:ssZ[Z]'));
</script>

import map 是通过HTML document中的 <script type="importmap">标签指定的。这个script 标签必须放在 document 中的中第一个 <script type="module">标签之前(最好是在<head>中),以便在进行模块解析之前对它进行解析。此外,目前每个 document 只允许有一个 import map,未来可能会取消这一限制。

script 标签内,一个JSON对象被用来指定document中 script 所需的所有必要的模块映射。一个典型的 import map 的结构如下所示。

<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>

在上面的 imports 对象中,每个属性都对应着一个映射。映射的左边是 import 指定器的名称,而右边是指定器应该映射到的相对或绝对URL。

当在映射中指定相对URL时,确保它们总是以/././开头。请注意,在 import map 中出现包并不意味着它一定会被浏览器加载。任何没有被页面上的 script 使用的模块都不会被浏览器加载,即使它存在于import map中。

<script type="importmap" src="importmap.json"></script>

你也可以在一个外部文件中指定你的映射,然后使用src属性链接到该文件(如上所示)。如果决定使用这种方法,请确保在发送文件时将其Content-Type标头设置为application/importmap+json

注意,出于性能方面的考虑,推荐使用内联方式,本文的其余部分的事例,也会使用内联方式。

一旦指定了映射,就可以在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>

需要注意的是,导入映射中的映射不会影响诸如<script>标签的 src 属性之类的位置。因此,如你的使用<script src="/app.js">之类的内容,浏览器将试图在该路径上下载一个字面上的app.js文件,而不管 import map 中的内容如何。

将指定者映射到整个包中

除了将一个指定器映射到一个模块,你也可以将一个指定器映射到一个包含多个模块的包。这是通过使用指定器键和以尾部斜线结尾的路径来实现的。

<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>

动态地构建 import map

映射也可以基于任意条件在 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 map 脚本标签之前进行(如上所述),因为修改一个已经存在的导入地图对象不会有任何效果。

通过对哈希值的映射来提高脚本的可缓存性

实现静态文件长期缓存的常见技术是在文件名中使用文件内容的哈希值,这样文件就会一直在浏览器的缓存中,直到文件内容发生变化。当这种情况发生时,文件将得到一个新的名字,以便最新的更新立即反映在应用程序中。

在传统的 bundling scripts,的方式下,如果一个被多个模块依赖的依赖关系被更新,这种技术就会出现问题。这将导致所有依赖该依赖的文件被更新,迫使浏览器重新下载它们,即使只有一个字符的代码被改变。

import map 为这个问题提供了一个解决方案,它允许通过重映射技术单独更新每个依赖关系。假设你需要从一个名为post.bundle.8cb615d12a121f6693aa.js的文件中导入一个方法:

<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 需要更新。由于对其导出的引用没有更改,它们将保持在浏览器中的缓存,同时由于更新的哈希值,更新的脚本将再次被下载。

<script type="importmap">{"imports": {"post.js": "./static/dist/post.bundle.6e2bf7368547b6a85160.js",}}
</script>

使用同一模块的多个版本

在 import map 中很容易实现一个包对应多个版本,所需要做的就是在映射中使用不同的导入指定符,如下图所示:

    <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>

通过使用作用域,也可以用同一个导入指定符来指代同一个包的不同版本。这允许我们在一个给定的作用域内改变导入指定符的含义。

<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>

有了这种映射,在/static/js路径下的任何模块,在导入语句中引用lodash/指定器时,将使用https://unpkg.com/lodash-es@3.10.1/,而其他模块将使用https://unpkg.com/lodash-es@4.17.21/

使用带有 import map 的 NPM 包

正如在本文中所展示的,任何使用ES Modules的NPM包的生产版本都可以通过ESM、Unpkg和Skypack等CDN在 import map中使用。

即使NPM上的包不是为ES模块系统和本地浏览器导入行为设计的,像Skypack和ESM这样的服务也可以将它们转化为可在导入地图中使用的包。可以使用Skypack主页上的搜索栏来寻找浏览器优化的NPM包,这些包可以立即使用,而无需摆弄构建步骤。

检测 import map支持

只要支持HTMLScriptElement.supports()方法,就可以在浏览器中检测 import map的支持:

if (HTMLScriptElement.supports && HTMLScriptElement.supports('importmap')) {// import maps is supported
}

支持旧的浏览器

Import map 使得在浏览器中使用裸模块指定器成为可能,而无需依赖目前在JavaScript生态系统中普遍存在的复杂的构建系统,但目前网络浏览器中并不广泛支持它。

在整理本文时,Chrome和Edge浏览器的89版及以后的版本提供了全面支持,但Firefox、Safari和一些移动浏览器不支持这项技术。为了在这些浏览器中保留对 import map的使用,必须采用一个合适的 polyfill 。

一个可以使用的polyfill的例子是ES Module Shims polyfill,它为任何支持ES模块基线的浏览器(约94%的浏览器)添加了 import map 和其他新模块特性的支持。我们所需要做的就是在 import map 脚本之前在HTML文件中包含es-module-shim脚本

<script async src="https://unpkg.com/es-module-shims@1.3.0/dist/es-module-shims.js"></script>

在包括polyfill之后,可能会在你的控制台中得到一个JavaScript TypeError。这个错误可以被安全地忽略,因为它不会产生任何面向用户的后果。

总结

import map提供了一种更理智的方式来在浏览器中使用ES模块,而不局限于从相对或绝对的URL中导入。这使得我们可以很容易地移动代码,而不需要调整 import语句,并使个别模块的更新更加无缝,而不影响依赖这些模块的脚本的缓存能力。总的来说,import map为ES模块在服务器和浏览器中的使用方式带来了平等性。

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。


作者:romaopedro199 译者:前端小智 来源:dev 原文:https://www.honeybadger.io/blog/import-maps/

交流

有梦想,有干货,微信搜索 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。

type=“module“ 你了解,但 type=“importmap“ 你知道吗相关推荐

  1. script标签之type = module

    在script标签中写js代码,或者使用src引入js文件时,默认不能使用module形式,即不能使用import导入文件,但是我们可以再script标签上加上type=module属性来改变方式. ...

  2. vue3 setup + ts + vite 项目问题解决:Cannot find module ... or its corresponding type declarations.(ts2307)

    昨日我尝试使用vue3 setup + ts + vite进行vue3项目的实现,遇到此问题: Cannot find module ... or its corresponding type dec ...

  3. Cannot find module ... or its corresponding type declarations.(ts2307)

    vue3+ts项目出现这样的编译提示,红色下划线 Cannot find module ... or its corresponding type declarations.(ts2307) 解决方法 ...

  4. script之type=module

    文章目录 实例 目录 代码 专栏目录请点击 在远古时代,我们引入js文件一般使用<script src='路径'>来引入其他的js文件,但是随着js的规范化和模块化,在模块与模块之间的引入 ...

  5. 记录 | node运行报错To load an ES module, set “type“: “module“ in the package.json or use the .mjs extens

    报错:To load an ES module, set "type": "module" in the package.json or use the .mj ...

  6. RuntimeError: Expected object of device type cuda but got device type cpu for argument pytorch数据位置

    RuntimeError: Expected object of device type cuda but got device type cpu for argument #2 'target' i ...

  7. Pytorch 类型错误:Expected object of type torch.FloatTensor but found type torch.cuda.FloatTensor.

    Expected object of type torch.FloatTensor but found type torch.cuda.FloatTensor Pytorcht调试过程中,将数据传入模 ...

  8. SAP WM Movement Type 里的‘Ref.Stor.Type Search’字段用法初探

    SAP WM Movement Type 里的'Ref.Stor.Type Search'字段用法初探 笔者在目前的项目里负责MM以及WM两个模块的实施.根据客户仓库存储区域的现状,我在WM层面的st ...

  9. The conversion of a varchar data type to a datetime data type resulted in an out-of-range value

    刚刚有在程序中,传递一个空值至MS SQL Server数据库,这个值的数据类型为DATETIME 执行时,它却发生了如标题提示的异常: The conversion of a varchar dat ...

最新文章

  1. BZOJ 2137 submultiple(约数,拉格朗日插值求自然数k次幂和)【BZOJ 修复工程】
  2. 人生致命的8个经典问题[转]
  3. c51为啥要宏定义时钟_51单片机时钟实训报告
  4. 好看高端的立体表白相册程序
  5. linux系统在物流公司的z作用,【项目案例】基于RFID的智能物流仓储系统
  6. C#中的多线程 - 基础知识 z
  7. pop3协议手机开通服务器,手机服务器pop3设置方法
  8. 《创新者的窘境》读书笔记
  9. 联想启天M415台式机安装esxi找不到网卡的解决方法
  10. 数字化发展正在影响服装企业
  11. AD中对PCB的滴泪和敷铜操作
  12. 关于渲染帧率(FPS)的问题
  13. swust2020春季《形势与政策》mooc考试答案参考
  14. Libxml2函数及使用方法概述
  15. Cocos2D教程:使用SpriteBuilder和Cocos2D 3.x开发横版动作游戏——Part 1
  16. 驻留内存 虚拟内存 共享内存
  17. 10步成为一个优秀的Java开发!
  18. 在学校游说开源和Linux
  19. 一些资源以及读书总结
  20. css-summarize

热门文章

  1. python抓取直播源 并更新_M3U8直播源有效性验证Python版
  2. python做值班表预测_Django model一张表中两个字段设置外键参考另一张表两个字段...
  3. Python爬取QQ音乐内地专辑
  4. 关于硬盘扇区的基本知识
  5. woo 图像合成,比python简单多了,一个文件到处运行,不用编译
  6. 存量 IoT 设备零改造,一键迁移企业物联网实例
  7. 微信小程序:修改按钮BUTTON尺寸
  8. 180°和360°伺服电机速度控制,转向控制Arduino代码与库(亲测可用)
  9. python的Bug
  10. LVS原理详解(4种工作模式)