-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve browser compatibility for Buffer usage #29
Conversation
@pabigot this is ready for review, thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, this isn't quite what I thought. Rather than replace the entry API use of Buffer
with Uint8Array
, it replaces the Node.js Buffer
with a reimplementation.
I see this as being useful for browser applications, but a step backwards for Node.js applications. The performance comparison suggests BrowserBuffer can be up to 4x slower than native Node.js (new, slice, and wrie operations particularly seem affected).
Can you come up with a solution that continues to use the native Buffer implementation in Node.js environments, but adds the external implementation only in browser environments?
If not, can you explain exactly why people who use this in Node.js won't be upset at the new unnecessary dependency and potential conflict of having multiple Buffer
implementations in their applications?
If not, then does it make more sense for you to fork this project and publish your changes as browser-buffer-layout
? That'd also simplify ongoing maintenance here, as the only changes I've had to make in the last three years are to support an environment that wasn't a target for the original solution.
lib/Layout.js
Outdated
@@ -2354,9 +2354,11 @@ class Blob extends Layout { | |||
if ((offset + span) > b.length) { | |||
throw new RangeError('encoding overruns Uint8Array'); | |||
} | |||
uint8ArrayToBuffer(b).write(src.toString('hex'), offset, span, 'hex'); | |||
const buffer = uint8ArrayToBuffer(b); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the earlier commit you use:
b = uint8ArrayToBuffer(b);
I'd rather see consistency so please change this to match. Also srcBuffer
should just change the variable src
.
Also: why is this necessary? The test seems to pass at the commit before this; if this is necessary there should be a new test case that fails without this change to demonstrate what's going on.
Depending on what motivated this change, it might be squashed into the one that changes all the other uses, so there bisecting wouldn't hit a commit that has a bug that resulted from the change in underlying implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Motivation of this change is that if the API supports Uint8Array
params, we need to polyfill the Buffer.write
method which doesn't exist on Uint8Array
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a new test case that fails without the conversion for b
and src
d2ad9d0
to
7cf00df
Compare
lib/Layout.js
Outdated
// Node v4 doesn't respect byteOffset and length arguments | ||
if (buffer.length > b.length) { | ||
buffer = buffer.slice(b.byteOffset, b.byteOffset + b.length); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without bumping the min node version, we need a little polyfill to account for the fact that node v4 doesn't have support for the byteOffset
and length
arguments to the Buffer
constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As noted in the review summary, I'm going to remove v4 support so you won't need this.
38f417e
to
6fb0246
Compare
@pabigot I've taken your feedback into account and this PR is now ready for another pass, thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is getting close, thanks.
Overall I feel your change warrants a minor release update to 1.3.0. Because of that, I've also updated various things related to packages and integrations that hadn't been touched in the last three years. Those are now in the pu branch, which is queued to merge to the next branch. Please take a look at #31, and comment on whether you have concerns. After you've taken a look, or by the middle of next week, I'll merge that to the next branch.
Once those changes are in next I'd like you to retarget your PR to next
instead of main. Since #31 removes the support for Node 4 and provides a rationale for doing so, one of your polyfills won't be needed anymore. Also I'd like you to remove release-related changes from your PR: the version number in package.json, and the description in CHANGELOG.md. I'll handle those when I do the new release. There will be one trivial conflict to resolve in lib/Layout.js
when you rebase.
Also, please update all commit messages to the format:
tag: short description
details of change...
Signed-off-by: yourname
The sentence/paragraph(s) in the body should describe the change and explain why it's being made, so somebody looking at changes in a commit can understand what they were intended to do. For example for 4cd65bf it should be something like:
Layout: Select Buffer implementation based on environment
Use the presence of a variable defined in browser environments to
select whether the Buffer implementation is built in to the
environment or needs to be retrieved from a (potentially external)
module. This allows use of the package in Node.js, pure
ECMAScript, and browser environments.
Signed-off-by: Justin Starry <justin@solana.com>
ffb8f3a should explain why Uint8Array
is preferred over Buffer, using text from #28. And so on.
A good summary of the policy I've used is here or here. The commits in #31 can also serve as an example.
test/LayoutTest.js
Outdated
@@ -1761,6 +1761,24 @@ suite('Layout', function() { | |||
assert.equal(bl.span, 3); | |||
assert.equal(bl.property, 'bl'); | |||
}); | |||
test('uint8array', function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Name this one basics
, since the effect of this patch series is to change the base packed data representation from Buffer
to Uint8Array
. Then rename the old basics
to Buffer
to prove Buffer arguments still work.
lib/Layout.js
Outdated
// Node v4 doesn't respect byteOffset and length arguments | ||
if (buffer.length > b.length) { | ||
buffer = buffer.slice(b.byteOffset, b.byteOffset + b.length); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As noted in the review summary, I'm going to remove v4 support so you won't need this.
@pabigot I've prepped this branch so that it should be ready for merge once |
20cef21
to
02e4a75
Compare
Use the presence of a variable defined in browser environments to select whether the Buffer implementation is built in to the environment or needs to be retrieved from a (potentially external) module. This allows use of the package in Node.js, pure ECMAScript, and browser environments. Signed-off-by: Justin Starry <justin@solana.com>
Loosen Buffer type checks to accept the Uint8Array base class. Uint8Array is preferred over Buffer due to its presence in both Node.js and browser environments. When Buffer methods are needed, create a new Buffer instance which uses the same underyling memory of the Uint8Array parameter. Signed-off-by: Justin Starry <justin@solana.com>
/* istanbul ignore if */ | ||
if ('undefined' !== typeof window && 'undefined' !== typeof window.Buffer) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ignored here, let me know if you disagree with taking this route
This looks fine. Please confirm that this branch works as intended in a browser environment, since there's currently nothing in place to confirm that. |
Great, it shouldn't be too bad to add a test for that with mocha. I added an issue to track adding browser test coverage: #32 |
Thanks again @pabigot, feel free to merge at your leisure, I don't have permission. |
This is a big change; I don't want to publish a version that claims to work in a browser without confirmation it works in that environment. Can you install it in the environment you need it in and confirm that this specific code (not just your original version) works there? I agree automated testing is highly desirable, but I don't even know how to do it manually. |
Sure thing, I have two branches here: https://github.com/jstarry/buffer-layout-test/branches. The |
buffer-layout has a couple of browser-specific improvements in pabigot/buffer-layout#29 and pabigot/buffer-layout#27 that this update pulls in
Fixes: #28
Changes
buffer
module so that bundlers can polyfill it for browser apps but use the globalBuffer
if available.Buffer.isBuffer
toinstanceof Uint8Array
to improve API for browser apps