Skip to content

feat: replace Buffer-based base64 paths with engine-neutral paths#98

Draft
Phillip9587 wants to merge 1 commit into
jshttp:masterfrom
Phillip9587:exodus-bytes
Draft

feat: replace Buffer-based base64 paths with engine-neutral paths#98
Phillip9587 wants to merge 1 commit into
jshttp:masterfrom
Phillip9587:exodus-bytes

Conversation

@Phillip9587
Copy link
Copy Markdown
Contributor

Migrate base64 encode/decode paths away from Node.js-specific Buffer to @exodus/bytes for cross-engine compatibility. Add base64 benchmarks for Buffer, @exodus/bytes, base64-js, and Uint8Array.fromBase64()/toBase64() with TextEncoder/TextDecoder, using runtime guards.

https://github.com/ExodusOSS/bytes does the heavy lifting of choosing the right implementation per environment.

Performance Comparison accross engines:

https://docs.google.com/spreadsheets/d/1GnQYzrzEdF3Ea1hJUoEkEZEVNUI3ve8PKPFhLWcEoBI/edit?gid=0
https://github.com/ExodusOSS/bytes/blob/main/Performance.md

I decided to use the strict utf8 methods that throws on invalid UTF-8 byte sequences. We can also use the loose methods that uses the replacement char instead of throwing but I think the strict method is more correct.

Migrate base64 encode/decode paths away from Node.js-specific Buffer to @exodus/bytes for cross-engine compatibility.
Add base64 benchmarks for Buffer, @exodus/bytes, base64-js, and Uint8Array.fromBase64()/toBase64() with TextEncoder/TextDecoder, using runtime guards.
@Phillip9587 Phillip9587 requested a review from blakeembrey May 13, 2026 19:22
@codecov
Copy link
Copy Markdown

codecov Bot commented May 13, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (1ba386f) to head (174b60f).

Additional details and impacted files
@@            Coverage Diff            @@
##            master       #98   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            1         1           
  Lines           55        61    +6     
  Branches        20        22    +2     
=========================================
+ Hits            55        61    +6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@blakeembrey
Copy link
Copy Markdown
Member

@Phillip9587 Using Buffer still seems incredibly fast when I check out this PR locally, are you seeing something different?

  decode base64-js - src/base64.bench.ts > base64 decode - short
    1.14x faster than decode Buffer
    2.38x faster than decode Uint8Array.fromBase64
    2.90x faster than decode @exodus/bytes

  encode Buffer - src/base64.bench.ts > base64 encode - short
    1.70x faster than encode @exodus/bytes
    2.50x faster than encode Uint8Array.toBase64
    3.28x faster than encode base64-js

  decode Buffer - src/base64.bench.ts > base64 decode - long
    1.97x faster than decode Uint8Array.fromBase64
    2.34x faster than decode @exodus/bytes
    2.51x faster than decode base64-js

  encode Buffer - src/base64.bench.ts > base64 encode - long
    2.25x faster than encode Uint8Array.toBase64
    2.38x faster than encode @exodus/bytes
    10.60x faster than encode base64-js

Makes me feel like it should still be Buffer and fallback on Uint8Array? Do you want older browser support without Uint8Array?

@blakeembrey
Copy link
Copy Markdown
Member

We may also want to consider applying size-limit if this is intended for browsers and other environments. I'm not sure pulling in that dependency is worth it.

@Phillip9587
Copy link
Copy Markdown
Contributor Author

@blakeembrey Hey, I took a look at your refactoring of my PR in #95. Please give me some time to explain my reasoning behind this PR versus #95. It’s currently holiday in Germany, so I’m away for the weekend.

@blakeembrey
Copy link
Copy Markdown
Member

Of course, no rush! In case it helps, my context is that it's a trade-off between package size and performance. Since Buffer is fastest anyway, and non-Buffer environments are package size constrained, it seemed best balance to ship something fast and small with the option of having those other environments opt-in via encode/decode options or polyfills to the larger package size.

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.

2 participants