This isn't a Mojo::JSON problem, nor a Math::BigInt or Math::BigFloat problem. And it won't be a JavaScript problem either. It is a problem of what happens when a floating point number is represented internally in binary format, regardless of the language.
Any JSON library on any platform is going to see {"int":5e22} as a floating point number (because 5e22 exceeds the size of any common platform's native integers). Most platforms will treat that internally as a double. The internal representation of 5e22 is inherently non-terminating. You and I see 1/3rd, and intuitively know that it is represented in decimal format as 0.33333333333......... (a non-terminating sequence). We have no problem making the mental leap that 33 cents is about 1/3rd of a dollar, even though we know in the back of our minds from elementary school that it's not exactly 1/3rd of 1.
Well, in the world of binary-representations of floating point numbers, any number that cannot be represented by m/(2^m) forms a non-terminating binary sequence, and as such, cannot be represented precisely with a finite number of bits. This is the case in any language that stores floating point numbers in an internal binary format.
So when you send {"int":5e22} to your JavaScript (or to Python, or even back to Perl), the receiving end will translate that to an internal representation of the floating point number 5e22. The internal binary representation, being non-terminating, is imprecise, and would be converted back to base-10 as 4.999e+22.
Presumably you've been using Math::BigInt and Math::BigFloat because precision is of some importance in what you're working on. When you serialize it to a plain-old-datatype, you are losing that precision, and the receiving party has no choice but to accept that loss.
If you serialize to a string, the receiving party still has an opportunity to preserve precision by converting the string to that language's concept of a BigInt or BigFloat.
In the general case, stringification is the better solution, and it might be so in your case as well; you will just have to deal with converting the string losslessly at the receiving end, if that's important to you.