Skip to content

Conversation

sarahsturgeon
Copy link
Member

I was just going to fix the Docker image but then it turned into a frenzied series of ADHD-fueled changes

@sarahsturgeon sarahsturgeon self-assigned this Oct 10, 2025
@sarahsturgeon sarahsturgeon added bug Something isn't working enhancement New feature or request labels Oct 10, 2025
Copy link
Member Author

@sarahsturgeon sarahsturgeon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tons of annotations, mostly for myself when I come back and ask why tf I did something

FROM base AS prod-deps
RUN npm ci --omit=dev
# Remove a bunch of unnecessary stuff to slim down the image
RUN rm -rf \
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other option is doing what I did originally, which was installing only specifically the packages we needed to run the app. Maybe I'll compare the total size, but this solution takes our runtime node_modules from like 200mb down to <70mb so I'm not too mad about it.

Best solution might be a combination of both. Install only what we need, and then delete any extra dependencies that get added that we simply won't use.

RUN apt-get update && apt-get install -y --no-install-recommends python3-minimal && rm -rf /var/lib/apt/lists/*

WORKDIR /app
FROM base AS prod-deps
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Separating the stages out into build-deps and prod-deps means we download+store the packages twice, but we don't have to redo the packages every time we make a change to any other file that we COPY - faster dev

COPY --from=builder /app/dist /app/dist

# Final Image
FROM gcr.io/distroless/nodejs22-debian12 AS final
Copy link
Member Author

@sarahsturgeon sarahsturgeon Oct 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Way smaller base image - it has exactly enough to run node22 and absolutely nothing more. Pretty neat.

We could probably look at docker-slim if we want to get it even smaller, but that would complicate our build setup (especially now that we're building for multiple architectures).


I played around with making the site entirely static inside Docker, but:

  1. There were no noticeable speed improvements when using the site
  2. Vastly complicated our build setup to support static in docker, but SSR in Cloudflare + Dev
  3. I think it would have ended up being bigger? The base HTML + sidebar HTML is multiple megabytes, and it'd need to be duplicated for every single page, resulting in a pretty massive set of content

Comment on lines 13 to +14
adapter = cloudflare({
mode: "advanced",
routes: {
strategy: "include",
include: ["/*"],
exclude: [
"/content/*",
"/script.js",
"/search_index.json",
"/~pagelist.json",
"/styles/gmod.css",
"/wiki/files/*",
"/rubat/*",
"/lewis/*",
"/garry/*",
"/fonts/*",
"/*.webp",
"/cdn-cgi/*",
"/last_build.txt",
]
}
imageService: "passthrough",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After updating astro + asrojs/cloudflare, it seems like the default behavior is correct for us, which is nice.

imageService: "passthrough" just means "don't try to optimize images" - we do that ourselves (and smarter, I think?).

It could be cool to use astro+cloudflare's built-in solution for progressive image loading (automatically generates multiple copies of the same image in different resolutions and then progressively loads them) but I don't feel like it's slow enough right now to start relying on Cloudflare's image service.

We could actually do this ourselves, at the cost of a larger final bundle size. (We'd skip it for the docker environment).

We would probably need to:

  1. Generate multiple copies of the same image at different qualities (2-3 steps maybe?)
  2. Replace all img tags with something simple that could load the images progressively (are there elements or attrs that do this for us? would we need to make our own astro component? is there a small library that makes it easy?)

Could be a cool enhancement some day

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some new static realm assets - right now we're using them in our og:logo or og:icon meta tag so that it shows the realm icon when linking a function. Kinda neat/cute

But hosting them means other people could use them for whatever, too 👍

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed after the astro upgrade

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to gitignore this file

const updated = "Updated: rarely";
---

<Layout title={"States Playground"} description={description} views={views} updated={updated}>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a cool page that lets people generate the realm icons in any size/format they want.
Gonna rename and reword it, then I gotta find somewhere to link it.

I like the idea of making our own utility pages, though. Should do more of that.

Comment on lines +39 to +65
const images = {
server: "/states/server.png",
client: "/states/client.png",
menu: "/states/menu.png",
"server-client": "/states/server-client.png",
"client-menu": "/states/client-menu.png",
"server-client-menu": "/states/server-client-menu.png",
"default": "/garry/822e60dc-c931-43e4-800f-cbe010b3d4cc.webp"
}
const getOpenGraphImage = (tags: string[]) => {
const hasServer = tags.includes("realm-server")
const hasClient = tags.includes("realm-client")
const hasMenu = tags.includes("realm-menu")
if (hasServer && hasClient && hasMenu) return images["server-client-menu"]
if (hasServer && hasClient) return images["server-client"]
if (hasClient && hasMenu) return images["client-menu"]
if (hasServer) return images["server"]
if (hasClient) return images["client"]
if (hasMenu) return images["menu"]
return images["default"]
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is our logic for returning a full URL to an image for the og:image meta tag. Uses the tags of the content json to determine what kind of function it is.

This means if you link a function, it'll include the realm icon in the embed, which is kinda cute.
We can probably do cooler things with this, too.

Comment on lines +3 to +4
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"],
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The astro upgrade guide suggested adding these 🤷‍♀️

@sarahsturgeon sarahsturgeon mentioned this pull request Oct 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant