From 197454b6056d264f18e50290ed29f2318a95d6e2 Mon Sep 17 00:00:00 2001 From: David First Date: Fri, 9 Oct 2026 10:41:51 -0400 Subject: [PATCH 1/2] perf(objects): copy small Source contents out of the shared inflate buffer --- scopes/scope/objects/models/source.spec.ts | 14 ++++++++++++++ scopes/scope/objects/models/source.ts | 3 +++ 2 files changed, 17 insertions(+) create mode 100644 scopes/scope/objects/models/source.spec.ts diff --git a/scopes/scope/objects/models/source.spec.ts b/scopes/scope/objects/models/source.spec.ts new file mode 100644 index 000000000000..2670df1c862e --- /dev/null +++ b/scopes/scope/objects/models/source.spec.ts @@ -0,0 +1,14 @@ +import { expect } from 'chai'; +import { deflateSync } from 'zlib'; +import { BitObject } from '../objects'; +import Source from './source'; + +describe('Source', () => { + it('should not keep the whole inflated buffer when the file is small', async () => { + const file = Source.from(Buffer.from('const a = 1;')); + const parsed = (await BitObject.parseObject(deflateSync(file.serialize()))) as Source; + expect(parsed.contents.toString()).to.equal('const a = 1;'); + expect(parsed.hash().toString()).to.equal(file.hash().toString()); + expect(parsed.contents.buffer.byteLength).to.be.below(16 * 1024); + }); +}); diff --git a/scopes/scope/objects/models/source.ts b/scopes/scope/objects/models/source.ts index 4f14025f9c15..3d7440ed92db 100644 --- a/scopes/scope/objects/models/source.ts +++ b/scopes/scope/objects/models/source.ts @@ -22,6 +22,9 @@ export default class Source extends BitObject { } static parse(contents: Buffer): Source { + // zlib returns an inflated object smaller than 16KB as a slice of a 16KB buffer. a Source is often kept for long + // (e.g. as a component file), so it gets its own copy. otherwise, every small file holds 16KB. + if (contents.byteLength < contents.buffer.byteLength / 2) contents = Buffer.from(contents); return new Source(contents); } From 96b49c77d70675c3e79a0e1f032d2ecb043368c4 Mon Sep 17 00:00:00 2001 From: David First Date: Fri, 9 Oct 2026 11:12:27 -0400 Subject: [PATCH 2/2] refactor(objects): clarify why Source copies small contents --- scopes/scope/objects/models/source.spec.ts | 1 - scopes/scope/objects/models/source.ts | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/scopes/scope/objects/models/source.spec.ts b/scopes/scope/objects/models/source.spec.ts index 2670df1c862e..0c05b269b3ba 100644 --- a/scopes/scope/objects/models/source.spec.ts +++ b/scopes/scope/objects/models/source.spec.ts @@ -8,7 +8,6 @@ describe('Source', () => { const file = Source.from(Buffer.from('const a = 1;')); const parsed = (await BitObject.parseObject(deflateSync(file.serialize()))) as Source; expect(parsed.contents.toString()).to.equal('const a = 1;'); - expect(parsed.hash().toString()).to.equal(file.hash().toString()); expect(parsed.contents.buffer.byteLength).to.be.below(16 * 1024); }); }); diff --git a/scopes/scope/objects/models/source.ts b/scopes/scope/objects/models/source.ts index 3d7440ed92db..5fbac96caf21 100644 --- a/scopes/scope/objects/models/source.ts +++ b/scopes/scope/objects/models/source.ts @@ -22,8 +22,8 @@ export default class Source extends BitObject { } static parse(contents: Buffer): Source { - // zlib returns an inflated object smaller than 16KB as a slice of a 16KB buffer. a Source is often kept for long - // (e.g. as a component file), so it gets its own copy. otherwise, every small file holds 16KB. + // zlib returns small results as a slice of a bigger (16KB) buffer. unlike other objects, which are parsed and dropped, + // a Source keeps these bytes, often for long (e.g. as a component file), so it copies them instead of pinning 16KB. if (contents.byteLength < contents.buffer.byteLength / 2) contents = Buffer.from(contents); return new Source(contents); }