-
-
Notifications
You must be signed in to change notification settings - Fork 6.4k
feat(shiki): use wasm engine #7896
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
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
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.
Pull Request Overview
This PR introduces a new approach to syntax highlighting by using a WASM-based engine on the server and a JavaScript-based engine on the web, optimizing for speed and bundle size.
- Minimal web highlighter now explicitly uses the JavaScript regex engine.
- Server highlighter is updated to initialize and use the WASM Oniguruma engine with top-level await.
- ESLint configuration is updated to support top-level await by using the latest ECMAScript version.
Reviewed Changes
Copilot reviewed 5 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
File | Description |
---|---|
packages/rehype-shiki/src/minimal.mjs | Added explicit engine selection for the minimal (web) highlighter |
packages/rehype-shiki/src/index.mjs | Integrated asynchronous WASM engine initialization for the server side |
packages/rehype-shiki/src/highlighter.mjs | Removed the default engine creation to allow external engine injection |
packages/rehype-shiki/package.json | Added dependency for the WASM Oniguruma engine |
packages/rehype-shiki/eslint.config.js | Updated ECMAScript version to support top-level await |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (1)
packages/rehype-shiki/src/highlighter.mjs:17
- Since the default engine creation was removed, it may be helpful to document that an engine must now be provided via options when calling createHighlighter.
const shiki = createHighlighterCoreSync({
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.
That's super !
@dario-piotrowicz https://github.com/nodejs/nodejs.org/actions/runs/15880572422/job/44779523238?pr=7896 Does OpenNext support WASM? |
sorry, not sure... this code comment suggests that it should work... I'll check with @vicb tomorrow, but I guess that we might be hitting some open-next bug here 🤔 |
It looks like the code is trying to create the module from a ![]() That is not supported on Workers - they need the wasm to be loaded from a |
Can we store the Uint8Array as a file? The contents of it, or is there some way we can convert this to a wasm file. My understanding is we can pass the wasm instance to Shiki and we don't need to import this module.... |
It should be a |
Looking at the code it looks like the wasm file is in vscode-oniguruma - shiki uses v1.7.0 |
@vicb is there any way OpenNext can support loading WASM files via
Shiki supplies custom imports ( Hypothetically, we might be able to do some custom import resolving, but that's a lot of boilerplate. We could also conditionally use the JavaScript engine in OpenNext, and the WASM one otherwise? Does OpenNext have any specific environment variable we can use to identify when it's in use? |
Codecov ReportAttention: Patch coverage is
✅ All tests successful. No failed tests found.
Additional details and impacted files@@ Coverage Diff @@
## main #7896 +/- ##
==========================================
- Coverage 75.45% 75.31% -0.14%
==========================================
Files 101 101
Lines 8311 8326 +15
Branches 218 218
==========================================
Hits 6271 6271
- Misses 2038 2053 +15
Partials 2 2 ☔ View full report in Codecov by Sentry. |
764df8c
to
58f7092
Compare
Ah, I see cloudflare/cloudflare-docs#13469 documents that this is not allowed. Is there a way to enable it on our end, knowing the security concerns? If not, I think the conditional JS Engine is the way to go. |
Yes you can
The security concerns are for Cloudflare too - that's why there is no way to instantiate from a buffer. |
Thank you for all your help! I'll investigate this! |
I pointed to the .wasm file to use in an earlier comment |
In case there isn't a viable solution (which, hopefully, it seems there is), is there a way to tell when our code in running in Cloudflare, versus everything else, so we can go with the conditional JS engine? |
You can use |
ac64564
to
50379dd
Compare
Thank you again for your help! We will, unfortunately, need to conditionally use the JavaScript RegExp engine when we are on Cloudflare Workers. If we were to import the WASM file like: // Also available at "vscode-oniguruma/release/onig.wasm"
import wasm from "shiki/onig.wasm";
await import("shiki/onig.wasm"); It would result in errors like, since the imports need to be defined before we import the WASM file:
|
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.
LGTM!
Lighthouse Results
|
Using the WASM shiki on the server, and the JavaScript shiki on the client, should result in the best mix of speed and size for our use-case.
See nodejs/api-docs-tooling#320.
Rouhgly a 50% speed improvement on the server, per my testing.