Another interesting use of the File System Access API (<a href="https://caniuse.com/?search=File%20System%20Access%20API" rel="nofollow">https://caniuse.com/?search=File%20System%20Access%20API</a>) is:<p><a href="https://vscode.dev/" rel="nofollow">https://vscode.dev/</a><p>You can grant it access to a directory on your local machine and then edit files like you would in the Electron version.
I wonder how this API will affect Electron apps once it's available there. For some apps the only reason you need non-UI code at all is for working with the file system; seems like it would be great to be able to consolidate more logic into the UI process
I find the way we are slowly converging on Chromium-Powered-Browser as the standard operating system to be both funny and frustrating.<p>I'm really dissatisfied with Electron apps in general and using an an operating system designed to run on top of other operating systems <i>feels</i> wrong.<p>But, I do really like it when things portably <i>just work</i>.
It's not terrible, but it still has a lot of warts. I wrote a saver plugin for Tiddlywiki that uses this API for a self modifying HTML file. <a href="https://slaymaker1907.github.io/tiddlywiki/plugin-library.html" rel="nofollow">https://slaymaker1907.github.io/tiddlywiki/plugin-library.ht...</a><p>One major annoyance is that you can't just show the file picker for "security reasons", it has to be user prompted. This is a useless precaution because you can just add an onclick handler to the document body. It inconveniences non-malware developers while hardly troubling malicious sites at all.<p>Another goodie is that resolving a path is extremely expensive with no opportunity for caching from the OS. You have to parse paths yourself and individually walk each directory.<p>I've also been working on an equivalent API to the fs module in Node lately, but really such an API should have been the #1 priority example for using this API. It would have immediately highlighted how difficult the path problem is. OS/browser engine nerds deal with file descriptors, but most applications work with paths.<p>It also would be great if Firefox would stop being so hostile to this API. The API has problems, but they aren't inherent to the goals of this API. I also find polyfills for this API to be ridiculous. You really can't polyfill this in a meaningful way for the browser because it is so groundbreaking. Having a non-Google implementation of the API would be way more helpful than polyfills.
> Google’s documentation and the specification itself contained this bug in example code.<p>Off-topic, but Google's documentation for _everything_ contains subtle bugs such as this.
Nice article! It’s a great API, hope to see the kinks ironed out.<p>I am using it to stream PNG frames in real-time into a user’s file system, for web-based media tools. This allows the user to generate their own HD video files offline at maximum quality, bringing static web a little closer to pro level media tooling.<p>One downside aside from browser support is that two permissions must be requested for this: one to select the directory to save to, and then again to give write access.
As a native programmer who meddles with the horrors of thread safety and & and &mut, and occasionally dabbles in high-level (JS/Dart) asynchronity, async functions fill me with much of the same fear and caution. await looks like merely a nonblocking function call, but means arbitrary code executes and can and will mutate arbitrary state under your feet. Shared state across coroutines is nearly as dangerous as shared state across threads, and (I conjecture) far more pervasive.<p>In the code in question (<a href="https://web.archive.org/web/20220113153505/https://web.dev/file-system-access/#drag-and-drop-integration" rel="nofollow">https://web.archive.org/web/20220113153505/https://web.dev/f...</a>, now changed in <a href="https://web.dev/file-system-access/#drag-and-drop-integration" rel="nofollow">https://web.dev/file-system-access/#drag-and-drop-integratio...</a>):<p><pre><code> elem.addEventListener('drop', async (e) => {
// Prevent navigation.
e.preventDefault();
// Process all of the items.
for (const item of e.dataTransfer.items) {
// Careful: `kind` will be 'file' for both file
// _and_ directory entries.
if (item.kind === 'file') {
const entry = await item.getAsFileSystemHandle();
if (entry.kind === 'directory') {
handleDirectoryEntry(entry);
} else {
handleFileEntry(entry);
}
}
}
});
</code></pre>
I probably wouldn't have guessed that `e.dataTransfer.items` gets cleared at the first await (since I'm not a proficient web developer), but I would've been <i>extremely</i> wary of this code in general. Additionally (not tied to async-await but race conditions in general), is `item.getAsFileSystemHandle()` a TOCTTOU vulnerability where the type of an item can change between folders and files and symlinks etc., while this code is running?<p>Rust's & vs. &mut system largely eliminates shared state hazards in both threading and asynchronity (&mut is exclusive/unaliased and can't be mutated by other threads or event loop jobs, and & is difficult and unidiomatic to mutate), though it doesn't solve async cancellation errors (<a href="https://carllerche.com/2021/06/17/six-ways-to-make-async-rust-easier/" rel="nofollow">https://carllerche.com/2021/06/17/six-ways-to-make-async-rus...</a>, discussed at <a href="https://news.ycombinator.com/item?id=27542504" rel="nofollow">https://news.ycombinator.com/item?id=27542504</a>), or filesystem TOCTTOU (<a href="https://blog.rust-lang.org/2022/01/20/cve-2022-21658.html" rel="nofollow">https://blog.rust-lang.org/2022/01/20/cve-2022-21658.html</a> as well as user code).<p>Qt event loop reentrancy is fun(tm) as well. It looks like a blocking call, but spawns a nested event loop which can do anything (but rarely enough to lull you into a false sense of complacency), resulting in segfaults like <a href="https://github.com/Nheko-Reborn/nheko/issues/656" rel="nofollow">https://github.com/Nheko-Reborn/nheko/issues/656</a> (workaround at <a href="https://github.com/Nheko-Reborn/nheko/commit/570d00b000bd558592af317746fa3639fb022fa4" rel="nofollow">https://github.com/Nheko-Reborn/nheko/commit/570d00b000bd558...</a>, I didn't look into it). And Qt lacks "easy" await syntax and a framework based on calling red functions (though I didn't look into C++20 coroutines yet, perhaps <a href="https://www.qt.io/blog/asynchronous-apis-in-qt-6" rel="nofollow">https://www.qt.io/blog/asynchronous-apis-in-qt-6</a> or <a href="https://github.com/mhogomchungu/tasks" rel="nofollow">https://github.com/mhogomchungu/tasks</a> or <a href="https://blog.blackquill.cc/asynchronous-qtquick-uis-and-their-implementation-the-toolbox#thennables" rel="nofollow">https://blog.blackquill.cc/asynchronous-qtquick-uis-and-thei...</a>?).