modulepreload 与 preload 区别
preload 仅仅下载和缓存资源,而 modulepreload 还会对 module 预编译,这会减小 FID。
此外,使用 preload 预加载 module,可能会导致 module 被重复下载两次,这归因于 CORS 策略的差异:
link、script 等标签都有一个 crossorigin 属性,它有三个值:未设置 crossorigin,crossorigin=anonymous 和 crossorigin=use-credentials。
而当 script 的 type=module 时,未设置 crossorigin == crossorigin=anonymous,这下只有两个值了。因此在默认情况下:
-
-
module 会因 CORS 策略的不同被意外的下载两次,除非为每个 link 都设置 crossorigin。但是 modulepreload 不存在此问题,因为它的行为默认与 script type=module 一致。
#learning
preload 仅仅下载和缓存资源,而 modulepreload 还会对 module 预编译,这会减小 FID。
此外,使用 preload 预加载 module,可能会导致 module 被重复下载两次,这归因于 CORS 策略的差异:
link、script 等标签都有一个 crossorigin 属性,它有三个值:未设置 crossorigin,crossorigin=anonymous 和 crossorigin=use-credentials。
而当 script 的 type=module 时,未设置 crossorigin == crossorigin=anonymous,这下只有两个值了。因此在默认情况下:
-
<script type=module> 未设置 crossorigin,表示使用 CORS,等价于 crossorigin="anonymous"-
<link rel=preload> 未设置 crossorigin,表示不使用 CORSmodule 会因 CORS 策略的不同被意外的下载两次,除非为每个 link 都设置 crossorigin。但是 modulepreload 不存在此问题,因为它的行为默认与 script type=module 一致。
#learning
👍4
🌸
https://publicsuffix.org/list/public_suffix_list.dat JP 域名分得好细,粗略数了下,大概有1900多条 .jp 记录,应该是列表里最多的了。
对了, github.io、 gitlab.io、 glitch.me 这些也在里面,这表示像 github.io 也被当成“顶级域(TLD)”对待。
也就是说 a.github.io 和 b.github.io 是两个完全独立的站点,并不共享资源。
也就是说 a.github.io 和 b.github.io 是两个完全独立的站点,并不共享资源。
想到两个 Service Worker 奇怪用法
1. 把一个页面(或数据)拆成 header、content、footer 三部分,在 Service Worker 缓存并自动拼上 header、footer,这样以后都只请求 content 就行了,相当是把 Service Worker 做成了一个简单的 rendering engine。
2. 在 Service Worker 维持一个 wss,并在会话建立后,把所有 HTTP Request 都 over wss,这样可以同时受益于 HTTP 的低会话成本、wss 的低延迟。
第二个打算近期找时间试一试,看看在小范围内能否获得性能提升。
#神奇海螺
1. 把一个页面(或数据)拆成 header、content、footer 三部分,在 Service Worker 缓存并自动拼上 header、footer,这样以后都只请求 content 就行了,相当是把 Service Worker 做成了一个简单的 rendering engine。
2. 在 Service Worker 维持一个 wss,并在会话建立后,把所有 HTTP Request 都 over wss,这样可以同时受益于 HTTP 的低会话成本、wss 的低延迟。
第二个打算近期找时间试一试,看看在小范围内能否获得性能提升。
#神奇海螺
Safari 16 将支持 Web Push API
Apple 将为 Safari 16 带来全平台的 Web Push Notifications 支持,它是最后一个提供 Web Push 支持的主流浏览器,届时 Web Push 将在所有主流平台可用。
此外,Safari on iOS 的 Web Notifications API 在此次更新后依旧不可用,它并没有被特别提到。
ref:
https://www.apple.com/ios/ios-16-preview/features/
https://www.apple.com/macos/macos-ventura-preview/features/
Apple 将为 Safari 16 带来全平台的 Web Push Notifications 支持,它是最后一个提供 Web Push 支持的主流浏览器,届时 Web Push 将在所有主流平台可用。
此外,Safari on iOS 的 Web Notifications API 在此次更新后依旧不可用,它并没有被特别提到。
ref:
https://www.apple.com/ios/ios-16-preview/features/
https://www.apple.com/macos/macos-ventura-preview/features/
Apple
OS - iOS 26
iOS 26 for iPhone with a new design, more helpful Apple Intelligence, polls and backgrounds in Messages, and features that make every day effortless.
Forwarded from Zenithal Hourly Radio
Vite 多入口踩坑
想给项目加多一个入口,并可以通过 /admin 请求(与前端的路由保持一致),按照 Vite 的目录结构,应该在 projectRoot 创建一个 admin 目录。
于是我创建了 projectRoot/admin/index.html 文件,并在浏览器中通过 /admin 测试,屡屡失败,但请求 /admin/index.html 却可以。
这一旦让我怀疑是自己配置的不对,因为 文档 确实是这么写的,我开始了在配置与配置之间反复调整,然后陷入不断的自我怀疑。
直到 ── 这时时间已经过去很久,我在偶然中发现,/admin 与 /admin/ 是不同的,请求 /admin/ 竟然可以!!这时我既喜悦,又气愤,这 TM 算什么 J8 设计??
此前我确实反复读了文档,文档也确实写的 `/nested/`,这没毛病,但却没写 /nested/ 和 /nested 是不同的,就连顺带一提 “注意最后的 /” 都没有,这让人下意识觉得只是书写风格的不同 ── 毕竟其它“常规”的 webserver 都应该默认认为这二者是等价的。
退一步说,如果 /nested/ 表示目录,/nested 表示文件,但是你能在同一个目录里建两个完全同名,但类型不同的东西?所以添加 “/” 的意义是什么,我是真的不理解。
---
补充内容:
写完这篇 post,我找到了 这个5个月前的 issue,它被标记为 bug,目前还是 open 状态。然而我并不确定这是不是 bug,因为 Vite 确实被实现为区分 “/”,而且文档也与这种行为保持了一致(最后带了 “/”),因此至少在写文档时,是很清楚 Vite 会有这种行为的。
所以我更倾向这是“先天性设计问题”,直到后来有像我这样的傻瓜踩到坑,被提出来,才被定性为“bug”。但是因为这个,我浪费了大量宝贵时间,实属不值!
想给项目加多一个入口,并可以通过 /admin 请求(与前端的路由保持一致),按照 Vite 的目录结构,应该在 projectRoot 创建一个 admin 目录。
于是我创建了 projectRoot/admin/index.html 文件,并在浏览器中通过 /admin 测试,屡屡失败,但请求 /admin/index.html 却可以。
这一旦让我怀疑是自己配置的不对,因为 文档 确实是这么写的,我开始了在配置与配置之间反复调整,然后陷入不断的自我怀疑。
直到 ── 这时时间已经过去很久,我在偶然中发现,/admin 与 /admin/ 是不同的,请求 /admin/ 竟然可以!!这时我既喜悦,又气愤,这 TM 算什么 J8 设计??
此前我确实反复读了文档,文档也确实写的 `/nested/`,这没毛病,但却没写 /nested/ 和 /nested 是不同的,就连顺带一提 “注意最后的 /” 都没有,这让人下意识觉得只是书写风格的不同 ── 毕竟其它“常规”的 webserver 都应该默认认为这二者是等价的。
退一步说,如果 /nested/ 表示目录,/nested 表示文件,但是你能在同一个目录里建两个完全同名,但类型不同的东西?所以添加 “/” 的意义是什么,我是真的不理解。
---
补充内容:
写完这篇 post,我找到了 这个5个月前的 issue,它被标记为 bug,目前还是 open 状态。然而我并不确定这是不是 bug,因为 Vite 确实被实现为区分 “/”,而且文档也与这种行为保持了一致(最后带了 “/”),因此至少在写文档时,是很清楚 Vite 会有这种行为的。
所以我更倾向这是“先天性设计问题”,直到后来有像我这样的傻瓜踩到坑,被提出来,才被定性为“bug”。但是因为这个,我浪费了大量宝贵时间,实属不值!
😁1
Rollup plugin 可能会为 virtual module id 添加 \0
Rollup 约定如果一个插件使用了 virtual module,则它的 id 需要以 \0 开头。
我发现这个,是因为在配置 manualChunks 时,出现了一些莫名其妙的问题,比如本是 dynamic import 的 bundle,却被提前 import 了。
在我的项目里,这是由于 commonjs 插件的 commonjsHelpers.js 被打包在了这个毫不相关的 bundle 里。而根本原因是我使用 id === 'commonjsHelpers.js' 比较 id,但实际的 id 是 '\0commonjsHelpers.js'。
这意味着,最好使用 id.includes('commonjsHelpers.js') 比较,或至少是 id.endsWith('commonjsHelpers.js') 而不是 startsWith。
话虽如此,某些插件创建的,如以 react/ 或 vite/ 开头的 module,依旧可以使用 startsWith,因为它们并不包含 \0。
#experience
Rollup 约定如果一个插件使用了 virtual module,则它的 id 需要以 \0 开头。
我发现这个,是因为在配置 manualChunks 时,出现了一些莫名其妙的问题,比如本是 dynamic import 的 bundle,却被提前 import 了。
在我的项目里,这是由于 commonjs 插件的 commonjsHelpers.js 被打包在了这个毫不相关的 bundle 里。而根本原因是我使用 id === 'commonjsHelpers.js' 比较 id,但实际的 id 是 '\0commonjsHelpers.js'。
这意味着,最好使用 id.includes('commonjsHelpers.js') 比较,或至少是 id.endsWith('commonjsHelpers.js') 而不是 startsWith。
话虽如此,某些插件创建的,如以 react/ 或 vite/ 开头的 module,依旧可以使用 startsWith,因为它们并不包含 \0。
#experience
Rollup 插件开发:让 Service Worker 中的 import 支持 Firefox
我有一个 packet module,它是一个实现了 binary communication protocol 的 common module,这意味着它不只在 SW 中使用,还会在通常的 browser context 中使用,因此可以将该 module 打包为独立的 bundle,以便能在这两个不同的地方分别 import 它。
但是,import statement in workers 在 Chrome、Edge、Safari 都得到了支持,而 Firefox 却不支持。要想让 SW 在 Firefox 也能正常工作,就必须考虑另外一个方案:将 packet module 分别为 SW 和 browser context 打包两份,也就是说 packet 一份代码抽象为两份存在,此时便不再需要 import。这没关系,因为它足够小且足够关键。
那么,问题是,在 Rollup 中每个 module 由一个 unique id 标识,这意味着 不可能让一份 id 产出两份代码。在这里,我选用更加灵活的 virtual module 实现这一目的。
操作步骤是,在 transform hook 中 parse SW entry 的 AST,traverse 里面所有的 import nodes,并分别将它们替换,如
替换后的模块名会进入 resolveId hook,在这里需要为其补全 extension,如 `sw-import:../utils/packet.ts`,并在随后的 load 中将其从 fs 加载即可。最后还需要在 manualChunks 中,检查 id 是否包含 `sw-import:`,如若包含,将其与 SW scripts 打包到一起,否则打包到 common bundle 并服务于常规的 browser context。
#experience
我有一个 packet module,它是一个实现了 binary communication protocol 的 common module,这意味着它不只在 SW 中使用,还会在通常的 browser context 中使用,因此可以将该 module 打包为独立的 bundle,以便能在这两个不同的地方分别 import 它。
但是,import statement in workers 在 Chrome、Edge、Safari 都得到了支持,而 Firefox 却不支持。要想让 SW 在 Firefox 也能正常工作,就必须考虑另外一个方案:将 packet module 分别为 SW 和 browser context 打包两份,也就是说 packet 一份代码抽象为两份存在,此时便不再需要 import。这没关系,因为它足够小且足够关键。
那么,问题是,在 Rollup 中每个 module 由一个 unique id 标识,这意味着 不可能让一份 id 产出两份代码。在这里,我选用更加灵活的 virtual module 实现这一目的。
操作步骤是,在 transform hook 中 parse SW entry 的 AST,traverse 里面所有的 import nodes,并分别将它们替换,如
import {pack, unpack} from '../utils/packet' 替换为 import {pack, unpack} from 'sw-import:../utils/packet'。替换后的模块名会进入 resolveId hook,在这里需要为其补全 extension,如 `sw-import:../utils/packet.ts`,并在随后的 load 中将其从 fs 加载即可。最后还需要在 manualChunks 中,检查 id 是否包含 `sw-import:`,如若包含,将其与 SW scripts 打包到一起,否则打包到 common bundle 并服务于常规的 browser context。
#experience
👍1