Skip to content

voidzero-dev/setup-vp

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Repository files navigation

setup-vp

GitHub Action and GitLab CI/CD remote template to set up Vite+ (vp).

Features

  • Install Vite+ globally via official install scripts
  • GitHub Action: optionally set up a specific Node.js version via vp env use
  • GitHub Action: cache project dependencies with auto-detection of lock files
  • Optionally run vp install after setup
  • Optionally wrap vp install with Socket Firewall Free (sfw) to block malicious dependencies
  • Support for all major package managers (npm, pnpm, yarn, bun)
  • GitLab CI/CD support through a reusable include:remote template

Usage

Basic Usage

steps:
  - uses: actions/checkout@v6
  - uses: voidzero-dev/setup-vp@v1

With Node.js Version

steps:
  - uses: actions/checkout@v6
  - uses: voidzero-dev/setup-vp@v1
    with:
      node-version: "lts"

With Node.js Version File

steps:
  - uses: actions/checkout@v6
  - uses: voidzero-dev/setup-vp@v1
    with:
      node-version-file: ".node-version"

With Working Directory

steps:
  - uses: actions/checkout@v6
  - uses: voidzero-dev/setup-vp@v1
    with:
      working-directory: web
      node-version-file: ".nvmrc"
      cache: true
      run-install: true

With Caching and Install

steps:
  - uses: actions/checkout@v6
  - uses: voidzero-dev/setup-vp@v1
    with:
      node-version: "lts"
      cache: true
      run-install: true

Specific Version

steps:
  - uses: actions/checkout@v6
  - uses: voidzero-dev/setup-vp@v1
    with:
      version: "1.2.3"
      node-version: "lts"
      cache: true

Version from package.json / Catalog

Keep a single source of truth for the Vite+ version by resolving it from the checked-out project instead of duplicating it in the workflow.

By default (when neither version nor version-file is set), the action reads the vite-plus entry from the project's package.json and installs that version. When that entry is a semver range like ^0.2.0 (which can't be installed directly), it is resolved to the exact version recorded in the lockfile (pnpm-lock.yaml, package-lock.json, npm-shrinkwrap.json, yarn.lock, or bun.lock; the binary bun.lockb can't be read). It falls back to latest only when nothing pins a resolvable version. So a project that pins vite-plus needs no extra configuration:

steps:
  - uses: actions/checkout@v6
  - uses: voidzero-dev/setup-vp@v1
    with:
      cache: true

To resolve from a specific file, set version-file explicitly. Like the auto-detect default, an explicit version-file that can't be resolved logs a warning and falls back to latest (it does not fail the run); the warning is worth watching for, since it means the pinned version was not applied:

steps:
  - uses: actions/checkout@v6
  - uses: voidzero-dev/setup-vp@v1
    with:
      version-file: package.json
      cache: true

When the package.json entry is catalog: / catalog:<name>, it is resolved through the nearest catalog source (searching upward from the manifest), covering every package manager that implements the catalog: protocol:

// package.json
{
  "devDependencies": {
    "vite-plus": "catalog:",
  },
}
  • pnpm: pnpm-workspace.yaml

    catalog:
      vite-plus: 0.2.0
  • yarn (>= 4.10): .yarnrc.yml

    catalog:
      vite-plus: 0.2.0
  • bun: root package.json (catalog/catalogs, top-level or under workspaces)

    {
      "workspaces": {
        "packages": ["packages/*"],
        "catalog": { "vite-plus": "0.2.0" },
      },
    }

For npm (no catalog feature) or any project that pins the version directly, just declare an exact version ("vite-plus": "0.2.0") and it is used as-is.

You can also point version-file straight at pnpm-workspace.yaml or .yarnrc.yml to read its default catalog entry. An explicit version always takes precedence over version-file. A resolved value must be an exact version or dist-tag: when an explicit version-file yields a semver range (e.g. ^0.2.0) or an alias (npm: / git:), it can't be installed directly, so the action warns and falls back to latest. (Auto-detection instead resolves a package.json range through the lockfile, as described above.)

Advanced Run Install

steps:
  - uses: actions/checkout@v6
  - uses: voidzero-dev/setup-vp@v1
    with:
      node-version: "lts"
      cache: true
      run-install: |
        - cwd: ./packages/app
          args: ['--frozen-lockfile']
        - cwd: ./packages/lib

With Private Registry (GitHub Packages)

If your repo has a .npmrc that declares the registry, pass NODE_AUTH_TOKEN via env and let the default vp install run — no registry-url needed. When NODE_AUTH_TOKEN is set, the action auto-generates a matching _authToken entry at $RUNNER_TEMP/.npmrc for each registry declared in your repo .npmrc that doesn't already have one, so your repo .npmrc can stay minimal:

# .npmrc in the repo (auth line not required — action adds it):
#   @myorg:registry=https://npm.pkg.github.com

steps:
  - uses: actions/checkout@v6
  - uses: voidzero-dev/setup-vp@v1
    with:
      node-version: "lts"
    env:
      NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

If you already have the _authToken line in your repo .npmrc (e.g. for local dev symmetry), that's respected as-is and the action won't overwrite it.

Alternatively, pass registry-url explicitly to bypass the action's repo-level .npmrc detection and auth propagation logic (the package manager may still read the repo .npmrc per its own config resolution):

steps:
  - uses: actions/checkout@v6
  - uses: voidzero-dev/setup-vp@v1
    with:
      node-version: "lts"
      registry-url: "https://npm.pkg.github.com"
      scope: "@myorg"
      run-install: false
  - run: vp install
    env:
      NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

With Socket Firewall Free (sfw)

Set sfw: true to wrap vp install with Socket Firewall Free. The action downloads the matching sfw binary from the upstream releases (auto-detected per OS/arch, with musl support on Alpine) and runs sfw vp install … so the underlying npm / pnpm / yarn fetches are inspected before packages are installed. Works on Linux, macOS, and Windows:

steps:
  - uses: actions/checkout@v6
  - uses: voidzero-dev/setup-vp@v1
    with:
      sfw: true
      run-install: true

sfw is only applied when run-install is enabled; other vp commands (e.g. vp env use, vp --version) run unwrapped.

The action pins the sfw version it downloads so a re-run of the same commit gets the same binary; Renovate opens a PR whenever SocketDev publishes a new sfw-free release (see .github/renovate.json).

Advanced: stricter supply chain via socketdev/action

The bundled download uses a pinned URL but is not itself SHA-pinned. For workflows that want the sfw binary itself SHA-pinned (so a compromise of the upstream release artifact cannot land silently on the next run), compose with socketdev/action in an earlier step. setup-vp auto-detects an existing sfw on PATH and uses it instead of downloading:

steps:
  - uses: actions/checkout@v6
  # SHA-pinned; let Renovate bump it
  - uses: socketdev/action@<sha>
    with:
      mode: firewall-free
  - uses: voidzero-dev/setup-vp@v1
    with:
      sfw: true
      run-install: true

In the action log you will see Using existing sfw on PATH: … when this composition is detected, vs. Installing sfw from … for the bundled-download path.

Note

macOS / Windows require Vite+ v0.1.23 or newer. Earlier vp releases didn't honor HTTPS_PROXY / SSL_CERT_FILE, so sfw vp install failed the TLS handshake on macOS / Windows (it always worked on Linux). The action's default version: latest satisfies this; if you pin an older vp and enable sfw on macOS / Windows, the install will fail the handshake. On a runner architecture with no published sfw binary (e.g. riscv64), the action logs a warning and falls back to plain vp install.

Alpine Container

Alpine Linux uses musl libc instead of glibc. Install compatibility packages before using the action:

jobs:
  build:
    runs-on: ubuntu-latest
    container:
      image: alpine:3.21
    steps:
      - run: apk add --no-cache bash curl gcompat libstdc++
      - uses: actions/checkout@v6
      - uses: voidzero-dev/setup-vp@v1

Matrix Testing with Multiple Node.js Versions

jobs:
  test:
    strategy:
      matrix:
        node-version: ["20", "22", "24"]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: voidzero-dev/setup-vp@v1
        with:
          node-version: ${{ matrix.node-version }}
          cache: true
      - run: vp run test

Inputs

Input Description Required Default
version Version of Vite+ to install. Takes precedence over version-file No auto / latest
version-file Path to a file to resolve the Vite+ version from (package.json, pnpm-workspace.yaml, or .yarnrc.yml) No
node-version Node.js version to install via vp env use No Latest LTS
node-version-file Path to file containing Node.js version (.nvmrc, .node-version, .tool-versions, package.json) No
working-directory Project directory used for relative paths, lockfile auto-detection, environment checks, and default install No Workspace root
run-install Run vp install after setup. Accepts boolean or YAML object with cwd/args No true
sfw Wrap vp install with Socket Firewall Free (sfw) No false
cache Enable caching of project dependencies No false
cache-dependency-path Path to lock file for cache key generation No Auto-detected
registry-url Optional registry to set up for auth. Sets the registry in .npmrc and reads auth from NODE_AUTH_TOKEN No
scope Optional scope for scoped registries. Falls back to repo owner for GitHub Packages No

When working-directory is set, relative run-install.cwd, node-version-file, version-file, and cache-dependency-path values are resolved from that directory.

Outputs

Output Description
version The installed version of Vite+
cache-hit Boolean indicating if cache was restored

Caching

Dependency Cache

When cache: true is set, the action additionally caches project dependencies by auto-detecting your lock file:

Lock File Package Manager Cache Directory
pnpm-lock.yaml pnpm pnpm store
bun.lockb bun bun cache
bun.lock bun bun cache
package-lock.json npm npm cache
yarn.lock yarn yarn cache

The dependency cache key format is: vite-plus-{OS}-{arch}-{pm}-{lockfile-hash}

When working-directory is set, lockfile auto-detection runs in that directory.

When cache-dependency-path points to a lock file in a subdirectory, the action resolves the package-manager cache directory from that lock file's directory.

GitLab CI/CD

setup-vp also provides a GitLab CI/CD remote template hosted from this GitHub repository. Because this repository is not a GitLab CI/CD component project, GitLab users should load it with include:remote instead of include:component.

See GitLab integration notes for the design background, constraints, and follow-up work.

Basic GitLab Usage

include:
  - remote: "https://raw.githubusercontent.com/voidzero-dev/setup-vp/v1/gitlab/setup-vp.yml"

test:
  extends: .setup-vp
  image: node:24
  script:
    - vp run test

With GitLab Inputs

include:
  - remote: "https://raw.githubusercontent.com/voidzero-dev/setup-vp/v1/gitlab/setup-vp.yml"
    inputs:
      version: "latest"
      working-directory: "web"
      run-install: "true"

test:
  extends: .setup-vp
  image: node:24
  script:
    - vp run test

With Pinned GitLab Runtime

When using an immutable tag or commit SHA, pin setup-ref to the same ref so the bootstrap and compiled runtime are downloaded from the same version as the included template:

include:
  - remote: "https://raw.githubusercontent.com/voidzero-dev/setup-vp/v1.0.0/gitlab/setup-vp.yml"
    inputs:
      setup-ref: "v1.0.0"

test:
  extends: .setup-vp
  image: node:24
  script:
    - vp run test

With Existing GitLab before_script

GitLab replaces array keywords such as before_script when a job uses extends; it does not append them. If the job already needs setup commands, reference .setup-vp-bootstrap explicitly before the job-specific commands and configure setup-vp with variables:

include:
  - remote: "https://raw.githubusercontent.com/voidzero-dev/setup-vp/v1/gitlab/setup-vp.yml"

test:
  image: node:24
  variables:
    SETUP_VP_VERSION: "latest"
    SETUP_VP_RUN_INSTALL: "true"
    SETUP_VP_SETUP_REF: "v1"
  before_script:
    - !reference [.setup-vp-bootstrap, before_script]
    - npm config set //registry.example.com/:_authToken "$NODE_AUTH_TOKEN"
    - corepack enable
  script:
    - vp run test

Use the same pattern when the project has default:before_script; put the shared setup commands in each job that needs them instead of relying on .setup-vp to append to the default array. The bootstrap variables match the GitLab inputs with SETUP_VP_ prefixes, for example SETUP_VP_WORKING_DIRECTORY, SETUP_VP_SFW, SETUP_VP_REGISTRY_URL, and SETUP_VP_SCOPE.

Advanced GitLab Run Install

include:
  - remote: "https://raw.githubusercontent.com/voidzero-dev/setup-vp/v1/gitlab/setup-vp.yml"
    inputs:
      run-install: |
        - cwd: ./packages/app
          args: ['--frozen-lockfile']
        - cwd: ./packages/lib

test:
  extends: .setup-vp
  image: node:24
  script:
    - vp run test

With GitLab Socket Firewall Free (sfw)

include:
  - remote: "https://raw.githubusercontent.com/voidzero-dev/setup-vp/v1/gitlab/setup-vp.yml"
    inputs:
      sfw: true
      run-install: "true"

test:
  extends: .setup-vp
  image: node:24
  script:
    - vp run test

With Private Registry

Pass NODE_AUTH_TOKEN as a GitLab CI/CD variable and set registry-url when the job needs an authenticated npm registry:

include:
  - remote: "https://raw.githubusercontent.com/voidzero-dev/setup-vp/v1/gitlab/setup-vp.yml"
    inputs:
      registry-url: "https://npm.pkg.github.com"
      scope: "@myorg"

test:
  extends: .setup-vp
  image: node:24
  variables:
    NODE_AUTH_TOKEN: "$NPM_TOKEN"
  script:
    - vp run test

GitLab Inputs

Input Description Default
version Version of Vite+ to install latest
working-directory Project directory used for relative paths and default vp install execution .
run-install String input for vp install after setup. Use "true"/"false" or a YAML object/list with cwd/args true
sfw Wrap vp install with Socket Firewall Free false
registry-url Optional registry URL to write to a temporary .npmrc
scope Optional scope for authenticating against scoped registries
setup-ref setup-vp ref used to download the GitLab bootstrap and compiled runtime v1

GitLab Notes

  • Use a tag such as v1 or v1.0.0 in the remote URL instead of main.
  • Pin setup-ref to the same tag or commit SHA as the remote URL when strict reproducibility is required.
  • Quote GitLab string inputs such as run-install: "false"; unquoted booleans are rejected by GitLab before the setup runtime can parse them.
  • GitLab 17.9+ users can add integrity to pin the remote file hash.
  • The template expects a Unix-like runner image with Node.js, bash, and either curl or wget.
  • The GitLab runtime source is TypeScript under src/gitlab/, but the template downloads and runs the vp pack generated JavaScript bundle from dist/gitlab/index.mjs.
  • The GitLab template does not set up Node.js. Use a Node image such as node:24, or install Node.js before extending .setup-vp.
  • The GitLab template intentionally does not expose cache or cache-dependency-path inputs. GitLab restores job cache before before_script, so this template cannot compute cache paths during setup and restore them for the same job. Configure GitLab cache: directly on the job when needed.

Example Workflow

name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - uses: voidzero-dev/setup-vp@v1
        with:
          node-version: "lts"
          cache: true

      - run: vp run build

      - run: vp run test

Development

Install Vite+ CLI

  • Linux / macOS: curl -fsSL https://viteplus.dev/install.sh | bash
  • Windows: irm https://viteplus.dev/install.ps1 | iex

Setup

git clone https://github.com/voidzero-dev/setup-vp.git
cd setup-vp
vp install

Available Commands

Command Description
vp run build Build (outputs to dist/)
vp run test Run tests
vp run test:watch Run tests in watch mode
vp run typecheck Type check
vp run check Lint + format check
vp run check:fix Auto-fix lint/format

Before Committing

  • Run vp run check:fix and vp run build
  • Generated files under dist/ must be committed, including dist/index.mjs for the GitHub Action and dist/gitlab/index.mjs for the GitLab template
  • Pre-commit hooks (via husky + lint-staged) will automatically run vp check --fix on staged files via vpx lint-staged

Releasing

Releases are published as git tags (there is no npm package, so package.json stays at 1.0.0). Consumers reference the moving major tag voidzero-dev/setup-vp@v1 (or pin a commit SHA), so every release also moves v1 forward to the new commit.

After the changes are merged to main:

  1. Update main and confirm dist/index.mjs is in sync (the working tree must stay clean after building):

    git checkout main && git pull --ff-only
    vp run build
    git status --short   # must be empty
  2. Create the new annotated version tag (bump the minor from the latest v1.x.0) on the merged commit, then move the v1 major tag to the same commit:

    git tag -a v1.13.0 -m "v1.13.0"
    git tag -fa v1 -m "v1"
  3. Push the new version tag, then force-push the moved v1 tag:

    git push origin v1.13.0
    git push origin v1 --force

Both are annotated tags whose message is the tag name. v1 always points at the latest v1.x.0 release, so @v1 consumers pick it up automatically.

Feedback

If you have any feedback or issues, please submit an issue.

License

MIT

About

GitHub Action to set up Vite+ with dependency caching support.

Resources

License

Security policy

Stars

95 stars

Watchers

4 watching

Forks

Contributors