fix: fix error with <Prism /> component in Cloudflare Workers#15723
Conversation
🦋 Changeset detectedLatest commit: 1e1d716 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 |
|
🤔 |
This comment was marked as outdated.
This comment was marked as outdated.
|
@rururux if the code that we're attempting to load is CJS, we should use |
|
Thank you for the suggestion! I tried the approach you proposed, and while it does improve stability, 20:07:54 [WARN] [vite] Failed to resolve dependency: @astrojs/prism > prismjs, present in ssr 'optimizeDeps.include'
20:07:54 [WARN] [vite] Failed to resolve dependency: @astrojs/prism > prismjs/components.js, present in ssr 'optimizeDeps.include'
20:07:54 [WARN] [vite] Failed to resolve dependency: @astrojs/prism > prismjs/dependencies.js, present in ssr 'optimizeDeps.include' |
|
Also, I just noticed there's actually an issue with the implementation in this PR, edit: done |
|
I added a simple detection logic to the Cloudflare Workers integration's Vite plugin that checks whether One limitation to note: since the check works by reading the If you'd prefer, I can update the Cloudflare integration's test fixtures to install |
ematipico
left a comment
There was a problem hiding this comment.
I need to wrap my head with the new code. There are weird things
|
I've switched to an approach that uses a virtual module to load Prism language files, but only in the Cloudflare Workers environment. |
# Conflicts: # packages/integrations/cloudflare/test/astro-dev-platform.test.ts
| }, | ||
| "imports": { | ||
| "#prism-loadLanguages": { | ||
| "workerd": "./dist/loadLanguages-workerd.js", |
There was a problem hiding this comment.
how does this work? What causes this to be loaded?
There was a problem hiding this comment.
This is due to this feature.
In PR #15565 as well, a similar approach was taken to address an issue that only occurs in the workerd environment.
https://developers.cloudflare.com/workers/wrangler/bundling/#conditional-exports
Wrangler respects the conditional exports field ↗ in package.json. This allows developers to implement isomorphic libraries that have different implementations depending on the JavaScript runtime they are running in. When bundling, Wrangler will try to load the workerd key ↗. Refer to the Wrangler repository for an example isomorphic package ↗.
|
Creating a preview release to test with. |
astro
@astrojs/prism
@astrojs/cloudflare
@astrojs/markdoc
@astrojs/markdown-remark
commit: |
| // Since Prism language files are written assuming the Prism instance is defined | ||
| // as a global variable, we will temporarily set the Prism instance globally. | ||
| function setPrismAsGlobal() { | ||
| globalThis.Prism = Prism; | ||
|
|
||
| return () => { | ||
| // @ts-expect-error globalThis type | ||
| delete globalThis.Prism; | ||
| }; | ||
| } |
There was a problem hiding this comment.
I tested this with the preview build and it mostly works fine.
https://github.com/rururux/astro-cf-prism-preview
https://dc96c388-prism-test.rururux.workers.dev/
But I occasionally encountered the error [ERROR] [vite] ReferenceError: Prism is not defined.
I believe the cause is that after globalThis.Prism is deleted in this cleanup section, something tries to read the value. However, removing the cleanup means the Prism object ends up persisting on globalThis indefinitely.
I also tried verifying the behavior with the node adapter, I read globalThis.Prism inside an Astro component that uses the <Prism /> component, and it was not undefined, confirming that the Prism object is being set on globalThis.
I have two proposals in mind:
-
Match the behavior of the node adapter and leave the Prism object set on
globalThis.Prism- Pros: Consistent behavior with the node adapter regarding whether a value is set on
globalThis.Prism - Cons:
globalThisremains polluted
- Pros: Consistent behavior with the node adapter regarding whether a value is set on
-
Track the number of invocations or similar, and ensure the Prism object is properly cleaned up from
globalThis.Prism- Pros: Avoids polluting
globalThis - Cons: Inconsistent behavior with the node adapter regarding whether a value is set on
globalThis.Prism
- Pros: Avoids polluting
For now, I'd like to go with option 2, prioritizing keeping globalThis clean.
If you think option 1 would be better, please let me know and I'll update accordingly.
# Conflicts: # packages/astro-prism/tsconfig.json
|
Thanks everyone for the reviews and approvals! |
fixes: #15722
Changes
loadLanguagesfrom prismjs, rewrote them as ESM, and configured them to be loaded in Cloudflare Workers environments.runHighlighterWithAstrofunction to an async function.runHighlighterWithAstroto also handle it as an async function.Fixes a CommonJS-related error that occurred when using the Cloudflare Workers integration with the
<Prism />component in the latest beta of Astro.The root cause was that the
loadLanguagesfunction exported from prismjs usedrequire()andrequire.resolve()internally.To work around this, i ported
loadLanguagesand its dependencies from the prismjs repository, rewrote them as ESM, and configured them to be loaded only in Cloudflare Workers environments.Initially, i considered simply adding
'prismjs/components/index.js'tooptimizeDeps.includein@astrojs/cloudflare, but this approach was abandoned because whilerequire()was replaced,require.resolve()remained as-is and still caused an error.In the original Prism code, language data files were loaded dynamically like this:
Since this couldn't be directly reproduced in ESM (the import path needs to be statically known at build time), I took the following approach instead:
nodeenvironment and theworkerdenvironment. In thenodeenvironment, things work the same way as before.workerdenvironment, a special objectbundledLanguagesis imported from'virtual:astro-cloudflare:prism', and each required language file is loaded from there.'virtual:astro-cloudflare:prism'is dynamically generated by a Vite plugin calledcfPrismPlugin, which is added in this pull request.bundledLanguageslooks something like this. This ensures that the import paths are statically known at the time the language data files are loaded:workerdenvironment, it also means a large number of dynamic import statements are generated, which caused lengthy logs to appear when they were loaded. This PR also addresses that logging issue.Reference
loadLanguages: https://github.com/PrismJS/prism/blob/76dde18a575831c91491895193f56081ac08b0c5/components/index.jsTesting
Added a test to verify that the component works without errors in a workerd environment.
Docs
N/A, bug fix