Skip to content

fix(vrowzer): write binary files given to ready() as bytes in both Workers - #66

Merged
kazupon merged 3 commits into
mainfrom
fix/ready-binary-files
Oct 1, 2026
Merged

kazupon merged 3 commits into
mainfrom
fix/ready-binary-files

Conversation

@kazupon

@kazupon kazupon commented Oct 1, 2026

Copy link
Copy Markdown
Owner

Closes #65

Binary files (ArrayBuffers) passed to ready({ files }) are now written with their bytes in both Workers, instead of as the string [object ArrayBuffer].

Cause

initialize() treated config.files as Record<string, string> and sent the files as text:

  • The Web Worker received them in the files of V_WW_SETUP, and updateFile() wrote every value with { encoding: 'utf8' }.
  • The Service Worker received them in the text field files of V_FS_INIT, which the @vrowzer/fs subscriber writes as UTF-8. The binary field, binaryFiles, was not used.

Binary files added later with addFile() or updateFile() were not affected.

Fix

  • Service Worker: initialize() splits the files into text and binary, and sends the binary files in binaryFiles of V_FS_INIT. The subscriber already writes them as bytes and emits add events, so public images also enter the public file list (fix(vite-dev-server): serve public files given to the runtime from the Service Worker #64). @vrowzer/fs is unchanged. With text files only, the message is the same as before.
  • Web Worker: updateFile() writes an ArrayBuffer as bytes, as the subscriber does, and a string as UTF-8 text as before. SetupWorkerMessage.files, setupWorker() and updateFile() accept ArrayBuffer values. The types are only widened, so existing callers keep working.
  • Copies: ready() copies the files when it is called, ArrayBuffers included, and sends the copies without a transfer list. Each Worker receives its own copy through structured cloning, and the caller's buffers stay usable, as with addFile() since feat(vrowzer): resolve file operations after the Workers apply them #61.
  • The JSDoc of VrowzerConfig.files and the README section of ready() describe the copy. The API references are regenerated.

FileSystemPublisher.initFiles() is not used. It would also send the files to the Web Worker, which already loaded them during setup, and it has its own bug (#63).

Behavior change

ready() now sends the files as they were when it was called. Before, it read config.files later, after loading the client files, and each Worker received the ArrayBuffers as they were when its message was sent. So changes that the caller made while ready() ran could reach one Worker and not the other, and an ArrayBuffer that the caller detached in the meantime could make ready() fail.

This keeps one extra copy of each binary file in memory until ready() finishes.

Not included

Tests

  • Unit tests:

    • transformer.test.ts: updateFile() and the initial files of setupWorker() write an ArrayBuffer as bytes and a string as UTF-8 text. Both tests failed before the change.

    • index-file-sync.test.ts:

      • binary files reach both Workers as copies with the same bytes, in the files of V_WW_SETUP and in the binaryFiles of V_FS_INIT, without a transfer list, and the caller's buffer keeps its bytes;
      • changes made right after calling ready(), to an ArrayBuffer or to the file record, do not reach the Workers.

      Both tests failed before the change, and fail again without the copy in ready(). The existing test of text-only initialization passes unchanged.

  • Integration tests in the shared playground, which now passes a public image and a binary file outside the public directory to ready():

    • the Service Worker serves both with the same bytes, through servePublicMiddleware and serveStaticMiddleware;
    • the Web Worker inlines the same bytes with ?import&inline;
    • the caller's ArrayBuffers keep their size and content after ready().

    Reverting either fix makes the matching test fail with the bytes of [object ArrayBuffer]. This also confirms in the browser that both Workers were affected.

Validated locally with:

  • vp run test:unit: 119 files, 1,911 tests
  • vp run test:integration:vrowzer: 67 passed and 1 conditional skip, in three runs
  • vp run test:e2e: 46 passed, 6 existing test.skip
  • oxlint (no new warnings), knip, the format check of the changed files, and typecheck

…eb Worker

The Web Worker wrote every file given in V_WW_SETUP with { encoding: 'utf8' }, so an ArrayBuffer was written as the string "[object ArrayBuffer]".

updateFile() now writes an ArrayBuffer as bytes, as the @vrowzer/fs subscriber does for binary content, and a string as UTF-8 text as before. SetupWorkerMessage.files and setupWorker() accept ArrayBuffer values.
…kers

initialize() treated config.files as text. The Web Worker received the ArrayBuffers in V_WW_SETUP, and the Service Worker in the text field of V_FS_INIT, so both wrote them as the string "[object ArrayBuffer]".

The Service Worker now receives binary files in the binaryFiles field of V_FS_INIT, which @vrowzer/fs writes as bytes. The Web Worker writes the ArrayBuffers in V_WW_SETUP as bytes since the previous commit. With text files only, V_FS_INIT is the same as before.

ready() copies the files when it is called, ArrayBuffers included, and sends the copies without a transfer list. Each Worker receives its own copy through structured cloning, and the caller's buffers stay usable. Changes that the caller makes while ready() runs no longer reach the Workers; before, the files were read later, so such changes could reach one Worker and not the other.

The JSDoc of VrowzerConfig.files and the README describe the copy, and the API references are regenerated.
The playground now passes two binary files to ready(): a public image and a file outside the public directory. The tests check that the Service Worker serves both with the same bytes, through servePublicMiddleware and serveStaticMiddleware, that the Web Worker inlines the same bytes with ?import&inline, and that the caller's ArrayBuffers keep their size and content after ready().

Without either fix, the matching test fails with the bytes of "[object ArrayBuffer]": sending the binary files in the text field of V_FS_INIT fails the Service Worker test, and writing them as UTF-8 in the Web Worker fails the Web Worker test.
@kazupon
kazupon merged commit 222ca64 into main Oct 1, 2026
4 checks passed
@kazupon
kazupon deleted the fix/ready-binary-files branch October 1, 2026 09:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Write binary files given to ready() as bytes in both Workers

1 participant