Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/full_update.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22
cache: "npm"

- name: Setup
Expand Down Expand Up @@ -59,9 +59,9 @@ jobs:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
run: |
(npx wrangler r2 object put gmodwiki/public_cache.zip --file ./public_cache.zip && rm -v public_cache.zip) &
(npx wrangler r2 object put gmodwiki/build_cache.zip --file ./build_cache.zip && rm -v build_cache.zip) &
(npx wrangler r2 object put gmodwiki/search_index.json --file ./search_index.json && mv ./search_index.json ./public/) &
(npx wrangler r2 object put gmodwiki/public_cache.zip --remote --file ./public_cache.zip && rm -v public_cache.zip) &
(npx wrangler r2 object put gmodwiki/build_cache.zip --remote --file ./build_cache.zip && rm -v build_cache.zip) &
(npx wrangler r2 object put gmodwiki/search_index.json --remote --file ./search_index.json && mv ./search_index.json ./public/) &
wait

# CF Publish
Expand All @@ -78,7 +78,7 @@ jobs:
CLOUDFLARE_CACHE_API_KEY: ${{ secrets.CF_CACHE_API_TOKEN }}
run: |
npm run clear_cloudflare_cache
rm --verbose deleted_files.json
rm -f --verbose deleted_files.json

- name: Set up Docker Buildx
if: ${{ github.event.inputs.skip_image != 'true' }}
Expand Down
14 changes: 6 additions & 8 deletions .github/workflows/update.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,13 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22
cache: "npm"

- name: Setup
run: |
npm --no-audit --progress=false ci &
(curl --location --remote-name https://storage.gmodwiki.com/build_cache.zip && unzip -q build_cache.zip && rm -v build_cache.zip) &
(curl --location --remote-name https://storage.gmodwiki.com/public_cache.zip && unzip -q public_cache.zip && rm -v public_cache.zip) &
wait
npm run download_caches

- name: Remove expired files
run: |
Expand Down Expand Up @@ -63,9 +61,9 @@ jobs:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
run: |
(npx wrangler r2 object put gmodwiki/public_cache.zip --file ./public_cache.zip && rm -v public_cache.zip) &
(npx wrangler r2 object put gmodwiki/build_cache.zip --file ./build_cache.zip && rm -v build_cache.zip) &
(npx wrangler r2 object put gmodwiki/search_index.json --file ./search_index.json && mv ./search_index.json ./public/) &
(npx wrangler r2 object put gmodwiki/public_cache.zip --remote --file ./public_cache.zip && rm -v public_cache.zip) &
(npx wrangler r2 object put gmodwiki/build_cache.zip --remote --file ./build_cache.zip && rm -v build_cache.zip) &
(npx wrangler r2 object put gmodwiki/search_index.json --remote --file ./search_index.json && mv ./search_index.json ./public/) &
wait

# CF Publish
Expand All @@ -82,7 +80,7 @@ jobs:
CLOUDFLARE_CACHE_API_KEY: ${{ secrets.CF_CACHE_API_TOKEN }}
run: |
npm run clear_cloudflare_cache
rm --verbose deleted_files.json
rm -f --verbose deleted_files.json

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ pnpm-debug.log*
.DS_Store

build/cache/
public/

public/*
!public/.gitkeep

slim.report.json

Expand Down
63 changes: 43 additions & 20 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,32 +1,55 @@
FROM node:21 AS builder
FROM node:22-slim AS base
WORKDIR /app
COPY package.json package-lock.json ./

ENV DEBIAN_FRONTEND=noninteractive
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

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.

/app/node_modules/@astrojs/cloudflare \
/app/node_modules/typescript \
/app/node_modules/@shikijs \
/app/node_modules/@esbuild \
/app/node_modules/@cloudflare \
/app/node_modules/fontkit \
/app/node_modules/@babel \
/app/node_modules/prismjs \
/app/node_modules/shiki \
/app/node_modules/rollup \
/app/node_modules/vite \
/app/node_modules/@types \
/app/node_modules/terser \
/app/node_modules/@rollup \
/app/node_modules/esbuild \
/app/node_modules/sharp \
/app/node_modules/@img \
/app/node_modules/astro

COPY package.json /app
COPY package-lock.json /app
COPY node_modules /app/node_modules
RUN npm install

COPY ./build /app/build
COPY ./public /app/public
COPY astro.config.mjs .
COPY tsconfig.json /app/tsconfig.json
COPY src /app/src
FROM base AS build-deps
RUN npm ci


FROM build-deps AS builder
COPY astro.config.mjs tsconfig.json ./
COPY .astro ./
COPY src ./src
COPY build ./build
COPY public ./public
ENV BUILD_ENV=docker
RUN npm run build
RUN npm run astrobuild

FROM node:21-alpine
WORKDIR /app
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

WORKDIR /app
COPY --from=prod-deps /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
ENV NODE_ENV=production
ENV HOST=0.0.0.0
ENV PORT=4321
ENV NODE_ENV=production
RUN npm i cookie kleur clsx cssesc server-destroy send path-to-regexp@6.2.1 html-escaper
RUN du -sh /app/node_modules
CMD ["node", "/app/dist/server/entry.mjs"]
EXPOSE 4321

CMD ["/app/dist/server/entry.mjs"]
33 changes: 7 additions & 26 deletions astro.config.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { defineConfig } from 'astro/config';
import { defineConfig } from "astro/config";

import node from '@astrojs/node';
import node from "@astrojs/node";
import cloudflare from "@astrojs/cloudflare";

const buildEnv = process.env.BUILD_ENV;
Expand All @@ -11,38 +11,19 @@ const buildConfig = { split: true };
if (buildEnv === "production") {
console.log("Building for Cloudflare adapter");
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",
Comment on lines 13 to +14
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

});
} else {
console.log("Building for Node adapter");
adapter = node({ mode: "standalone" });

buildConfig.rollupOptions = {
external: ["fs", "node:fs", "path", "node:path"]
}
external: ["fs", "node:fs", "path", "node:path"],
};
}

export default defineConfig({
build: buildConfig,
output: "server",
adapter: adapter
adapter: adapter,
});
Binary file added build/assets/states/client-menu.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/assets/states/client.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/assets/states/menu.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/assets/states/server-client-menu.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/assets/states/server-client.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/assets/states/server.png
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 👍

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions build/assets/~searchmanifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>

<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:moz="http://www.mozilla.org/2006/browser/search/">
<ShortName>GMod Wiki Mirror</ShortName>
<Description>A reliable and fast Mirror of the official Garry&#x27;s Mod Lua Wiki, with delightful improvements aimed at developers</Description>
<InputEncoding>UTF-8</InputEncoding>
<Tags>wiki games game gmod garrys mod glua lua api</Tags>

<Image width="16" height="16" type="image/png">https://gmodwiki.com/garry/822e60dc-c931-43e4-800f-cbe010b3d4cc.png</Image>
<Image width="32" height="32" type="image/png">https://gmodwiki.com/garry/822e60dc-c931-43e4-800f-cbe010b3d4cc.png</Image>

<Url method="get" rel="results" type="text/html" template="https://gmodwiki.com/websearch?query={searchTerms}"/>

<Url type="application/opensearchdescription+xml" rel="self" template="https://gmodwiki.com/~searchmanifest"/>
</OpenSearchDescription>
Comment on lines +1 to +15
Copy link
Member Author

Choose a reason for hiding this comment

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

I saw that the FP wiki has this file. I don't quite understand what it does or how it's supposed to be formatted (very little info about it, wasn't about to read the entire RFC for the feature) but figured we could try having our own copy.

Might have something to do with adding the site as a "search engine" in the browser?

51 changes: 0 additions & 51 deletions build/fragments/[...slug].astro
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.

This was being treated as a fragment (something that we'd modify and then programmatically put in src/pages/) but we never did any modifications to it so i just moved it to src/pages/

This file was deleted.

4 changes: 4 additions & 0 deletions build/fragments/layoutScript.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const logo = "/garry/822e60dc-c931-43e4-800f-cbe010b3d4cc.webp";

const ogLogo = `${Astro.url.protocol}//${Astro.url.host}${logo}`;
const fullUrl = `${Astro.url.protocol}//${Astro.url.host}${Astro.url.pathname}`;
Comment on lines +1 to +4
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 gets plopped into the frontmatter of the Layout.astro - it's small but I'd rather have it in a .ts file than a random string in some build file. Plus, if we expand on it, we'll get typechecking and all that.

Loading