Skip to content

Conversation

@gronxb
Copy link

@gronxb gronxb commented Oct 22, 2025

Summary

Fixed #2701

First of all, buffer is a built-in API in Node.js, so it cannot be used in React Native.
However, it seems to be used here.

But if someone has installed the buffer package, it would still be imported successfully even if react-native-svg doesn’t explicitly declare it as a dependency (a so-called “phantom dependency”).

Still, it’s strange that react-native-svg has buffer as a dependency.

Therefore, we should replace it with atob (a built-in API) for the conversion, and remove buffer from the code

If you are using an older version of React Native, atob might not be available in Hermes.
However, since there are already many polyfill implementations for atob, it’s still better than having no buffer at all.

Test Plan

https://github.com/Nodonisko/hermesx

i have test hermesx

mkdir buffer-test
cd buffer-test
npm init
npm install -g hermesx
npm install buffer

Create test code test.ts

import { Buffer } from "buffer";

const decodeBase64ImageOrigin = (uri: string) => {
  const decoded = decodeURIComponent(uri);
  const splitContent = decoded.split(";")[1].split(",");
  const dataType = splitContent[0] as BufferEncoding;
  const content = splitContent.slice(1).join(",");

  return Buffer.from(content, dataType).toString("utf-8");
};

const decodeBase64ImageWithAtob = (uri: string) => {
  const decoded = decodeURIComponent(uri);
  const splitContent = decoded.split(";")[1].split(",");
  const content = splitContent.slice(1).join(",");

  // Decode base64 using native APIs
  return atob(content);
};

// Test SVG URIs
const testSVGs = {
  blueRectangle: `data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj4KICA8cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYmx1ZSIgLz48L3N2Zz4=`,
  redCircle: `data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHRpdGxlPkNpcmNsZTwvdGl0bGU+CiAgPGNpcmNsZSBjeD0iNTAiIGN5PSI1MCIgcj0iNDIiIHN0eWxlPSJmaWxsOnJlZDsiIC8+Cjwvc3ZnPg==`,
  greenTriangle: `data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBvbHlnb24gcG9pbnRzPSI1MCwxMCAxMCw5MCA5MCw5MCIgc3R5bGU9ImZpbGw6Z3JlZW47IiAvPgo8L3N2Zz4=`,
  wavyIcon: `data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IS0tIFVwbG9hZGVkIHRvOiBTVkcgUmVwbywgd3d3LnN2Z3JlcG8uY29tLCBHZW5lcmF0b3I6IFNWRyBSZXBvIE1peGVyIFRvb2xzIC0tPgo8c3ZnIGZpbGw9IiMwMDAwMDAiIHdpZHRoPSI4MDBweCIgaGVpZ2h0PSI4MDBweCIgdmlld0JveD0iMCAwIDI1NiAyNTYiIGlkPSJGbGF0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxwYXRoIGQ9Ik0zNi44NzUsNzQuNDkwMjNhMy45OTU4MiwzLjk5NTgyLDAsMCwxLC42MjYtNS42MTMyOEE3Ny4zNjg1Niw3Ny4zNjg1NiwwLDAsMSw2NS4wMjk3OSw1Ni4xMTkxNGMxNS4zODEzNC0zLjg0Mzc1LDM5LjE3Njc1LTQuNzg5MDYsNjUuMTg5LDEyLjU1Mjc0LDE4LjgyMjI3LDEyLjU0Nzg1LDM4LjUsMTYuNDI3NzMsNTguNDg2ODIsMTEuNTI3MzRhNzAuNzc5MDYsNzAuNzc5MDYsMCwwLDAsMjQuODAxNzUtMTEuMzI3MTUsMy45OTk3NSwzLjk5OTc1LDAsMCwxLDQuOTkxNyw2LjI1MSw3Ny4zNjg1Niw3Ny4zNjg1NiwwLDAsMS0yNy41Mjg4MSwxMi43NTc4MSw3Ny4yNDgwNiw3Ny4yNDgwNiwwLDAsMS0xOC43MTUzMywyLjMxMTUyYy0xMy4zODU3NC4wMDEtMjkuNDU0MS0zLjUxNzU4LTQ2LjQ3MzYzLTE0Ljg2NDI2QzEwNi45NTksNjIuNzc5Myw4Ny4yODA3Niw1OC44OTk0MSw2Ny4yOTQ0Myw2My44MDA3OEE3MC43NzkwNiw3MC43NzkwNiwwLDAsMCw0Mi40OTI2OCw3NS4xMjc5Myw0LjAwMzg2LDQuMDAzODYsMCwwLDEsMzYuODc1LDc0LjQ5MDIzWm0xNzYuNjMyMzIsNTAuMzgxODRhNzAuNzc5MDYsNzAuNzc5MDYsMCwwLDEtMjQuODAxNzUsMTEuMzI3MTVjLTE5Ljk4NjgyLDQuODk5NDEtMzkuNjY0NTUsMS4wMjA1MS01OC40ODY4Mi0xMS41MjczNC0yNi4wMTIyMS0xNy4zNDA4My00OS44MDc2Mi0xNi4zOTY0OS02NS4xODktMTIuNTUyNzRBNzcuMzY4NTYsNzcuMzY4NTYsMCwwLDAsMzcuNTAxLDEyNC44NzdhMy45OTk3NSwzLjk5OTc1LDAsMCwwLDQuOTkxNyw2LjI1MSw3MC43NzkwNiw3MC43NzkwNiwwLDAsMSwyNC44MDE3NS0xMS4zMjcxNWMxOS45ODYzMy00LjkwMjM0LDM5LjY2NDU1LTEuMDIwNTEsNTguNDg2ODIsMTEuNTI3MzQsMTcuMDE5NTMsMTEuMzQ2NjgsMzMuMDg3ODksMTQuODY1MjQsNDYuNDczNjMsMTQuODY0MjZBNzkuNDQ5NzIsNzkuNDQ5NzIsMCwwLDAsMjE4LjQ5OSwxMzEuMTIzMDVhMy45OTk3NSwzLjk5OTc1LDAsMCwwLTQuOTkxNy02LjI1MVptMCw1NmE3MC43NzkwNiw3MC43NzkwNiwwLDAsMS0yNC44MDE3NSwxMS4zMjcxNWMtMTkuOTg2ODIsNC44OTk0MS0zOS42NjQ1NSwxLjAxOTUzLTU4LjQ4NjgyLTExLjUyNzM0LTI2LjAxMjIxLTE3LjM0MDgzLTQ5LjgwNzYyLTE2LjM5NjQ5LTY1LjE4OS0xMi41NTI3NEE3Ny4zNjg1Niw3Ny4zNjg1NiwwLDAsMCwzNy41MDEsMTgwLjg3N2EzLjk5OTc1LDMuOTk5NzUsMCwwLDAsNC45OTE3LDYuMjUxLDcwLjc3OTA2LDcwLjc3OTA2LDAsMCwxLDI0LjgwMTc1LTExLjMyNzE1YzE5Ljk4NjMzLTQuOTAzMzIsMzkuNjY0NTUtMS4wMjA1MSw1OC40ODY4MiwxMS41MjczNCwxNy4wMTk1MywxMS4zNDY2OCwzMy4wODc4OSwxNC44NjUyNCw0Ni40NzM2MywxNC44NjQyNkE3OS40NDk3Miw3OS40NDk3MiwwLDAsMCwyMTguNDk5LDE4Ny4xMjMwNWEzLjk5OTc1LDMuOTk5NzUsMCwwLDAtNC45OTE3LTYuMjUxWiIvPgo8L3N2Zz4=`,
};

// Test each SVG
console.log("=== SVG Base64 Decoding Test ===\n");

Object.entries(testSVGs).forEach(([name, uri]) => {
  console.log(`\n--- Testing: ${name} ---`);

  const origin = decodeBase64ImageOrigin(uri);
  const atobResult = decodeBase64ImageWithAtob(uri);
  const isEqual = origin === atobResult;

  console.log("Origin method:", origin);
  console.log("Atob method:", atobResult);
  console.log("Results are equal:", isEqual);

  if (!isEqual) {
    console.log("❌ FAILED: Results do not match!");
  } else {
    console.log("✅ PASSED");
  }
});
npx hermesx test.ts
Bundling index.ts with rspack...
hermesSrcDir /private/tmp/bunx-501-hermesx@latest/node_modules/hermesx/lib
outputPath /var/folders/36/qsc87ykd71j6vtcwrcqxcpm80000gn/T/hermesx-bundle-9df5fb0a8444bd5a.js
Bundled to: /var/folders/36/qsc87ykd71j6vtcwrcqxcpm80000gn/T/hermesx-bundle-9df5fb0a8444bd5a.js
Executing with Hermes...
/var/folders/36/qsc87ykd71j6vtcwrcqxcpm80000gn/T/hermesx-bundle-9df5fb0a8444bd5a.js:233:3756: warning: the variable "SharedArrayBuffer" was not declared in function "from"
...peof SharedArrayBuffer!=='u...
        ^~~~~~~~~~~~~~~~~
=== SVG Base64 Decoding Test ===


--- Testing: blueRectangle ---
Origin method: <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
  <rect width="100" height="100" fill="blue" /></svg>
Atob method: <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
  <rect width="100" height="100" fill="blue" /></svg>
Results are equal: true
✅ PASSED

--- Testing: redCircle ---
Origin method: <svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
  <title>Circle</title>
  <circle cx="50" cy="50" r="42" style="fill:red;" />
</svg>
Atob method: <svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
  <title>Circle</title>
  <circle cx="50" cy="50" r="42" style="fill:red;" />
</svg>
Results are equal: true
✅ PASSED

--- Testing: greenTriangle ---
Origin method: <svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
  <polygon points="50,10 10,90 90,90" style="fill:green;" />
</svg>
Atob method: <svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
  <polygon points="50,10 10,90 90,90" style="fill:green;" />
</svg>
Results are equal: true
✅ PASSED

--- Testing: wavyIcon ---
Origin method: <?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg fill="#000000" width="800px" height="800px" viewBox="0 0 256 256" id="Flat" xmlns="http://www.w3.org/2000/svg">
  <path d="M36.875,74.49023a3.99582,3.99582,0,0,1,.626-5.61328A77.36856,77.36856,0,0,1,65.02979,56.11914c15.38134-3.84375,39.17675-4.78906,65.189,12.55274,18.82227,12.54785,38.5,16.42773,58.48682,11.52734a70.77906,70.77906,0,0,0,24.80175-11.32715,3.99975,3.99975,0,0,1,4.9917,6.251,77.36856,77.36856,0,0,1-27.52881,12.75781,77.24806,77.24806,0,0,1-18.71533,2.31152c-13.38574.001-29.4541-3.51758-46.47363-14.86426C106.959,62.7793,87.28076,58.89941,67.29443,63.80078A70.77906,70.77906,0,0,0,42.49268,75.12793,4.00386,4.00386,0,0,1,36.875,74.49023Zm176.63232,50.38184a70.77906,70.77906,0,0,1-24.80175,11.32715c-19.98682,4.89941-39.66455,1.02051-58.48682-11.52734-26.01221-17.34083-49.80762-16.39649-65.189-12.55274A77.36856,77.36856,0,0,0,37.501,124.877a3.99975,3.99975,0,0,0,4.9917,6.251,70.77906,70.77906,0,0,1,24.80175-11.32715c19.98633-4.90234,39.66455-1.02051,58.48682,11.52734,17.01953,11.34668,33.08789,14.86524,46.47363,14.86426A79.44972,79.44972,0,0,0,218.499,131.12305a3.99975,3.99975,0,0,0-4.9917-6.251Zm0,56a70.77906,70.77906,0,0,1-24.80175,11.32715c-19.98682,4.89941-39.66455,1.01953-58.48682-11.52734-26.01221-17.34083-49.80762-16.39649-65.189-12.55274A77.36856,77.36856,0,0,0,37.501,180.877a3.99975,3.99975,0,0,0,4.9917,6.251,70.77906,70.77906,0,0,1,24.80175-11.32715c19.98633-4.90332,39.66455-1.02051,58.48682,11.52734,17.01953,11.34668,33.08789,14.86524,46.47363,14.86426A79.44972,79.44972,0,0,0,218.499,187.12305a3.99975,3.99975,0,0,0-4.9917-6.251Z"/>
</svg>
Atob method: <?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg fill="#000000" width="800px" height="800px" viewBox="0 0 256 256" id="Flat" xmlns="http://www.w3.org/2000/svg">
  <path d="M36.875,74.49023a3.99582,3.99582,0,0,1,.626-5.61328A77.36856,77.36856,0,0,1,65.02979,56.11914c15.38134-3.84375,39.17675-4.78906,65.189,12.55274,18.82227,12.54785,38.5,16.42773,58.48682,11.52734a70.77906,70.77906,0,0,0,24.80175-11.32715,3.99975,3.99975,0,0,1,4.9917,6.251,77.36856,77.36856,0,0,1-27.52881,12.75781,77.24806,77.24806,0,0,1-18.71533,2.31152c-13.38574.001-29.4541-3.51758-46.47363-14.86426C106.959,62.7793,87.28076,58.89941,67.29443,63.80078A70.77906,70.77906,0,0,0,42.49268,75.12793,4.00386,4.00386,0,0,1,36.875,74.49023Zm176.63232,50.38184a70.77906,70.77906,0,0,1-24.80175,11.32715c-19.98682,4.89941-39.66455,1.02051-58.48682-11.52734-26.01221-17.34083-49.80762-16.39649-65.189-12.55274A77.36856,77.36856,0,0,0,37.501,124.877a3.99975,3.99975,0,0,0,4.9917,6.251,70.77906,70.77906,0,0,1,24.80175-11.32715c19.98633-4.90234,39.66455-1.02051,58.48682,11.52734,17.01953,11.34668,33.08789,14.86524,46.47363,14.86426A79.44972,79.44972,0,0,0,218.499,131.12305a3.99975,3.99975,0,0,0-4.9917-6.251Zm0,56a70.77906,70.77906,0,0,1-24.80175,11.32715c-19.98682,4.89941-39.66455,1.01953-58.48682-11.52734-26.01221-17.34083-49.80762-16.39649-65.189-12.55274A77.36856,77.36856,0,0,0,37.501,180.877a3.99975,3.99975,0,0,0,4.9917,6.251,70.77906,70.77906,0,0,1,24.80175-11.32715c19.98633-4.90332,39.66455-1.02051,58.48682,11.52734,17.01953,11.34668,33.08789,14.86524,46.47363,14.86426A79.44972,79.44972,0,0,0,218.499,187.12305a3.99975,3.99975,0,0,0-4.9917-6.251Z"/>
</svg>
Results are equal: true
✅ PASSED

Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes UI.

What's required for testing (prerequisites)?

What are the steps to reproduce (after prerequisites)?

Compatibility

OS Implemented
iOS ✅❌
MacOS ✅❌
Android ✅❌
Web ✅❌

Checklist

  • I have tested this on a device and a simulator
  • I added documentation in README.md
  • I updated the typed files (typescript)
  • I added a test for the API in the __tests__ folder

- Remove Buffer dependency to avoid polyfill issues
- Use atob() and TextDecoder for base64 decoding
- Improve React Native compatibility
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.

Missing buffer dependency

1 participant