fix(docker): fix Docker image latest tag and production runtime errors; add dev compose file, Codespace support, and semver release tagging (#7) (#4277)

* fix: also tag Docker image as latest on main branch push

Agent-Logs-Url: https://github.com/pourmand1376/readest/sessions/bbc0f66e-7488-4d9d-976b-434588b3faa8



* fix: production Dockerfile missing patches/.env.web; add compose.dev.yaml for dev hot-reload

Agent-Logs-Url: https://github.com/pourmand1376/readest/sessions/e27bba4e-b8ea-4694-b44d-6308aa778d41



* fix: add devcontainer to init submodules; add clear Dockerfile error when submodules missing

Agent-Logs-Url: https://github.com/pourmand1376/readest/sessions/16d24ae0-d2e8-4523-b47e-4969dd587c50



* simplify production-stage: COPY --from=build /app /app instead of selective copies

Agent-Logs-Url: https://github.com/pourmand1376/readest/sessions/356fabe4-f944-48b6-a409-41640480d52f



* fix: add CI=true to dev compose to prevent pnpm no-TTY abort

Agent-Logs-Url: https://github.com/pourmand1376/readest/sessions/ddc30fef-2c76-452d-aad6-d688ca912a1a



* fix: add semver Docker image version tags on release

Agent-Logs-Url: https://github.com/pourmand1376/readest/sessions/18cbc3c6-ba92-4e63-bef9-93dcf6698c21



---------

Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
Amir Pourmand
2026-05-23 06:09:15 +03:30
committed by GitHub
parent 66c198e575
commit b8d986cbd6
6 changed files with 53 additions and 29 deletions
+6
View File
@@ -0,0 +1,6 @@
{
"name": "Readest",
// Initialize only the submodules required for Docker builds.
// tauri/tauri-plugins are skipped here since they're only needed for desktop builds.
"postCreateCommand": "git submodule update --init packages/foliate-js packages/simplecc-wasm"
}
+6 -2
View File
@@ -135,8 +135,10 @@ jobs:
images: ghcr.io/${{ github.repository_owner }}/readest images: ghcr.io/${{ github.repository_owner }}/readest
tags: | tags: |
type=raw,value=main,enable={{is_default_branch}} type=raw,value=main,enable={{is_default_branch}}
type=raw,value=latest,enable={{is_default_branch}}
type=raw,value=latest,enable=${{ github.event_name == 'release' }} type=raw,value=latest,enable=${{ github.event_name == 'release' }}
type=raw,value=${{ github.event.release.tag_name }},enable=${{ github.event_name == 'release' }} type=semver,pattern={{version}},enable=${{ github.event_name == 'release' }}
type=semver,pattern={{major}}.{{minor}},enable=${{ github.event_name == 'release' }}
type=sha,prefix=sha- type=sha,prefix=sha-
- name: Extract image metadata (GHCR + Docker Hub) - name: Extract image metadata (GHCR + Docker Hub)
@@ -149,8 +151,10 @@ jobs:
docker.io/${{ secrets.DOCKERHUB_USERNAME }}/readest docker.io/${{ secrets.DOCKERHUB_USERNAME }}/readest
tags: | tags: |
type=raw,value=main,enable={{is_default_branch}} type=raw,value=main,enable={{is_default_branch}}
type=raw,value=latest,enable={{is_default_branch}}
type=raw,value=latest,enable=${{ github.event_name == 'release' }} type=raw,value=latest,enable=${{ github.event_name == 'release' }}
type=raw,value=${{ github.event.release.tag_name }},enable=${{ github.event_name == 'release' }} type=semver,pattern={{version}},enable=${{ github.event_name == 'release' }}
type=semver,pattern={{major}}.{{minor}},enable=${{ github.event_name == 'release' }}
type=sha,prefix=sha- type=sha,prefix=sha-
- name: Create manifest list and push (GHCR only) - name: Create manifest list and push (GHCR only)
+4 -9
View File
@@ -9,6 +9,9 @@ COPY apps/readest-app/package.json ./apps/readest-app/
COPY patches/ ./patches/ COPY patches/ ./patches/
COPY packages/ ./packages/ COPY packages/ ./packages/
RUN --mount=type=cache,id=pnpm,sharing=locked,target=/pnpm/store pnpm install --frozen-lockfile RUN --mount=type=cache,id=pnpm,sharing=locked,target=/pnpm/store pnpm install --frozen-lockfile
RUN test -f packages/foliate-js/vendor/pdfjs/annotation_layer_builder.css \
&& test -d packages/simplecc-wasm/dist/web \
|| { printf '\nERROR: Required git submodules are not initialized in the source directory.\nEnsure submodules are initialized before running docker build.\nRun: git submodule update --init packages/foliate-js packages/simplecc-wasm\n\n'; exit 1; }
RUN pnpm --filter @readest/readest-app setup-vendors RUN pnpm --filter @readest/readest-app setup-vendors
FROM docker.io/library/node:24-slim@sha256:24dc26ef1e3c3690f27ebc4136c9c186c3133b25563ae4d7f0692e4d1fe5db0e AS development-stage FROM docker.io/library/node:24-slim@sha256:24dc26ef1e3c3690f27ebc4136c9c186c3133b25563ae4d7f0692e4d1fe5db0e AS development-stage
@@ -50,15 +53,7 @@ ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable RUN corepack enable
RUN corepack prepare pnpm@11.1.1 --activate RUN corepack prepare pnpm@11.1.1 --activate
WORKDIR /app WORKDIR /app
# Only copy what next start needs — omit source, Rust, tests, patches, etc. COPY --from=build /app /app
COPY --from=build /app/package.json /app/package.json
COPY --from=build /app/pnpm-workspace.yaml /app/pnpm-workspace.yaml
COPY --from=build /app/node_modules /app/node_modules
COPY --from=build /app/apps/readest-app/package.json /app/apps/readest-app/package.json
COPY --from=build /app/apps/readest-app/next.config.mjs /app/apps/readest-app/next.config.mjs
COPY --from=build /app/apps/readest-app/node_modules /app/apps/readest-app/node_modules
COPY --from=build /app/apps/readest-app/.next /app/apps/readest-app/.next
COPY --from=build /app/apps/readest-app/public /app/apps/readest-app/public
WORKDIR /app/apps/readest-app WORKDIR /app/apps/readest-app
ENTRYPOINT ["pnpm", "start-web", "-H", "0.0.0.0"] ENTRYPOINT ["pnpm", "start-web", "-H", "0.0.0.0"]
EXPOSE 3000 EXPOSE 3000
+13 -10
View File
@@ -63,13 +63,19 @@ replace `your-dockerhub-username` with the Docker Hub namespace that publishes y
for official images, use the namespace configured for this repository's Docker Hub publishing secrets. for official images, use the namespace configured for this repository's Docker Hub publishing secrets.
published tags: published tags:
- `latest`: published from release events - `latest`: rolling image from the default branch and from release events
- `<release-tag>` (for example `v1.2.3`): published from release events - `<release-tag>` (for example `v1.2.3`): published from release events
- `main`: rolling image from the default branch - `main`: rolling image from the default branch
- `sha-<commit>`: immutable commit tag - `sha-<commit>`: immutable commit tag
### Build locally instead of pulling ### Build locally instead of pulling
> **Prerequisites for local builds**: the `packages/foliate-js` and `packages/simplecc-wasm` git submodules must be initialized before building:
> ```bash
> git submodule update --init packages/foliate-js packages/simplecc-wasm
> ```
> In GitHub Codespaces this is done automatically via `.devcontainer/devcontainer.json`.
```bash ```bash
cd docker cd docker
docker compose -f compose.yaml -f compose.build.yaml up --build -d docker compose -f compose.yaml -f compose.build.yaml up --build -d
@@ -82,16 +88,13 @@ docker compose -f compose.yaml -f compose.build.yaml up --build -d
### Hot Reload (development) ### Hot Reload (development)
to develop using the compose stack, use local builds (`compose.yaml` + `compose.build.yaml`) and set the build target on `client` to `development-stage` in `compose.build.yaml`, which runs the next.js dev server. to enable hot reload, uncomment the `volumes` block in the `client` service in `compose.yaml`: > **Prerequisites**: submodules must be initialized (see above).
```yaml to develop using the compose stack, use `compose.dev.yaml` which sets the build target to `development-stage` (Next.js dev server) and mounts your local repo for hot reload:
volumes:
- ../:/app ```bash
- /app/node_modules cd docker
- /app/apps/readest-app/node_modules docker compose -f compose.yaml -f compose.dev.yaml up --build -d
- /app/apps/readest-app/public/vendor
- /app/apps/readest-app/.next
- /app/packages/foliate-js/node_modules
``` ```
the first mount overlays your local repo into the container. the remaining anonymous volumes shadow the directories that were pre-built inside the image, so the container's installed deps and vendor assets are used instead of what's on your host. the first mount overlays your local repo into the container. the remaining anonymous volumes shadow the directories that were pre-built inside the image, so the container's installed deps and vendor assets are used instead of what's on your host.
+24
View File
@@ -0,0 +1,24 @@
# Overlay on top of compose.yaml.
# Usage (from the docker/ directory):
# docker compose -f compose.yaml -f compose.dev.yaml up --build -d
services:
client:
build:
context: ..
target: development-stage
args:
NEXT_PUBLIC_APP_PLATFORM: web
environment:
# Required so pnpm does not abort when purging node_modules without a TTY
CI: "true"
# Mount the source code for hot reload.
# Anonymous volumes shadow pre-built dirs inside the image so the
# container's installed deps and vendor assets are used instead of
# what's on the host.
volumes:
- ../:/app
- /app/node_modules
- /app/apps/readest-app/node_modules
- /app/apps/readest-app/public/vendor
- /app/apps/readest-app/.next
- /app/packages/foliate-js/node_modules
-8
View File
@@ -124,14 +124,6 @@ services:
restart: unless-stopped restart: unless-stopped
ports: ports:
- "3000:3000" - "3000:3000"
# to enable hot reload, mount the source code as a volume, and artifacts as anon volumes
# volumes:
# - ../:/app
# - /app/node_modules
# - /app/apps/readest-app/node_modules
# - /app/apps/readest-app/public/vendor
# - /app/apps/readest-app/.next
# - /app/packages/foliate-js/node_modules
environment: environment:
SUPABASE_URL: http://kong:8000 SUPABASE_URL: http://kong:8000
SUPABASE_PUBLIC_URL: http://${HOST_IP}:${KONG_HTTP_PORT:-8000} SUPABASE_PUBLIC_URL: http://${HOST_IP}:${KONG_HTTP_PORT:-8000}