fix: use file_get_contents to prevent large JS files (>8KB) from being truncated#208
Conversation
ReadableResourceStream sets the php://temp stream to non-blocking mode, causing AMPHP's fiber event loop to deliver only the first 8192-byte chunk. Files larger than 8KB are silently truncated, producing 'SyntaxError: Unexpected end of input' in Playwright. Replacing fopen/fread/php://temp/ReadableResourceStream with a plain file_get_contents + string response body sends the full file content in one shot, bypassing the async read-chunk limitation. This also fixes the 0-byte fread crash from #1635 without needing a separate filesize() guard. Fixes pestphp/pest#1664
There was a problem hiding this comment.
Pull request overview
Fixes truncation of JavaScript assets >8KB when served by the internal Laravel HTTP server during browser tests by switching from an AMPHP resource stream pipeline to a string body response.
Changes:
- Replace
fopen/ReadableResourceStream-based asset serving withfile_get_contents()+ string response body. - Keep JS URL rewriting but apply it directly to the in-memory string.
- Add explicit
Content-Lengthheader based on the final rewritten content.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…sets Address review feedback: only use file_get_contents for .js files where the php://temp + ReadableResourceStream truncation occurs. Non-JS assets (images, fonts, CSS) continue to use ReadableResourceStream on the real file handle, which is not affected by the 8KB chunk issue and is more memory-efficient for large binary files. Also adds an explanatory comment on why file_get_contents is used.
Adds a test that creates a JS file slightly above 8192 bytes with a sentinel string at the end, then asserts the full content is returned. Without the fix, ReadableResourceStream would truncate the response to the first 8KB, causing the sentinel assertion to fail.
|
Addressed both review comments: Memory concern (r3057164015): Fixed — the Regression test (r3057164073): Added in |
Problem
When running browser tests, all static JS files larger than 8192 bytes are truncated to exactly 8KB, causing
SyntaxError: Unexpected end of inputin Playwright. This makesassertNoJavaScriptErrors()fail on any page loading Livewire, Filament, or any Vite bundle.Evidence
Capturing error details via
window.__pestBrowser.jsErrorsafterwaitForLoadState('networkidle'):[ { "message": "Uncaught SyntaxError: Unexpected end of input", "filename": ".../livewire.min.js", "lineno": 1, "colno": 8193 }, { "message": "Uncaught SyntaxError: Unexpected end of input", "filename": ".../support.js", "lineno": 1, "colno": 8193 }, { "message": "Uncaught SyntaxError: Invalid or unexpected token", "filename": ".../tables.js", "lineno": 1, "colno": 8189 } ]colno: 8193= exactly 8192 bytes received — one AMPHP read chunk.Root Cause
ReadableResourceStreamsets the stream to non-blocking mode (stream_set_blocking($resource, false)). Forphp://tempin non-blocking mode, AMPHP's fiber event loop only delivers the first 8192-byte chunk and does not schedule further reads within the same request, so files >8KB are silently truncated.Fix
Replace the
fopen/fread/php://temp/ReadableResourceStreampipeline withfile_get_contentsand a plain string response body. The AMPHPResponseaccepts a string body and sends it in full, bypassing async read-chunk limitations entirely.This also supersedes PR #203: the
filesize() === 0guard is no longer needed sincefile_get_contentson an empty file returns''rather than crashing.Fixes pestphp/pest#1664
Also fixes pestphp/pest#1635