Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/smooth-mice-divide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@lit-labs/ssr-client': patch
---

Add a digest cache to reduce the overhead of rendering the same template multiple times
16 changes: 15 additions & 1 deletion packages/labs/ssr-client/src/lib/hydrate-lit-html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,10 @@ const createAttributeParts = (

// Number of 32 bit elements to use to create template digests
const digestSize = 2;

// Digest cache
const digestCache = new WeakMap<TemplateStringsArray, string>();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make sure that we're not exacerbating the static template memory leak with this...

I think we're not because once the static template cache frees a template, the forged TemplateStringsArray will be able to be freed and this cache will release the entry.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you're correct based on my understanding of how WeakMaps work in JS

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once an object used as a key has been collected, its corresponding values in any WeakMap become candidates for garbage collection as well — as long as they aren't strongly referred to elsewhere.
-MDN

So as long as the template is only associated with WeakMaps (or I'm assuming other "weak" data structures), we should be good.


// We need to specify a digest to use across rendering environments. This is a
// simple digest build from a DJB2-ish hash modified from:
// https://github.com/darkskyapp/string-hash/blob/master/index.js
Expand All @@ -461,6 +465,11 @@ const digestSize = 2;
// - Easily specifiable and implementable in multiple languages.
// We don't care about cryptographic suitability.
export const digestForTemplateResult = (templateResult: TemplateResult) => {
let digest = digestCache.get(templateResult.strings);
if (digest !== undefined) {
return digest;
}

const hashes = new Uint32Array(digestSize).fill(5381);

for (const s of templateResult.strings) {
Expand All @@ -469,6 +478,7 @@ export const digestForTemplateResult = (templateResult: TemplateResult) => {
}
}
const str = String.fromCharCode(...new Uint8Array(hashes.buffer));

// Use `btoa` in browsers because it is supported universally.
//
// In Node, we are sometimes executing in an isolated VM context, which means
Expand All @@ -478,5 +488,9 @@ export const digestForTemplateResult = (templateResult: TemplateResult) => {
// for `btoa` when they set up their VM context, we instead inject an import
// for `Buffer` from Node's built-in `buffer` module in our Rollup config (see
// note at the top of this file), and use that.
return NODE_MODE ? Buffer.from(str, 'binary').toString('base64') : btoa(str);
digest = NODE_MODE
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw, we should start using btoa in Node soon...

? Buffer.from(str, 'binary').toString('base64')
: btoa(str);
digestCache.set(templateResult.strings, digest);
return digest;
};
Loading