Skip to content

Instantly share code, notes, and snippets.

@jthemphill
Last active October 30, 2024 17:39
Show Gist options
  • Save jthemphill/5365b67cad46f837578e4d10c1a9528e to your computer and use it in GitHub Desktop.
Save jthemphill/5365b67cad46f837578e4d10c1a9528e to your computer and use it in GitHub Desktop.
Figure out which files are causing `babel-plugin-react-compiler` to output bad code and crash Vite's Rollup build
import asyncio
import sys
import typing
"""
vite.config.ts has these lines:
function djb2Hash(str: string): number {
let hash = 5381
for (let i = 0; i < str.length; i++) {
hash = (hash * 33) ^ str.charCodeAt(i)
}
return hash >>> 0 // Ensure positive integer
}
const NUMERATOR = 41
const DENOMINATOR = 256
"""
def write_constants(numerator: int, denominator: int) -> None:
with open("vite_config/vite.config.ts") as f:
lines = f.readlines()
for i, line in enumerate(lines):
if "const NUMERATOR" in line:
lines[i] = f"const NUMERATOR = {numerator}\n"
elif "const DENOMINATOR" in line:
lines[i] = f"const DENOMINATOR = {denominator}\n"
with open("vite_config/vite.config.ts", "w") as f:
f.writelines(lines)
SUCCESS_MESSAGE = 'Export "ConfigConsumer" of module'
FAILURE_MESSAGE = "ENOENT"
async def forward_stream(
input_stream: asyncio.StreamReader,
output_stream: typing.IO[str],
) -> None:
"""Forward a subprocess stream to one of our output streams."""
while not input_stream.at_eof():
line_bytes = await input_stream.readline()
line = line_bytes.decode()
output_stream.write(line)
output_stream.flush()
async def forward_and_parse_stream(
input_stream: asyncio.StreamReader,
output_stream: typing.IO[str],
) -> bool:
"""Process stderr and look for signs of success or failure.
Return True if we see a line indicating successful startup.
Return False if we see an error message.
"""
success: typing.Optional[bool] = None
while True:
line_bytes = await input_stream.readline()
line = line_bytes.decode()
# Forward each line of the process's stdout to our stdout
output_stream.write(line)
output_stream.flush()
# Look for messages which indicate success or failure
if success is None:
if SUCCESS_MESSAGE in line:
success = True
elif FAILURE_MESSAGE in line:
success = False
if success is not None:
return success
async def run_build(
stdout: typing.IO[str],
stderr: typing.IO[str],
) -> bool:
process = await asyncio.create_subprocess_exec(
"/opt/homebrew/bin/pnpm",
"vite:build",
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
assert process.stdout is not None
assert process.stderr is not None
stdout_forward = asyncio.create_task(forward_stream(process.stdout, stdout))
success = await forward_and_parse_stream(process.stderr, stderr)
process.terminate()
await process.wait()
await stdout_forward
return success
async def bisect():
nmodules = 27218
numerator = 41
denominator = 128
# numerator = 297
# denominator = 512
with open("stdout.txt", "w") as stdout:
with open("stderr.txt", "w") as stderr:
while denominator < nmodules * 2:
write_constants(numerator, denominator)
print(f"jeff running: {numerator}/{denominator}...")
success = await run_build(stdout, stderr)
status_emoji = "✅" if success else "❌"
print(f"jeff result: {numerator}/{denominator}: {status_emoji}")
if success:
numerator += denominator // 2
numerator = numerator % denominator
else:
denominator *= 2
if __name__ == "__main__":
asyncio.run(bisect())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment