feat(docker): official Vite+ toolchain image#1944
Conversation
✅ Deploy Preview for viteplus-preview ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
✅ Staging deployment successful! Preview: https://viteplus-staging.void.app/ |
vite-plus
@voidzero-dev/vite-plus-core
@voidzero-dev/vite-plus-prompts
@voidzero-dev/vite-plus-cli-darwin-arm64
@voidzero-dev/vite-plus-cli-darwin-x64
@voidzero-dev/vite-plus-cli-linux-arm64-gnu
@voidzero-dev/vite-plus-cli-linux-arm64-musl
@voidzero-dev/vite-plus-cli-linux-x64-gnu
@voidzero-dev/vite-plus-cli-linux-x64-musl
@voidzero-dev/vite-plus-cli-win32-arm64-msvc
@voidzero-dev/vite-plus-cli-win32-x64-msvc
@voidzero-dev/vite-plus-darwin-arm64
@voidzero-dev/vite-plus-darwin-x64
@voidzero-dev/vite-plus-linux-arm64-gnu
@voidzero-dev/vite-plus-linux-arm64-musl
@voidzero-dev/vite-plus-linux-x64-gnu
@voidzero-dev/vite-plus-linux-x64-musl
@voidzero-dev/vite-plus-win32-arm64-msvc
@voidzero-dev/vite-plus-win32-x64-msvc
commit: |
Manual verification commands for the Docker preview imagesPreview images on GHCR (from the
1. Basic functionalitydocker run --rm ghcr.io/voidzero-dev/vite-plus:pr-1944 vp --version
docker run --rm ghcr.io/voidzero-dev/vite-plus:pr-1944 sh -c \
'id -un; command -v vp; vp help >/dev/null && echo "vp help ok"; git --version'2. Common
|
Measure each published preview image (docker pull + image inspect) and render a size table in the comment, alongside the pull commands. Addresses review feedback on #1944.
🐳 Docker preview imagesBuilt from this PR's pkg.pr.new build:
docker pull ghcr.io/voidzero-dev/vite-plus:pr-1944
docker pull ghcr.io/voidzero-dev/vite-plus:pr-1944-alpineQuick check: docker run --rm ghcr.io/voidzero-dev/vite-plus:pr-1944 vp --versionSee docs/guide/docker.md for usage. |
|
An exception was found that may be related to the vite task. The lint command runs normally when executed directly, but throws an error after passing through the task runner. docker run --rm ghcr.io/voidzero-dev/vite-plus:pr-1944 bash -c \
'vp create vite:monorepo --directory hello --no-interactive && cd hello && vp lint && vp run ready'
◇ Scaffolded hello with Vite+ monorepo
• Node 24.18.0 pnpm 11.9.0
✓ Dependencies installed in 27s
→ Next: cd hello && vp run
Found 0 warnings and 0 errors.
Finished in 1.2s on 6 files with 111 rules using 16 threads.
$ vp check
pass: All 18 files are correctly formatted (1112ms, 16 threads)
Error running tsgolint: "exit status: exit status: 1"/app/hello/node_modules/.pnpm/oxlint-tsgolint@0.23.0/node_modules/oxlint-tsgolint/bin/tsgolint.js:18
throw e;
^
<ref *1> Error: spawnSync /app/hello/node_modules/.pnpm/@oxlint-tsgolint+linux-x64@0.23.0/node_modules/@oxlint-tsgolint/linux-x64/tsgolint EINVAL
at Object.spawnSync (node:internal/child_process:1143:20)
at spawnSync (node:child_process:911:24)
at Object.execFileSync (node:child_process:954:15)
at Object.<anonymous> (/app/hello/node_modules/.pnpm/oxlint-tsgolint@0.23.0/node_modules/oxlint-tsgolint/bin/tsgolint.js:11:17)
at Module._compile (node:internal/modules/cjs/loader:1871:14)
at Object..js (node:internal/modules/cjs/loader:2002:10)
at Module.load (node:internal/modules/cjs/loader:1594:32)
at Module._load (node:internal/modules/cjs/loader:1396:12)
at wrapModuleLoad (node:internal/modules/cjs/loader:255:19)
at Module.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:154:5) {
errno: -22,
code: 'EINVAL',
syscall: 'spawnSync /app/hello/node_modules/.pnpm/@oxlint-tsgolint+linux-x64@0.23.0/node_modules/@oxlint-tsgolint/linux-x64/tsgolint',
path: '/app/hello/node_modules/.pnpm/@oxlint-tsgolint+linux-x64@0.23.0/node_modules/@oxlint-tsgolint/linux-x64/tsgolint',
spawnargs: [ 'headless' ],
error: [Circular *1],
status: null,
signal: null,
output: null,
pid: 0,
stdout: undefined,
stderr: undefined
}
Node.js v24.18.0
Linting failed before analysis started
error: Linting could not startcc @wan9chi |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d36ba17fad
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Copy only package.json + lockfile in the cached dependency layer so projects that pin Node via engines.node / devEngines.runtime (no .node-version file) do not fail at COPY. .node-version, when used, is picked up from the full COPY . . before vp build. Addresses review feedback on #1944.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3a61144d72
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Propose an official Vite+ toolchain Docker image on GHCR that bundles the vp CLI for the build/CI/dev phases, plus a documented multi-stage pattern that copies the exact .node-version Node into a slim glibc runtime (no vp), keeping deployed images small while honoring the project's pinned Node. Refs #1490, #1324
The image installs vp from npm via the official install script (pinned VP_VERSION) and publishes after the npm release, rather than copying release artifacts. Mark the RFC accepted with implementation in progress.
Add docker/Dockerfile for the official Vite+ toolchain image: a glibc (debian:bookworm-slim) image that bundles the vp CLI for the build, CI, and development phases. vp provisions the exact Node.js from .node-version at build time, so the image is version-agnostic and needs no Node-keyed tags. Add a publish-docker job to release.yml that builds the multi-arch (amd64/arm64) image and pushes it to ghcr.io/voidzero-dev/vite-plus, tagged by vp version, after the npm release is published. Add docs/guide/docker.md documenting the recommended multi-stage pattern that copies the resolved Node.js into a small, vp-free production runtime image, plus static-SPA, CI, devcontainer, and ad-hoc usage. Refs #1490
Add a publish-docker-preview job to publish-to-pkg.pr.new.yml that builds the multi-arch image from the PR's pkg.pr.new build (VP_PR_VERSION) and pushes it as ghcr.io/voidzero-dev/vite-plus:pr-<number>, so the image can be verified before a real release. Teach docker/Dockerfile an optional VP_PR_VERSION build arg, which installs vp from pkg.pr.new instead of npm. Refs #1490
Fixes vp check formatting failures in docs/guide/docker.md and rfcs/docker-image.md (table alignment and emphasis markers).
- Drop xz-utils: vp only extracts .tar.gz (gzip), never xz. - Drop redundant `mkdir -p /app && chown`: WORKDIR /app under USER vp already creates it owned by vp (verified). - Combine the two ENV instructions into one layer. - Build the per-PR preview image for linux/amd64 only; arm64 is covered by the release build and the test-install-sh-arm64 job, avoiding the slow QEMU leg on every labeled PR.
Reference why-reproductions-are-required/vite-plus-docker-example, which CI-verifies the documented Dockerfile patterns end to end.
The installer pre-provisions a default Node.js (~190MB), but each project provisions its own pinned Node at build time, so the default is dead weight in a builder image. Remove it (rm -rf $VP_HOME/js_runtime) in the install layer; the node/npm/npx shims remain and fetch the right version on first use. Toolchain image: ~1.04GB -> ~846MB, more than an Alpine switch would save and without the musl tradeoffs.
Publish an opt-in Alpine variant under -alpine tags (docker/Dockerfile.alpine), built via a debian+alpine matrix in both the release and pkg.pr.new preview workflows. It yields the smallest runtime (Alpine SSR ~136MB vs ~150MB distroless, ~198MB debian-slim) for teams that standardize on Alpine. Document the musl tradeoffs loudly: Node comes from the unofficial, unsigned musl builds; native addons may need musl prebuilds or source compilation; and a musl Node binary only runs on a musl base, so the runtime stage must also be Alpine. The Debian image stays the recommended default.
Switch the example tags from the fictional :1 to the real 0.x scheme (:0, :0.2, :0.2.2 and -alpine variants), since 0.2.2 is the first published image. Add a link to the GitHub package page to browse all published versions and digests.
The image runs as the non-root vp user, so COPY without --chown writes root-owned files that vp install cannot update (permission denied) when it needs to write package.json or the lockfile (e.g. no committed lockfile, or vp add). Use COPY --chown=vp:vp in the build/deps stages. Verified end to end against the published pr-1944 preview image.
After both preview variants publish, post (or update) a single PR comment with the pr-<n> / pr-<n>-alpine docker pull commands. Uses a hidden marker so re-runs reuse the same comment instead of creating new ones. Implemented with the existing actions/github-script (no new dependency); needs pull-requests: write.
Document why the sticky-comment body uses a line array (YAML block-scalar vs fenced code blocks) and add 'keep in sync' notes on the install RUN line shared verbatim between docker/Dockerfile and docker/Dockerfile.alpine.
Measure each published preview image (docker pull + image inspect) and render a size table in the comment, alongside the pull commands. Addresses review feedback on #1944.
Avoid hardcoded version tags in the runnable examples so users do not copy an outdated pin; the tags table now documents the scheme with placeholders.
Copy only package.json + lockfile in the cached dependency layer so projects that pin Node via engines.node / devEngines.runtime (no .node-version file) do not fail at COPY. .node-version, when used, is picked up from the full COPY . . before vp build. Addresses review feedback on #1944.
… summary Read the compressed download size from the registry manifest (no docker pull, ~425MB saved per run; matches what users pull and the GHCR package page), and remove the per-leg step summary now superseded by the sticky PR comment.
Use a .node-version* glob in the dependency COPY so the file is optional (no failure for engines.node/devEngines.runtime projects) yet available in every stage, including the SSR deps stage, when present. Reword the tag note so the :latest examples and the 'pin for reproducibility' advice no longer conflict.
git is installed with --no-install-recommends, which omits the SSH client, so git+ssh dependencies would fail during vp install; add openssh-client (apt and apk). Also create + chown /app to the vp user so downstream WORKDIR /app + vp install can write regardless of the builder. Addresses review feedback on #1944.
publish-docker needs the whole Release job; its last step is the Discord webhook. A notification failure must not fail Release (npm/GitHub release are already published) or skip GHCR publishing. Mark the step continue-on-error. Addresses review feedback on #1944.
|
@codex review |
Move the Discord notification out of the Release job into a terminal discord-notify job that runs after publish-docker, so the message can include the GHCR image (docker pull + alpine tag). This also fully removes the earlier concern about a notification failure affecting Docker publishing (Discord is now downstream of it). Webhook secret is a repo secret (used by request-approval without the release environment), so no environment/approval gate is needed.
|
Codex Review: Didn't find any major issues. Hooray! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
publish-docker already needs Release, so listing it again is redundant; depend on [check, publish-docker] (check is kept for its outputs).
Node.js is the trademarked product name (OpenJS Foundation); bare 'Node' is incorrect. Use 'Node.js' for the runtime/version in prose and keep lowercase 'node' for the binary/command and image tags. Applied across the Docker guide, the RFC, and the Dockerfile comments. Addresses review feedback on #1944.
Implements the official Vite+ Docker image from the RFC (
rfcs/docker-image.md).vpalready provisions the exact Node.js from.node-version, so one toolchain image builds any project (no Node-version-keyed tags). It is not a production runtime image: a documented multi-stage build copies the resolved Node.js into a small, vp-free runtime stage.Changes
docker/Dockerfile: glibc (debian:bookworm-slim) image bundlingvp+ native build toolchain, non-root user.release.yml:publish-dockerjob, multi-arch (amd64/arm64) push toghcr.io/voidzero-dev/vite-plusafter npm publish, version-tagged.docs/guide/docker.md+ sidebar: multi-stage runtime, static SPA, CI, devcontainer, ad-hoc usage.Verified locally:
.node-version=24.15.0resolves and installs exactly v24.15.0; the copied Node runs standalone in a plaindebian:bookworm-slimstage.Note:
the first publish needs the GHCR package made public / linked to the repo in org settings.Closes #1490