-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Lazy loaded shiki languages during syntax highlighting #10618
Conversation
🦋 Changeset detectedLatest commit: aaddd40 The changes in this PR will be included in the next version bump. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
making this a draft for now as its possible we can't have these nice things unless rehype lets us do async 👀 edit: false alarm, looks like it is happy |
Thanks! All these changes make sense to me. About shiki lazy load, we actually used to do the same but I removed it because I thought shikiji/shiki 1.0 already did that by default, but in hindsight it probably didn't because its highlighter functions are all sync anyways (which you pointed out). About your message on Discord on version bumps, this will require a major for Would you be able to add a major changeset for |
have fixed the broken test FYI it was working because of this it seems: astro/packages/astro/src/runtime/server/escape.ts Lines 99 to 103 in 0be26d8
i suppose edit: yeah of course, we await the child in |
This moves the static image helper outside of the build hooks such that the scope is no longer captured. Since the static image helper exists on `window`, none of the function's scope will be garbage collected at any point. Part of said scope is `resolvedConfig`, which holds package caches, plugins, etc. These will also be retained. By moving the function into a factory, we no longer hold a reference to `resolvedConfig`, leading to lower memory usage.
This discards the SSR plugin context once a build has finished, so we're no longer holding it in memory and it can be garbage collected.
This discards the markdown processor once a build ends, allowing it to be garbage collected.
When highlighting code via shiki, we default to enabling all available languages. This results in shiki internally loading each individual language module, evaluating it, and keeping hold of it in memory. Instead, we should be able to load the bare minimum and (try) lazily load any missing languages later on. By doing this, we're not unnecessarily loading up dozens of large modules and will only load what the user consumes. Since traversal of the AST via unist is synchronous, we first do the traversal to find the nodes and later asynchronously _process_ the nodes (i.e. execute the highlighter and mutate the AST).
This adds a test for ensuring highlighting happens when using a lazily loaded language (typescript in this case).
Aligning the prism plugin with the shiki plugin - exporting an async visitor since the code block highlighter now returns a promise.
Markdoc actually supports async transforms already. Now that the shiki highlighting is async, we also need to make our transform async. Do note that typescript will be unhappy until markdoc/markdoc#495 is resolved.
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.
Thanks!
Changes
There's a few changes in this PR, each contributing to memory usage improvement. Bundled into one PR since all but one are close to one-liners.
['plaintext']
rather than all languages, leading to all others being lazily loaded by defaultglobalThis
, we were holding deep references to large objects beforeMemory benchmark
Before:
After:
I did a few runs and got roughly these results each time.
Testing
Docs
We may need to update docs on the fact that the default shiki languages are now
['plaintext']
, although it shouldn't make much difference to a user since the rest will be lazily loaded anyway if they use them.For reviewers
Each commit describes its own change, so it may be worth reading the commit messages and/or the diff of the individual commit if you want to understand better.