The problem
While the web developer tools in Firefox and Chrome provide a
Storage/Application tab for inspecting the local data stored by a web
app, neither shows OPFS files there, making it difficult to
tell what's going wrong when you have a bug (which was a problem when
writting my recent blog posts about OPFS). There's open
Firefox and Chromium
bugs about the missing feature, so if it's been a while since this was
posted when you're reading this, hopefully this is no longer a problem.
Additionally, the tools I did find all use recursion, resulting in
them failing to work on the deeply nested directory tree I created by
accident.
The solution
If you don't have several hundred levels deep of nested directories,
you can just use this Chrome extension or
this script (or probably
this web component, although I couldn't get it to
install), all named "opfs-explorer".
The following AsyncIterator returns all of the files in
OPFS without using recursion and adds properties to include their full
path and parent directory:
async function* getFilesNonRecursively(dir) {
const stack = [[dir, "", undefined, 0]];
while (stack.length) {
const [current, prefix, parentDir] = stack.pop();
current.relativePath = prefix + current.name;
current.parentDir = parentDir;
current.depth = depth;
yield current;
if (current.kind === "directory") {
for await (const handle of current.values()) {
stack.push([handle,
prefix + current.name + "/",
current,
depth + 1]);
}
}
}
}
And here's the simple HTML display function I've been using that calls that
(you will likely want to modify this to your preferences):
async function displayOPFSFileList() {
const existing = document.getElementById("opfs-file-list");
const l = document.createElement('ol');
l.id = "opfs-file-list";
if (existing) existing.replaceWith(l);
else document.body.appendChild(l);
const root = await navigator.storage.getDirectory();
for await (const fileHandle
of getFilesNonRecursively(root)) {
const i = document.createElement("li");
i.innerText = fileHandle.kind + ": "
+ (fileHandle.relativePath ?? "(root)");
if (fileHandle.kind === "file") {
const content = await fileHandle.getFile();
const contentStr = content.type.length === 0
|| content.type.startsWith("text/")
? ("\"" + (await content.slice(0, 100).text()).trim()
+ "\"")
: content.type;
i.innerText += ": (" + content.size + " bytes) "
+ contentStr;
}
l.appendChild(i);
}
}
The details