Skip to content
Draft
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
126 changes: 126 additions & 0 deletions .github/workflows/publish-to-pkg.pr.new.yml
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,129 @@ jobs:
'./packages/cli' \
'./packages/core' \
'./packages/prompts'

# Build and push a preview Docker image from the pkg.pr.new build so the image
# can be verified before a real release. Tagged `pr-<number>`; never `latest`.
# See docker/Dockerfile and docs/guide/docker.md.
publish-docker-preview:
if: >-
github.repository == 'voidzero-dev/vite-plus' &&
contains(github.event.pull_request.labels.*.name, 'pkg.pr.new')
name: Docker preview image (${{ matrix.variant }})
runs-on: ubuntu-latest
needs: publish
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- variant: debian
dockerfile: docker/Dockerfile
tag_suffix: ''
- variant: alpine
dockerfile: docker/Dockerfile.alpine
tag_suffix: '-alpine'
env:
IMAGE: ghcr.io/voidzero-dev/vite-plus
TAG: pr-${{ github.event.pull_request.number }}${{ matrix.tag_suffix }}
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2

- uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0

- name: Log in to GHCR
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

# Builds from the pkg.pr.new packages for this PR (VP_PR_VERSION). The
# platform packages must exist first, hence `needs: publish`.
# amd64-only: this throwaway preview avoids the slow arm64 QEMU leg; arm64
# is covered by the release build and the test-install-sh-arm64 job.
- name: Build and push preview image
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
with:
context: docker
file: ${{ matrix.dockerfile }}
platforms: linux/amd64
push: true
tags: ${{ env.IMAGE }}:${{ env.TAG }}
build-args: |
VP_PR_VERSION=${{ github.event.pull_request.number }}
provenance: false

- name: Summary
run: |
{
echo "### Docker preview image (${{ matrix.variant }})"
echo ""
echo '```bash'
echo "docker pull ${IMAGE}:${TAG}"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"

# Post (or update) a single sticky PR comment with the preview image tags after
# both variants publish successfully. Re-runs reuse the same comment via the
# hidden marker instead of creating a new one.
comment-docker-preview:
if: >-
github.repository == 'voidzero-dev/vite-plus' &&
contains(github.event.pull_request.labels.*.name, 'pkg.pr.new')
name: Comment Docker preview
runs-on: ubuntu-latest
needs: publish-docker-preview
permissions:
pull-requests: write
steps:
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
env:
IMAGE: ghcr.io/voidzero-dev/vite-plus
with:
script: |
const image = process.env.IMAGE;
const pr = context.payload.pull_request.number;
const marker = '<!-- docker-preview -->';
const body = [

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Could you show the final size of the Docker image? Please display this metadata in a table.

marker,
'## 🐳 Docker preview images',
'',
"Built from this PR's pkg.pr.new build:",
'',
'```bash',
`docker pull ${image}:pr-${pr}`,
`docker pull ${image}:pr-${pr}-alpine`,
'```',
'',
'Quick check:',
'',
'```bash',
`docker run --rm ${image}:pr-${pr} vp --version`,
'```',
'',
'See [docs/guide/docker.md](https://github.com/voidzero-dev/vite-plus/blob/main/docs/guide/docker.md) for usage.',
].join('\n');
const comments = await github.paginate(github.rest.issues.listComments, {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr,
});
const existing = comments.find((c) => c.body && c.body.includes(marker));
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr,
body,
});
}
67 changes: 67 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -232,3 +232,70 @@ jobs:
• macOS/Linux: `curl -fsSL https://vite.plus | bash`
• Windows: `irm https://vite.plus/ps1 | iex`
embed-url: https://github.com/${{ github.repository }}/releases/tag/v${{ env.VERSION }}

# Build and push the official toolchain Docker image to GHCR after the npm
# release is published (the image installs vp from npm, so the version must
# exist first). See docker/Dockerfile and docs/guide/docker.md.
publish-docker:
name: Publish Docker image (${{ matrix.variant }})
runs-on: ubuntu-latest
needs: [check, Release]
if: needs.check.outputs.version_changed == 'true'
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
# Debian (glibc) is the default: tags get no suffix.
- variant: debian
dockerfile: docker/Dockerfile
suffix: ''
# Alpine (musl): tags get the -alpine suffix.
- variant: alpine
dockerfile: docker/Dockerfile.alpine
suffix: '-alpine'
env:
VERSION: ${{ needs.check.outputs.version }}
IMAGE: ghcr.io/voidzero-dev/vite-plus
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2

- uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0

- uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0

- name: Log in to GHCR
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Docker metadata
id: meta
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0
with:
images: ${{ env.IMAGE }}
flavor: |
latest=false
suffix=${{ matrix.suffix }}
tags: |
type=semver,pattern={{version}},value=${{ env.VERSION }}
type=semver,pattern={{major}}.{{minor}},value=${{ env.VERSION }}
type=semver,pattern={{major}},value=${{ env.VERSION }}
type=raw,value=latest

- name: Build and push
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
with:
context: docker
file: ${{ matrix.dockerfile }}
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
VP_VERSION=${{ env.VERSION }}
provenance: false
60 changes: 60 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# syntax=docker/dockerfile:1
#
# Official Vite+ toolchain image.
#
# Bundles the `vp` CLI for the build, CI, and development phases. This is NOT a
# production runtime image: it ships the full toolchain (vite, rolldown, vitest,
# oxlint, ...) and is meant for use as a build stage, CI image, or devcontainer.
#
# For production, use the documented multi-stage pattern (see docs/guide/docker.md)
# where this image builds the app and the exact Node.js resolved from
# `.node-version` is copied into a small, vp-free runtime stage.

FROM debian:bookworm-slim

LABEL org.opencontainers.image.source="https://github.com/voidzero-dev/vite-plus" \
org.opencontainers.image.description="Vite+ toolchain image (vp CLI) for build, CI, and development" \
org.opencontainers.image.licenses="MIT"

# Version of vp to install. Override at build time:
# docker build --build-arg VP_VERSION=1.4.2 .
ARG VP_VERSION=latest

# Optional: build a preview image from a pkg.pr.new build instead of npm.
# Set to a PR number or commit SHA; when set it overrides VP_VERSION.
# docker build --build-arg VP_PR_VERSION=1569 .
ARG VP_PR_VERSION=

# Toolchain image: include git and a C/C++ build toolchain so native addons
# (for example better-sqlite3 or sharp) can compile during `vp install`.
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
curl \
git \
build-essential \
python3 \
pkg-config \
&& rm -rf /var/lib/apt/lists/* \
&& useradd --create-home --shell /bin/bash vp

# Run as a non-root user by default (mirrors oven/bun's `bun` and Deno's `deno`).
USER vp

ENV VP_HOME=/home/vp/.vite-plus \
PATH=/home/vp/.vite-plus/bin:$PATH

# Install the vp global CLI. The installer downloads the platform package from
# npm (or from pkg.pr.new when VP_PR_VERSION is set). Node.js itself is
# provisioned per-project by vp at build time, honoring `.node-version` /
# `engines.node` / `devEngines.runtime`.
#
# The installer pre-provisions a default Node.js (~190 MB). Drop it: each project
# downloads its own pinned Node at build time, so the default is dead weight in a
# builder image. The node/npm/npx shims remain and fetch the right version on
# first use.
RUN curl -fsSL https://vite.plus | VP_VERSION="${VP_VERSION}" VP_PR_VERSION="${VP_PR_VERSION}" bash \
&& vp --version \
&& rm -rf "$VP_HOME/js_runtime"

WORKDIR /app
53 changes: 53 additions & 0 deletions docker/Dockerfile.alpine
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# syntax=docker/dockerfile:1
#
# Alpine (musl) variant of the official Vite+ toolchain image.
#
# Smaller base than the Debian image, but note the tradeoffs:
# - Vite+ installs Node.js from the unofficial musl builds
# (unofficial-builds.nodejs.org), which are NOT PGP-signed.
# - Some native addons need musl prebuilds or source compilation.
# - A musl Node.js binary only runs on a musl base, so pair this builder with
# an Alpine runtime stage (see docs/guide/docker.md).
#
# Prefer the Debian image (ghcr.io/voidzero-dev/vite-plus) unless you
# specifically need Alpine/musl.

FROM alpine:3.21

LABEL org.opencontainers.image.source="https://github.com/voidzero-dev/vite-plus" \
org.opencontainers.image.description="Vite+ toolchain image (vp CLI, Alpine/musl) for build, CI, and development" \
org.opencontainers.image.licenses="MIT"

# Version of vp to install. Override at build time:
# docker build --build-arg VP_VERSION=1.4.2 -f docker/Dockerfile.alpine .
ARG VP_VERSION=latest

# Optional: build a preview image from a pkg.pr.new build instead of npm.
ARG VP_PR_VERSION=

# build-base + python3 let native addons compile from source on musl.
RUN apk add --no-cache \
bash \
ca-certificates \
curl \
git \
tar \
build-base \
python3 \
&& adduser -D -s /bin/bash vp

# Run as a non-root user by default (mirrors oven/bun's `bun` and Deno's `deno`).
USER vp

ENV VP_HOME=/home/vp/.vite-plus \
PATH=/home/vp/.vite-plus/bin:$PATH

# Install the vp global CLI (musl build), then drop the pre-provisioned default
# Node.js: each project provisions its own pinned Node at build time, so the
# default is dead weight. The node/npm/npx shims remain and fetch the right
# version on first use.
RUN curl -fsSL https://vite.plus | VP_VERSION="${VP_VERSION}" VP_PR_VERSION="${VP_PR_VERSION}" bash \
&& vp --version \
&& rm -rf "$VP_HOME/js_runtime"

WORKDIR /app
1 change: 1 addition & 0 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const guideSidebar = [
items: [
{ text: 'IDE Integration', link: '/guide/ide-integration' },
{ text: 'CI', link: '/guide/ci' },
{ text: 'Docker', link: '/guide/docker' },
{ text: 'Commit Hooks', link: '/guide/commit-hooks' },
{ text: 'Monorepo Guide', link: '/guide/monorepo' },
{ text: 'Troubleshooting', link: '/guide/troubleshooting' },
Expand Down
Loading
Loading