
一个能自己写自己的 HTML,我在 Safari 上捏碎了
· 阅读约 3 分钟
前几天看到一个叫 Bento 的东西,整个应用——幻灯片、编辑器、逻辑代码——全塞在一个 HTML 文件里。大概 560KB。
你拿浏览器打开它,它能自己改自己。你编辑完,按个保存,它用 File System Access API 把文件流写回硬盘里。
这头牛,我非钻穿不可。
我先把这文件下下来看了一眼。文件最顶上是一大坨 JSON,底下跟着一长串极其折磨人眼球的 base64 字符串。应用逻辑全被压缩成 base64 塞在里面了。相当于这个文件既是数据包,也是程序本体。
<script id="bento-data" type="application/json">
{ "slides": [{ "title": "Hello", "elements": [] }] }
</script>
<script src="data:text/javascript;base64,YmFzZTY0IGVuY29kZWQg..."></script>
这设计挺浪漫的。但我今天不聊它的架构,我想钻的就一件事:它到底怎么做到“自己写自己”的,以及在 Safari 上是怎么翻车的。
平时前端干“保存”这事,搞个 <a> 标签,塞个 download 属性,点一下,浏览器给你扔到下载文件夹里。完事。
但在这种单文件应用里,你改一下,下载一个 bento(1).html,再改一下,又来一个 bento(2).html。灾难。
所以得靠 File System Access API。我先写了个最简单的 demo 摸一下。
const [fileHandle] = await window.showOpenFilePicker();
const writable = await fileHandle.createWritable();
await writable.write(newHtmlContent);
await writable.close();
Chrome 上美滋滋。选好文件改完,硬盘上的文件真就变了。
我当时心想,这不就通了?
结果翻车了。
我把这个 demo 发给朋友,让他在 Safari 上点一下。啥也没发生,哎。控制台一开,showOpenFilePicker is not a function。我又切到 iOS Safari 上试,死得透透的。
活见鬼。
if ('showOpenFilePicker' in window) {
const writable = await fileHandle.createWritable();
await writable.write(newHtmlContent);
await writable.close();
} else {
// 阴间浏览器回退方案
const blob = new Blob([newHtmlContent], {type: 'text/html'});
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'bento.html';
a.click();
}
能用流就流写,不能用就老老实实兜底回下载。你说气不气?Chrome 喊了这么久的本地优先,Safari 到现在还在那儿装死。
这还没完。我拿手机试的时候,在 iOS Safari 里打开那个 560KB 的 HTML,两个手指一捏——
肉眼可见的掉帧,然后白屏。就离谱。
iOS Safari 在处理大体积 DOM 的捏合缩放时,那个合成层的重新计算逻辑玄学得很。你稍微有点复杂的属性挂在节点上,它就卡给你看。我上次钻 transform 触发合成层那个坑的时候,撞过一模一样的墙。你以为是 JS 阻塞了主线程?根本不是,是渲染引擎在重排的时候摆烂了。
想稳住这种交互,就得自己把缩放接管过来,硬生生阻断掉浏览器那个默认行为。
document.addEventListener('gesturestart', (e) => {
e.preventDefault();
});
就这一行。AI 写代码的时候,它可不会管你 iOS Safari 的 gesturestart 有多坑。Cursor 给你生成的代码永远是在理想国里跑的。一到真机上捏一下,直接现原形。它没在真机上跑过,根本不知道这捏一下有多疼。
| 浏览器 | 支持 | 备注 |
|---|---|---|
| Chrome / Edge | 完美 | File System Access API 全绿,写入丝滑 |
| Firefox | 部分支持 | 文件流 API 依旧残废,只能走下载兜底 |
| macOS Safari | 阴间 | 读不了文件,下载一堆 (1) 副本 |
| iOS Safari | 极度阴间 | 双指缩放直接卡死,内存小点的机型闪退 |
拉胯的还是 Safari。桌面版不支持 API 咱忍了,移动版直接把页面捏崩溃,这谁受得了?每次写 Web 应用,Safari 永远是那个逼你下跪求饶的祖宗。
最后,说个跟这篇八竿子打不着的事。昨晚我折腾这个 Bento 文件搞到凌晨两点,想把它的 base64 解码出来看看,手敲了个 Node 脚本去读,结果忘了转编码,终端里刷出来一堆乱码,还伴随着哔哔的报警声。我猫吓得从桌上一跃而下,正好踩中我的回车键,又跑了一遍脚本。我盯着那个疯狂闪烁的黑框,突然觉得这猫 vibe coding 比我强,至少它不挑浏览器。扯远了,反正——嘿嘿,下次见。
评论
还没有评论,写下第一条讨论。