Advertisement · 728 × 90

Posts by K.

Hahahaha, taint

1 year ago 2 0 0 0

I should really learn what durable objects are and why everyone likes them so much, will definitely check it out if you post it on here!

1 year ago 1 0 1 0

Wow just tried Tanstack table for the first time, the API is really clean!

1 year ago 1 0 0 0
This game existing is a Miracle
This game existing is a Miracle YouTube video by Mojomoud

Oi! New video is up, it's on a game that for all intents and purposes should exist, but does. And that's kind of rad. The game itself is pretty good too.

I'm talking about S.T.A.L.K.E.R. 2, by the way youtu.be/WjkFrF0VSho?...

1 year ago 1 1 0 0

Awesome!

1 year ago 0 0 0 0

Woke up looking for the broccoli

Mr get off dropppppeeeddddddd

1 year ago 0 0 0 0

Tested this from the cottage this weekend on spotty, slow internet and works well!

When I pick this up again I'm going to learn about CDNs and how they are so fast, and how to host my own for my toy rom manager app

1 year ago 0 0 0 0
Advertisement

Okay, so caching going kinda smoothly! Stats:
-server cache hits are ~90ms (this is also true of client cache misses hitting a server cache)
-client cache hits send no network request
-server cache misses are a bit expensive at ~600ms but my app uses no CDNs for images and sends base64 string 🤫

1 year ago 0 0 1 0

Oh! Also any custom or opinionated linting rules you like!

Thanks sensei

1 year ago 1 0 0 0

Naming recommendations (files, functions, variables), alignment, fn defs (const vs function), type X = SomeType vs Interfaces, how many components per file (after reading full stack components, this seems obvious but I think would be good to get into), any opinionated lint rules and why

1 year ago 2 0 1 0

Eyyyy its fuckin bobbo

1 year ago 0 0 0 0
superwhisper AI powered voice to text for macOS

superwhisper.com is pretty great

1 year ago 1 0 0 0

Getting older is realizing useState was just an escape hatch all along

1 year ago 0 0 0 0

I think I may be allowed to use remix at work for a new project, yessssssssssss

1 year ago 0 0 0 0

This series is so good, I think I'll do the same!

1 year ago 0 0 0 0
Post image
1 year ago 2 0 0 0
Post image

Version I have now (with no stale-while-revalidate functionality)

1 year ago 0 0 1 0
Advertisement
Post image

I think this could be simplified a ton by allowing developers to modify the request that is made to your server with `serverLoader()` in the `clientLoader`. The browser could handle ETag validation!

1 year ago 1 0 1 0
Code sample illustrating a potential client side cache implementation in Remix. Code to follow:

export async function withClientCache<T, S extends StoreKey>({
  store,
  cacheKey,
  ttl,
  serverLoader,
  request,
  params,
}: WithClientCacheOptions<T, S>) {
  try {
    let key = typeof cacheKey === "function" ? cacheKey(params) : cacheKey;
    let cached = await cacheManager[store].get(key);

    if (cached) {
      let age = Date.now() - cached.timestamp;
      let isExpired = age >= ttl;

      if (!isExpired) return cached.data;

      if (cached.eTag) {
        let versionCheck = await fetch(request.url, {
          method: "HEAD",
          headers: {
            "If-None-Match": cached.eTag,
          },
        });

        if (versionCheck.status === 304) {
          await cacheManager[store].set(key, {
            data: { ...cached } as any,
            timestamp: Date.now(),
            eTag: cached.eTag,
          });
          return cached.data;
        }
      }
    }

    let freshData = await serverLoader();

    await cacheManager[store].set(key, {
      data: { ...freshData },
      timestamp: Date.now(),
      eTag: freshData.eTag,
    });

    return freshData;
  } catch (error) {
    console.error("Cache error:", error);
    return serverLoader();
  }
}

Code sample illustrating a potential client side cache implementation in Remix. Code to follow: export async function withClientCache<T, S extends StoreKey>({ store, cacheKey, ttl, serverLoader, request, params, }: WithClientCacheOptions<T, S>) { try { let key = typeof cacheKey === "function" ? cacheKey(params) : cacheKey; let cached = await cacheManager[store].get(key); if (cached) { let age = Date.now() - cached.timestamp; let isExpired = age >= ttl; if (!isExpired) return cached.data; if (cached.eTag) { let versionCheck = await fetch(request.url, { method: "HEAD", headers: { "If-None-Match": cached.eTag, }, }); if (versionCheck.status === 304) { await cacheManager[store].set(key, { data: { ...cached } as any, timestamp: Date.now(), eTag: cached.eTag, }); return cached.data; } } } let freshData = await serverLoader(); await cacheManager[store].set(key, { data: { ...freshData }, timestamp: Date.now(), eTag: freshData.eTag, }); return freshData; } catch (error) { console.error("Cache error:", error); return serverLoader(); } }

client cache:

1 year ago 0 0 0 0

Protip: add a `DEPLOY_SECRET` or something to eTag generation or waste time wondering why deploys mess up the cache 😅

1 year ago 0 0 1 0

Where I've landed: the server cache is longer lived and invalidated on mutation, the client cache is 25% of the server cache and on expiry it sends a HEAD request to check the eTag, if it is different, await the server's full response

1 year ago 0 0 1 0

I think I've been overthinking caching, and should just go with something and measure the impact of the cache before optimizing everything. A 90ms (on my not-so-good internet connection to my server) round trip is good, but most requests not leaving the browser makes this feel so good

1 year ago 0 0 1 0

client loaders also strip headers, which I guess I get, but getting the eTag would have been awesome :(

1 year ago 0 0 0 0

Nice! I really like the pattern of abusing the URL for app state so I'm excited to give this a try

1 year ago 1 0 0 0

Current caching dilemma:

Implementing a HEAD request to check an ETag on the server in a Remix client Loader adds a 90ms round trip to navigation. When just relying on a TTL, you only paid the network cost once.

I wonder where the line is, no one told me this was just tradeoffs all the way down 😭

1 year ago 0 0 1 0

I think I'd like it more with one level of configuration, at first glance

searchTerm: {
urlKey: 'q',
parse: parseAsString,
default: ''
}

1 year ago 0 0 1 0
x.com

Read about it here:

x.com/samselikoff/...

1 year ago 0 0 0 0
Advertisement
HTML Standard

TIL about input.validity and input.setCustomValidity(), I wonder if I could use this as strong defaults wrt to assistive technologies over aria-described-by. AI is a little too wishy-washy with its answers to say if it's a good idea or not

html.spec.whatwg.org/multipage/fo...

(back to caching)

1 year ago 0 0 1 0

I find its also really good at giving you primers on topics you may not have encountered yet. I often ask it to walk me through topics, even advanced ones, and then I can look up the primary source later if I need to.

Super useful if you are newer in your career or at an intermediate level I think!

1 year ago 1 0 1 0
Preview
Caching for Cash Kent C. Dodds discusses the fundamentals of caching including vocabulary, solid practices, general considerations, and recommendations.

@kentcdodds.com is equally to blame for my current deep dive into caching

www.epicweb.dev/talks/cachin...

1 year ago 4 0 0 1