或者,如何控制 JavaScript 导入的行为
<script>
<base>
元素import.meta.resolve()
该提案允许控制 JavaScript import
语句和import()
表达式获取哪些 URL。这允许“裸导入说明符”(例如import moment from "moment"
起作用。
执行此操作的机制是通过导入映射,该映射通常可用于控制模块说明符的解析。作为介绍性示例,请考虑以下代码
import moment from "moment" ;
import { partition } from "lodash" ;
今天,这会抛出异常,因为此类裸说明符已被明确保留。通过向浏览器提供以下导入映射
< script type =" importmap " >
{
"imports" : {
"moment" : "/node_modules/moment/src/moment.js" ,
"lodash" : "/node_modules/lodash-es/lodash.js"
}
}
</ script >
上面的行为就好像你写了一样
import moment from "/node_modules/moment/src/moment.js" ;
import { partition } from "/node_modules/lodash-es/lodash.js" ;
有关<script>
的type=""
属性的新"importmap"
值的更多信息,请参阅安装部分。现在,我们将专注于映射的语义,推迟安装讨论。
具有 ES2015 之前的模块系统经验的 Web 开发人员,例如 CommonJS(在 Node 中或使用 webpack/browserify 为浏览器捆绑),习惯于能够使用简单的语法导入模块:
const $ = require ( "jquery" ) ;
const { pluck } = require ( "lodash" ) ;
翻译成 JavaScript 内置模块系统的语言,这些将是
import $ from "jquery" ;
import { pluck } from "lodash" ;
在这样的系统中,这些"jquery"
或"lodash"
的裸导入说明符被映射到完整的文件名或 URL。更详细地说,这些说明符代表packages ,通常分布在npm上;通过仅指定包的名称,它们隐式地请求该包的主模块。
该系统的主要好处是它可以轻松地在整个生态系统中进行协调。任何人都可以编写模块并使用包的众所周知的名称包含导入语句,并让 Node.js 运行时或其构建时工具负责将其转换为磁盘上的实际文件(包括确定版本控制注意事项)。
如今,许多 Web 开发人员甚至使用 JavaScript 的本机模块语法,但将其与裸露的导入说明符相结合,从而使他们的代码无法在每个应用程序的提前修改的情况下在 Web 上运行。我们希望解决这个问题,并将这些好处带给网络。
我们通过一系列示例来解释导入映射的功能。
正如简介中提到的,
{
"imports" : {
"moment" : " /node_modules/moment/src/moment.js " ,
"lodash" : " /node_modules/lodash-es/lodash.js "
}
}
在 JavaScript 代码中提供裸导入说明符支持:
import moment from "moment" ;
import ( "lodash" ) . then ( _ => ... ) ;
请注意,映射的右侧(称为“地址”)必须以/
、 ../
或./
开头,或者可解析为绝对 URL,以标识 URL。对于类似相对 URL 的地址,它们是相对于导入映射的基本 URL 进行解析的,即内联导入映射的页面的基本 URL 以及外部导入映射的导入映射资源的 URL。
特别是,像node_modules/moment/src/moment.js
这样的“裸”相对 URL 目前在这些位置不起作用。这是作为保守的默认值完成的,因为将来我们可能希望允许多个导入映射,这可能会以特别影响这些裸露情况的方式改变右侧的含义。
在 JavaScript 生态系统中,一个包(在 npm 的意义上)包含多个模块或其他文件是很常见的。对于这种情况,我们希望将模块说明符空间中的前缀映射到可获取 URL 空间中的另一个前缀。
导入映射通过为以斜杠结尾的说明符键赋予特殊含义来实现此目的。因此,像这样的地图
{
"imports" : {
"moment" : " /node_modules/moment/src/moment.js " ,
"moment/" : " /node_modules/moment/src/ " ,
"lodash" : " /node_modules/lodash-es/lodash.js " ,
"lodash/" : " /node_modules/lodash-es/ "
}
}
不仅允许导入主要模块,例如
import moment from "moment" ;
import _ from "lodash" ;
还有非主模块,例如
import localeData from "moment/locale/zh-cn.js" ;
import fp from "lodash/fp.js" ;
在 Node.js 生态系统中导入不包含扩展名的文件也很常见。在找到合适的匹配之前,我们没有机会尝试多个文件扩展名。然而,我们可以通过使用导入映射来模拟类似的东西。例如,
{
"imports" : {
"lodash" : " /node_modules/lodash-es/lodash.js " ,
"lodash/" : " /node_modules/lodash-es/ " ,
"lodash/fp" : " /node_modules/lodash-es/fp.js " ,
}
}
不仅允许import fp from "lodash/fp.js"
,还允许import fp from "lodash/fp"
。
尽管此示例展示了如何允许使用导入映射进行无扩展导入,但这并不一定是可取的。这样做会使导入映射变得臃肿,并使包的界面变得不那么简单——无论是对于人类还是对于工具来说。
如果您需要允许在包内进行无扩展导入,这种膨胀尤其成问题。在这种情况下,您将需要包中每个文件的导入映射条目,而不仅仅是顶级入口点。例如,要允许从/node_modules/lodash-es/lodash.js
文件中import "./fp"
,您需要一个导入条目将/node_modules/lodash-es/fp
映射到/node_modules/lodash-es/fp.js
。现在想象一下对每个不带扩展名引用的文件重复此操作。
因此,我们建议在导入映射或编写模块中使用此类模式时要小心。如果我们不依赖导入映射来修补与文件扩展名相关的不匹配,那么生态系统将会变得更简单。
作为允许一般重新映射说明符的一部分,导入映射特别允许重新映射类似 URL 的说明符,例如"https://example.com/foo.mjs"
或"./bar.mjs"
。其实际用途是映射哈希值,但在这里我们演示了一些基本的哈希值来传达该概念:
{
"imports" : {
"https://www.unpkg.com/vue/dist/vue.runtime.esm.js" : " /node_modules/vue/dist/vue.runtime.esm.js "
}
}
这一重新映射可确保任何 unpkg.com 版本的 Vue 导入(至少在该 URL 处)都从本地服务器获取。
{
"imports" : {
"/app/helpers.mjs" : " /app/helpers/index.mjs "
}
}
此重新映射确保解析为/app/helpers.mjs
任何类似 URL 的导入,包括例如从/app/
内的文件import "./helpers.mjs"
,或从文件import "../helpers.mjs"
在/app/models
内,将解析为/app/helpers/index.mjs
。这可能不是一个好主意;您应该更新源文件以导入正确的文件,而不是创建混淆代码的间接寻址。但是,它是演示导入地图功能的有用示例。
这种重新映射也可以在前缀匹配的基础上完成,通过以尾部斜杠结束说明符键:
{
"imports" : {
"https://www.unpkg.com/vue/" : " /node_modules/vue/ "
}
}
此版本确保以子字符串"https://www.unpkg.com/vue/"
开头的说明符的导入语句将映射到/node_modules/vue/
下的相应 URL。
一般来说,重点是重新映射对于类似 URL 的导入和裸导入的作用是一样的。我们之前的例子改变了像"lodash"
这样的说明符的解析,从而改变了import "lodash"
的含义。在这里,我们更改了诸如"/app/helpers.mjs"
之类的说明符的分辨率,从而更改了import "/app/helpers.mjs"
的含义。
请注意,这种类似 URL 说明符映射的尾部斜杠变体仅在类似 URL 说明符具有特殊方案时才有效:例如, "data:text/": "/foo"
的映射不会影响import "data:text/javascript,console.log('test')"
的含义import "data:text/javascript,console.log('test')"
,但只会影响import "data:text/"
。
脚本文件的文件名中通常会被赋予唯一的哈希值,以提高可缓存性。请参阅该技术的一般讨论,或者更多以 JavaScript 和 webpack 为重点的讨论。
对于模块图,这种技术可能会出现问题:
考虑一个简单的模块图,其中app.mjs
依赖于dep.mjs
,后者又依赖于sub-dep.mjs
。通常,如果您升级或更改sub-dep.mjs
, app.mjs
和dep.mjs
可以保留缓存,只需要通过网络传输新的sub-dep.mjs
。
现在考虑相同的模块图,使用散列文件名进行生产。在那里,我们的构建过程从原始的三个文件生成app-8e0d62a03.mjs
、 dep-16f9d819a.mjs
和sub-dep-7be2aa47f.mjs
。
如果我们升级或更改sub-dep.mjs
,我们的构建过程将为生产版本重新生成一个新文件名,例如sub-dep-5f47101dc.mjs
。但这意味着我们需要更改dep.mjs
生产版本中的import
语句。这会改变它的内容,这意味着dep.mjs
的生产版本本身需要一个新的文件名。但这意味着我们需要更新app.mjs
生产版本中的import
语句...
也就是说,对于包含散列文件名脚本文件的模块图和import
语句,对图的任何部分的更新都会对其所有依赖项进行病毒式传播,从而失去所有可缓存性优势。
导入映射提供了一种摆脱这种困境的方法,它将import
语句中出现的模块说明符与服务器上的 URL 解耦。例如,我们的网站可以从导入地图开始,例如
{
"imports" : {
"/js/app.mjs" : " /js/app-8e0d62a03.mjs " ,
"/js/dep.mjs" : " /js/dep-16f9d819a.mjs " ,
"/js/sub-dep.mjs" : " /js/sub-dep-7be2aa47f.mjs "
}
}
并使用import "./sub-dep.mjs"
形式的导入语句,而不是import "./sub-dep-7be2aa47f.mjs"
。现在,如果我们更改sub-dep.mjs
,我们只需更新导入映射:
{
"imports" : {
"/js/app.mjs" : " /js/app-8e0d62a03.mjs " ,
"/js/dep.mjs" : " /js/dep-16f9d819a.mjs " ,
"/js/sub-dep.mjs" : " /js/sub-dep-5f47101dc.mjs "
}
}
并保留import "./sub-dep.mjs"
语句。这意味着dep.mjs
的内容不会更改,因此它会保持缓存状态; app.mjs
也是如此。
<script>
关于使用导入映射更改导入说明符含义的一个重要注意事项是,它不会更改原始 URL 的含义,例如<script src="">
或<link rel="modulepreload">
中出现的 URL。也就是说,考虑到上面的例子,同时
import "./app.mjs" ;
将在支持导入映射的浏览器中正确地重新映射到其哈希版本,
< script type =" module " src =" ./app.mjs " > </ script >
不会:在所有类别的浏览器中,它都会尝试直接获取app.mjs
,从而导致 404。在支持 import-map 的浏览器中,有效的方法是
< script type =" module " > import "./app.mjs" ; </ script >
通常情况下,您希望使用相同的导入说明符来引用单个库的多个版本,具体取决于导入它们的人。这封装了正在使用的每个依赖项的版本,并避免了依赖地狱(较长的博客文章)。
我们通过允许您在给定范围内更改说明符的含义来支持导入映射中的此用例:
{
"imports" : {
"querystringify" : " /node_modules/querystringify/index.js "
},
"scopes" : {
"/node_modules/socksjs-client/" : {
"querystringify" : " /node_modules/socksjs-client/querystringify/index.js "
}
}
}
(此示例是@zkat 提供的每个应用程序多个版本的几个野外示例之一。谢谢@zkat!)
通过此映射,在 URL 以/node_modules/socksjs-client/
开头的任何模块内, "querystringify"
说明符将引用/node_modules/socksjs-client/querystringify/index.js
。否则,顶级映射将确保"querystringify"
引用/node_modules/querystringify/index.js
。
请注意,位于范围内不会改变地址的解析方式;仍然使用导入映射的基本 URL,而不是范围 URL 前缀。
作用域以一种故意简单的方式相互“继承”,在它们运行时合并但压倒一切。例如,以下导入映射:
{
"imports" : {
"a" : " /a-1.mjs " ,
"b" : " /b-1.mjs " ,
"c" : " /c-1.mjs "
},
"scopes" : {
"/scope2/" : {
"a" : " /a-2.mjs "
},
"/scope2/scope3/" : {
"b" : " /b-3.mjs "
}
}
}
将作出以下决议:
说明符 | 推荐人 | 结果网址 |
---|---|---|
一个 | /scope1/foo.mjs | /a-1.mjs |
乙 | /scope1/foo.mjs | /b-1.mjs |
c | /scope1/foo.mjs | /c-1.mjs |
一个 | /scope2/foo.mjs | /a-2.mjs |
乙 | /scope2/foo.mjs | /b-1.mjs |
c | /scope2/foo.mjs | /c-1.mjs |
一个 | /scope2/scope3/foo.mjs | /a-2.mjs |
乙 | /scope2/scope3/foo.mjs | /b-3.mjs |
c | /scope2/scope3/foo.mjs | /c-1.mjs |
您可以使用<script>
元素(内联或带有src=""
属性)为您的应用程序安装导入映射:
< script type =" importmap " >
{
"imports" : { ... } ,
"scopes" : { ... }
}
</ script >
< script type =" importmap " src =" import-map.importmap " > </ script >
使用src=""
属性时,生成的 HTTP 响应必须具有 MIME 类型application/importmap+json
。 (为什么不重用application/json
?这样做可能会绕过 CSP。)与模块脚本一样,请求是在启用 CORS 的情况下发出的,并且响应始终被解释为 UTF-8。
由于它们会影响所有导入,因此在完成任何模块解析之前,所有导入映射都必须存在并成功获取。这意味着在导入映射获取时模块图获取被阻止。
这意味着强烈建议使用内联形式的导入映射以获得最佳性能。这类似于内联关键 CSS 的最佳实践;这两种类型的资源都会阻止您的应用程序执行重要工作,直到它们被处理为止,因此引入第二个网络往返(甚至磁盘缓存往返)是一个坏主意。如果您决定使用外部导入映射,您可以尝试使用 HTTP/2 Push 或捆绑 HTTP 交换等技术来减轻这种往返损失。
作为导入映射如何影响所有导入的另一个结果,在任何模块图获取开始后尝试添加新的<script type="importmap">
是一个错误。导入映射将被忽略,并且<script>
元素将触发error
事件。
目前,页面上仅允许有一个<script type="importmap">
。一旦我们弄清楚组合多个导入映射的正确语义,我们计划在未来扩展它。请参阅 #14、#137 和 #167 中的讨论。
我们在工人中做什么?可能是new Worker(someURL, { type: "module", importMap: ... })
?或者你应该从工人内部设置它?专职工作人员是否应该默认使用还是始终使用其控制文档的地图?在#2 中讨论。
上述规则意味着您可以动态生成导入映射,只要在执行任何导入之前执行此操作即可。例如:
< script >
const im = document . createElement ( 'script' ) ;
im . type = 'importmap' ;
im . textContent = JSON . stringify ( {
imports : {
'my-library' : Math . random ( ) > 0.5 ? '/my-awesome-library.mjs' : '/my-rad-library.mjs'
}
} ) ;
document . currentScript . after ( im ) ;
</ script >
< script type =" module " >
import 'my-library' ; // will fetch the randomly-chosen URL
</ script >
更实际的示例可能会使用此功能来根据特征检测来组装导入映射:
< script >
const importMap = {
imports : {
moment : '/moment.mjs' ,
lodash : someFeatureDetection ( ) ?
'/lodash.mjs' :
'/lodash-legacy-browsers.mjs'
}
} ;
const im = document . createElement ( 'script' ) ;
im . type = 'importmap' ;
im . textContent = JSON . stringify ( importMap ) ;
document . currentScript . after ( im ) ;
</ script >
< script type =" module " >
import _ from "lodash" ; // will fetch the right URL for this browser
</ script >
请注意,(与其他<script>
元素一样)在将<script type="importmap">
插入到文档中后修改它的内容将不起作用。这就是为什么我们在创建和插入<script type="importmap">
之前通过组装导入映射的内容来编写上面的示例。
导入映射是应用程序级别的东西,有点像服务工作者。 (更正式地说,它们将是每个模块的映射,因此也是每个领域的映射。)它们并不是要组合的,而是由具有 Web 应用程序整体视图的人员或工具生成。例如,库包含导入映射是没有意义的;库可以简单地通过说明符引用模块,并让应用程序决定这些说明符映射到哪些 URL。
除了一般的简单性之外,这也是对<script type="importmap">
进行上述限制的部分原因。
由于应用程序的导入映射会更改模块映射中每个模块的解析算法,因此它们不会受到模块的源文本最初是否来自跨源 URL 的影响。如果您从使用裸导入说明符的 CDN 加载模块,则需要提前了解该模块向您的应用程序添加了哪些裸导入说明符,并将它们包含在应用程序的导入映射中。 (也就是说,您需要知道应用程序的所有传递依赖项是什么。)应用程序作者对每个包使用哪些 URL 的控制非常重要,这样他们就可以全面管理模块的版本控制和共享。
大多数浏览器都有一个推测性 HTML 解析器,它会在 HTML 解析器等待获取和执行阻塞脚本时尝试发现 HTML 标记中声明的资源。尽管在 Whatwg/html#5959 中正在努力这样做,但尚未指定这一点。本节讨论一些需要注意的潜在相互作用。
首先,请注意,尽管据我们所知,目前没有浏览器这样做,但在以下示例中,推测解析器有可能在等待阻塞脚本https://example.com/blocking-1.js
时获取https://example.com/foo.mjs
https://example.com/blocking-1.js
:
<!DOCTYPE html >
<!-- This file is https://example.com/ -->
< script src =" blocking-1.js " > </ script >
< script type =" module " >
import "./foo.mjs" ;
</ script >
同样,在以下示例中,浏览器可以通过将导入映射解析为推测解析过程的一部分来推测获取https://example.com/foo.mjs
和https://example.com/bar.mjs
:
<!DOCTYPE html >
<!-- This file is https://example.com/ -->
< script src =" blocking-2.js " > </ script >
< script type =" importmap " >
{
"imports" : {
"foo" : "./foo.mjs" ,
"https://other.example/bar.mjs" : "./bar.mjs"
}
}
</ script >
< script type =" module " >
import "foo" ;
import "https://other.example/bar.mjs" ;
</ script >
这里需要注意的一个交互是,推测性地解析内联 JS 模块但不支持导入映射的浏览器可能会错误地推测此示例:它们可能推测性地获取https://other.example/bar.mjs
,而不是它映射到https://example.com/bar.mjs
。
更一般地说,基于进口地图的推测可能会遭受与其他推测相同的错误。例如,如果blocking-1.js
的内容是
const el = document . createElement ( "base" ) ;
el . href = "/subdirectory/" ;
document . currentScript . after ( el ) ;
那么在无导入映射示例中对https://example.com/foo.mjs
的推测性获取将被浪费,因为到执行模块的实际评估时,我们将重新计算相对说明符"./foo.mjs"
并意识到实际请求的是https://example.com/subdirectory/foo.mjs
。
类似地,对于导入映射情况,如果blocking-2.js
的内容是
document . write ( `<script type="importmap">
{
"imports": {
"foo": "./other-foo.mjs",
"https://other.example/bar.mjs": "./other-bar.mjs"
}
}
</script>` ) ;
那么https://example.com/foo.mjs
和https://example.com/bar.mjs
的推测性获取将被浪费,因为新编写的导入映射将生效,而不是看到的那个内联在 HTML 中。
<base>
元素当文档中存在<base>
元素时,导入映射中的所有 URL 和类似 URL 的说明符都将使用<base>
中的href
转换为绝对 URL。
< base href =" https://www.unpkg.com/vue/dist/ " >
< script type =" importmap " >
{
"imports" : {
"vue" : "./vue.runtime.esm.js" ,
}
}
</ script >
< script >
import ( "vue" ) ; // resolves to https://www.unpkg.com/vue/dist/vue.runtime.esm.js
</ script >
如果浏览器支持 HTMLScriptElement 的supports(type) 方法, HTMLScriptElement.supports('importmap')
必须返回 true。
if ( HTMLScriptElement . supports && HTMLScriptElement . supports ( 'importmap' ) ) {
console . log ( 'Your browser supports import maps.' ) ;
}
与 Node.js 不同,在浏览器中,我们没有足够快的文件系统来爬行查找模块。因此,我们不能直接实现Node模块解析算法;它需要为每个import
语句执行多次服务器往返,当我们不断收到 404 错误时会浪费带宽和时间。我们需要确保每个import
语句只引起一个 HTTP 请求;这需要某种预先计算措施。
有些人建议使用 JavaScript 挂钩来自定义浏览器的模块解析算法来解释每个模块说明符。
不幸的是,这对性能来说是致命的;在模块图的每个边缘跳入和退出 JavaScript 会大大减慢应用程序的启动速度。 (典型的 Web 应用程序有数千个模块,其中有 3-4 倍的导入语句。)您可以想象各种缓解措施,例如将调用限制为仅裸导入说明符或要求钩子采用批量说明符和返回批量的 URL,但最终没有什么比预计算更好的了。
另一个问题是,即使 Web 开发人员获得了这个钩子,也很难想象他们可以编写有用的映射算法。 Node.js 有一个,但它基于重复抓取文件系统并检查文件是否存在;正如上面所讨论的,这在网络上是不可行的。通用算法可行的唯一情况是(a)您从不需要每个子图定制,即您的应用程序中每个模块只存在一个版本; (b) 工具设法以某种统一的、可预测的方式提前安排模块,以便算法变成“return /js/${specifier}.js
”。但无论如何,如果我们在这个世界上,声明式解决方案会更简单。
目前使用的一种解决方案(例如,通过 babel-plugin-unpkg 在 unpkg CDN 中)是使用构建工具提前将所有裸导入说明符重写为其适当的绝对 URL。这也可以在安装时完成,这样当您使用 npm 安装包时,它会自动重写包的内容以使用绝对或相对 URL,而不是裸露的导入说明符。
这种方法的问题是它不适用于动态import()
,因为不可能静态分析传递给该函数的字符串。您可以注入一个修复程序,例如将import(x)
的每个实例更改为import(specifierToURL(x, import.meta.url))
,其中specifierToURL
是构建工具生成的另一个函数。但最终,这是一个相当有漏洞的抽象,而且specifierToURL
函数很大程度上重复了该提案的工作。
乍一看,Service Worker 似乎是进行此类资源转换的合适场所。我们过去讨论过寻找某种方法将说明符与服务工作人员的获取事件一起传递,从而允许它返回适当的Response
。
但是, Service Worker 在首次加载时不可用。因此,它们不能真正成为用于加载模块的关键基础设施的一部分。它们只能用作提取之上的渐进增强,否则通常会起作用。
如果您有一个简单的应用程序,不需要作用域依赖解析,并且有一个包安装工具,可以轻松地重写包内磁盘上的路径(与当前版本的 npm 不同),那么您可以使用更简单的映射。例如,如果您的安装工具创建了以下形式的平面列表
node_modules_flattened/
lodash/
index.js
core.js
fp.js
moment/
index.js
html-to-dom/
index.js
那么您唯一需要的信息是
/node_modules_flattened/
)index.js
)您可以想象一个模块导入配置格式仅指定这些内容,甚至仅指定某些子集(如果我们对其他内容进行假设)。
这个想法不适用于需要范围解析的更复杂的应用程序,因此我们认为完整的导入地图提案是必要的。但它对于简单的应用程序仍然有吸引力,我们想知道是否有一种方法可以使提案也有一个简单模式,不需要列出所有模块,而是依赖约定和工具来确保需要最少的映射。在#7 中讨论。
人们多次提出希望为每个模块提供元数据;例如,完整性元数据或获取选项。尽管有些人建议使用 import 语句来执行此操作,但仔细考虑这些选项会导致更喜欢带外清单文件。
导入映射可以是该清单文件。然而,由于以下几个原因,它可能不是最合适的:
按照目前的设想,应用程序中的大多数模块在导入映射中不会有条目。主要用例是需要通过裸说明符引用的模块,或者需要执行一些棘手操作(例如填充或虚拟化)的模块。如果我们设想每个模块都在地图中,我们就不会包含像packages-via-trailing-slashes这样的便利功能。
到目前为止,所有建议的元数据都适用于任何类型的资源,而不仅仅是 JavaScript 模块。解决方案可能应该在更一般的层面上发挥作用。
多个<script type="importmap">
出现在页面上是很自然的,就像多个其他类型的<script>
一样。我们希望将来能够实现这一点。
这里最大的挑战是决定多个导入映射如何组成。也就是说,给定两个重新映射相同 URL 的导入映射,或者两个覆盖相同 URL 前缀空间的范围定义,对页面的影响应该是什么?当前领先的候选者是级联解析,它将导入映射从导入说明符 → URL 映射重新转换为一系列级联的导入说明符 → 导入说明符映射,最终在“可获取的导入说明符”(本质上是一个 URL)中触底。
请参阅这些未解决的问题以进行更多讨论。
某些用例需要一种从脚本读取或操作领域的导入映射的方法,而不是通过插入声明性<script type="importmap">
元素。将其视为一种“导入地图对象模型”,类似于允许操作页面的通常声明性 CSS 规则的 CSS 对象模型。
这里的挑战在于如何协调声明性导入映射与任何编程更改,以及在页面生命周期中何时可以运行此类 API。一般来说,设计越简单,功能就越弱,并且可能满足的用例也越少。
请参阅这些未解决的问题,以获取更多讨论和编程 API 可以提供帮助的用例。
import.meta.resolve()
建议的import.meta.resolve(specifier)
函数允许模块脚本随时将导入说明符解析为 URL。有关更多信息,请参阅whatwg/html#5572。这与导入映射相关,因为它允许您解析“包相关”资源,例如
const url = import . meta . resolve ( "somepackage/resource.json" ) ;
将为您提供由页面导入映射控制的somepackage/
命名空间内的resource.json
的适当映射位置。
社区的一些成员一直致力于与导入地图相关的填充和工具的开发。以下是我们所知道的:
package.json
和node_modules/
目录生成导入映射。package.json
生成导入映射。<script type="systemjs-importmap">
的导入映射。请随时发送包含更多内容的拉取请求!此外,您可以在问题跟踪器中使用#146 来讨论此空间。
该文档源自 @domenic、@hiroshige-g、@justinfagnani、@MylesBorins 和 @nyaxt 为期一天的冲刺。从那时起,@guybedford 在原型设计和推动对该提案的讨论方面发挥了重要作用。
还要感谢问题跟踪器上的所有贡献者在改进提案方面提供的帮助!