Skip to content
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

Loading apps from esm.sh is very slow #46

Open
karimsa opened this issue Mar 1, 2023 · 3 comments
Open

Loading apps from esm.sh is very slow #46

karimsa opened this issue Mar 1, 2023 · 3 comments

Comments

@karimsa
Copy link
Member

karimsa commented Mar 1, 2023

Looks like esm.sh does not use edge caching, but rather relies on client-side caching. Not doing so is really slowing down app loads from esm.sh.

For example: my-ext in the example project builds in 200ms, but when it imports a sass file (and therefore the sass library from esm.sh), it takes about 4s.

karimsa added a commit that referenced this issue Mar 3, 2023
This implements an HTTP client that will (mostly) respect
`Cache-Control` headers.

Architecture of the cache:

 * Cache is persisted to discuss in a JSON file
* Deserialization does not seem to cause noticeable delay on startup
(tested with ~6MB cache)
* Serialization blocks esbuild (cache saving is done at the end of the
esbuild pipeline), but the overall perf was unaffected even when this
was done concurrently/skipped
* Cache contains byte size, and a hashmap of URLs -> entries. Entries
store a deadline (or nil for immutable), contents as string (esbuild
takes a string pointer rather than a byte slice, so it was faster to
just store as a string), and an int64ptr that holds the time of last
use.
* Retrieving a value from the cache causes the time of last use to be
atomically updated (not fully atomic, since we generate and then write,
but worst case, this causes a few nanosecs diff)
 * On retrieve, we delete the entry if it has passed its TTL
* On save/flush, the cache performs a 'compaction' cycle, where it
evicts all expired data and then finally deletes from the least recently
used items until the cache reaches the desired size. It then flushes the
cache to disk.

---

It significantly helps with #46, though does not fix it completely.

 * On main, cold loading `@robinplatform/app-example` takes around 22s.
   * 16.5s to render `base.html`
* On httpcache, cold loading `@robinplatform/app-example` takes around
0.3s.
   * 150ms to render `base.html`
* On either, cold loading `@robinplatform/app-example` from disk takes
around 0.14s. (how on earth is this a different order of
magnitude.........)
   * 70ms to render `base.html`

---------

Co-authored-by: Albert Liu <[email protected]>
@ije
Copy link

ije commented Mar 16, 2023

For example: my-ext in the example project builds in 200ms, but when it imports a sass file (and therefore the sass library from esm.sh), it takes about 4s.
esm.sh does use edge cache actually. can you please share the link i can check? thanks

@karimsa
Copy link
Member Author

karimsa commented Mar 17, 2023

Hey, @ije! Thanks for the comment.

The specific issue we are facing is for invalid files / loading TS. When loading TS/TSX off your CDN, they don't seem to get transpiled, so all the imports are still relative. To get around this, we implement our own node resolution algorithm to resolve the imports. However, esm.sh specifically asks for 404s (or I guess it is throwing a 500 for some reason) to not be cached, even for immutable URLs:

$ curl -iL --head https://esm.sh/react/foobar

HTTP/2 302 
date: Fri, 17 Mar 2023 07:08:47 GMT
location: https://esm.sh/[email protected]/foobar
access-control-allow-origin: *
cache-control: public, max-age=600
vary: Origin
report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=TC4ngQH2qpYQ5d9KcUcwJS7316cU6PlowNjeSzjCtRr0i8tXvKWWhVGSQs0E5YhtoTRBoZujlWdoSd7a%2FWydPfPRoapSnoFiwt%2B5jQII5TYgrpsP5%2FjBfR%2F0abjBIka1fvdQLJU%3D"}],"group":"cf-nel","max_age":604800}
nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
server: cloudflare
cf-ray: 7a93681a9d18a20e-YYZ
alt-svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400

HTTP/2 500 
date: Fri, 17 Mar 2023 07:08:47 GMT
content-type: application/javascript; charset=utf-8
content-length: 354
cf-ray: 7a93681b6e9ca20e-YYZ
cache-control: private, no-store, no-cache, must-revalidate
vary: Origin
cf-cache-status: DYNAMIC
report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=DByGZb3Ip9GBwII9SKv2q8k8kElYBETtcrzjZ9ZanURLyqHZfMpfGEbsOAZ6smT49DCyEZrmOzOuNtcjBgKhVSONomayRNzH8TvBbFkqCCgWjWQacmQNQbKX8ZgKxy9zX9oFOy4%3D"}],"group":"cf-nel","max_age":604800}
nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
server: cloudflare
alt-svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400

From my understanding, this should be safe to cache at the edge since react v18.0.2 did not have a file called 'foobar', and package releases are immutable.

Of course native transpilation of TS & TSX from esm.sh would also fix this - but I understand that JSX might be out of scope for your project.

@ije
Copy link

ije commented Mar 17, 2023

I see. there is a plan to add support for ts/jsx transpiler

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants