spi*_*ers 21 browser-cache web es6-modules
ES6模块允许我们创建一个单一的入口点,如下所示:
// main.js
import foo from 'foo';
foo()
Run Code Online (Sandbox Code Playgroud)
<script src="scripts/main.js" type="module"></script>
Run Code Online (Sandbox Code Playgroud)
foo.js将存储在浏览器缓存中.在我将新版本的foo.js推向生产之前,这是可取的.
通常的做法是添加一个具有唯一ID的查询字符串参数,以强制浏览器获取新版本的js文件(foo.js?cb = 1234)
如何使用es6模块模式实现这一目标?
Ric*_*lli 11
HTTP 标头来救援。使用作为文件校验和的ETag为您的文件提供服务。S3在示例中默认执行此操作。当您再次尝试导入文件时,浏览器将请求该文件,这次将 ETag 附加到“ if-none-match ”标头:服务器将验证 ETag 是否与当前文件匹配并返回一个 304 Not修改,节省带宽和时间,或文件的新内容(带有新的 ETag)。
这样,如果您更改项目中的单个文件,用户将不必下载所有其他模块的完整内容。添加一个短max-age
头也是明智的,这样如果同一模块在短时间内被请求两次,就不会有额外的请求。
如果您添加缓存破坏(例如通过捆绑程序附加 ?x={randomNumber} ,或将校验和添加到每个文件名),您将强制用户在每个新项目版本中下载每个必要文件的完整内容。
在这两种情况下,您无论如何都会对每个文件进行请求(级联上的导入文件将产生新请求,如果您使用 etags,至少可能以小 304 结束)。为避免这种情况,您可以使用动态导入e.g if (userClickedOnSomethingAndINeedToLoadSomeMoreStuff) { import('./someModule').then('...') }
Wan*_*ton 10
对于所有这些,有一种解决方案不涉及查询字符串。假设您的模块文件在/modules/
. 使用相对模块解析./
或../
导入模块时,然后在服务器端重写路径以包含版本号。使用类似的东西/modules/x.x.x/
然后将路径重写为/modules/
. 现在你可以通过包含你的第一个模块来获得模块的全局版本号
<script type="module" src="/modules/1.1.2/foo.mjs"></script>
或者,如果您无法重写路径,那么只需/modules/version/
在开发过程version
中将文件放入文件夹,并在发布时将文件夹重命名为版本号并在脚本标签中更新路径。
b.p*_*ell 10
您可以使用导入映射来实现此目的。我至少在 Edge 中测试过它。这只是将版本号或哈希值附加到查询字符串的老技巧的一个变体。 import
不会将查询字符串发送到服务器,但如果您使用导入映射,它就会发送。
<script type="importmap">
{
"imports": {
"/js/mylib.js": "/js/mylib.js?v=1",
"/js/myOtherLib.js": "/js/myOtherLib.js?v=1"
}
}
</script>
Run Code Online (Sandbox Code Playgroud)
然后在你的调用代码中:
import myThing from '/js/mylib.js';
import * as lib from '/js/myOtherLib.js';
Run Code Online (Sandbox Code Playgroud)