Skip to content
Latchkey

CI workflow (vitejs/vite)

The CI workflow from vitejs/vite, explained and optimized by Latchkey.

A

CI health: A - excellent

The optimized version below adds job timeouts.

Source: vitejs/vite.github/workflows/ci.ymlLicense MITView source

What it does

This is the CI workflow from the vitejs/vite repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.

Below, Latchkey shows a faster, safer version produced by its optimization engine.

The workflow

workflow (.yml)
name: CI

env:
  # 7 GiB by default on GitHub, setting to 6 GiB
  # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources
  NODE_OPTIONS: --max-old-space-size=6144
  # install playwright binary manually (because pnpm only runs install script once)
  PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
  # Vitest auto retry on flaky segfault
  VITEST_SEGFAULT_RETRY: 3

# Remove default permissions of GITHUB_TOKEN for security
# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
permissions: {}

on:
  push:
    branches:
      - main
      - release/*
      - feat/*
      - fix/*
      - perf/*
      - "v[0-9]+" # v1, v2, ...
      - "v[0-9]+.[0-9]+" # v4.0, v4.1, ...
  pull_request:
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.event.number || github.sha }}
  cancel-in-progress: true

jobs:
  changed:
    name: Get changed files
    runs-on: ubuntu-slim
    outputs:
      should_skip: ${{ steps.changed-files.outputs.only_changed == 'true' }}

    steps:
      - name: Checkout
        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
        with:
          # Assume PRs are less than 50 commits
          fetch-depth: 50
          persist-credentials: false

      - name: Get changed files
        id: changed-files
        uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6
        with:
          files: |
            docs/**
            .github/**
            !.github/workflows/ci.yml
            packages/create-vite/template**
            **.md

  test:
    needs: changed
    if: needs.changed.outputs.should_skip != 'true'
    timeout-minutes: 20
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest]
        node_version: [20, 22, 24, 26]
        include:
          # Active LTS + other OS
          - os: macos-latest
            node_version: 24
          - os: windows-latest
            # use older minor to workaround https://github.com/nodejs/node/issues/63638
            node_version: 24.15.0
      fail-fast: false

    name: "Build&Test: node-${{ matrix.node_version }}, ${{ matrix.os }}"
    steps:
      - name: Checkout
        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
        with:
          persist-credentials: false

      - name: Install pnpm
        uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9

      - name: Set node version to ${{ matrix.node_version }}
        uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
        with:
          node-version: ${{ matrix.node_version }}
          cache: "pnpm"

      - name: Install deps
        run: pnpm install

      # Install playwright's binary under custom directory to cache
      - name: (non-windows) Set Playwright path and Get playwright version
        if: runner.os != 'Windows'
        run: |
          echo "PLAYWRIGHT_BROWSERS_PATH=$HOME/.cache/playwright-bin" >> $GITHUB_ENV
          PLAYWRIGHT_VERSION="$(pnpm ls --depth 0 --json -w playwright-chromium | jq --raw-output '.[0].devDependencies["playwright-chromium"].version')"
          echo "PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION" >> $GITHUB_ENV
      - name: (windows) Set Playwright path and Get playwright version
        if: runner.os == 'Windows'
        run: |
          echo "PLAYWRIGHT_BROWSERS_PATH=$HOME\.cache\playwright-bin" >> $env:GITHUB_ENV
          $env:PLAYWRIGHT_VERSION="$(pnpm ls --depth 0 --json -w playwright-chromium | jq --raw-output '.[0].devDependencies["playwright-chromium"].version')"
          echo "PLAYWRIGHT_VERSION=$env:PLAYWRIGHT_VERSION" >> $env:GITHUB_ENV

      - name: Cache Playwright's binary
        uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
        with:
          key: ${{ runner.os }}-playwright-bin-v1-${{ env.PLAYWRIGHT_VERSION }}
          path: ${{ env.PLAYWRIGHT_BROWSERS_PATH }}
          restore-keys: |
            ${{ runner.os }}-playwright-bin-v1-

      - name: Install Playwright
        # does not need to explicitly set chromium after https://github.com/microsoft/playwright/issues/14862 is solved
        run: pnpm playwright install chromium

      - name: Build
        run: pnpm run build

      - name: Test unit
        run: pnpm run test-unit

      - name: Test serve
        run: pnpm run test-serve

      - name: Test build
        run: pnpm run test-build

  test-passed:
    if: (!cancelled() && !failure())
    needs: test
    runs-on: ubuntu-slim
    name: Build & Test Passed or Skipped
    steps:
      - run: echo "Build & Test Passed or Skipped"

  test-failed:
    if: (!cancelled() && failure())
    needs: test
    runs-on: ubuntu-slim
    name: Build & Test Failed
    steps:
      - run: echo "Build & Test Failed"

  lint:
    timeout-minutes: 10
    runs-on: ubuntu-latest
    name: "Lint: node-24, ubuntu-latest"
    steps:
      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
        with:
          persist-credentials: false

      - name: Install pnpm
        uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9

      - name: Set node version to 24
        uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
        with:
          node-version: 24
          cache: "pnpm"

      - name: Install deps
        run: pnpm install

      - name: Build
        run: pnpm run build

      - name: Lint
        run: pnpm run lint

      - name: Check formatting
        run: pnpm format && git diff --exit-code

      - name: Typecheck
        run: pnpm run typecheck

      - name: Test docs
        run: pnpm run test-docs

      # From https://github.com/rhysd/actionlint/blob/main/docs/usage.md#use-actionlint-on-github-actions
      - name: Check workflow files
        run: |
          bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
          ./actionlint -color -shellcheck=""

The same workflow, on Latchkey

Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.

name: CI env:  # 7 GiB by default on GitHub, setting to 6 GiB  # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources  NODE_OPTIONS: --max-old-space-size=6144  # install playwright binary manually (because pnpm only runs install script once)  PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"  # Vitest auto retry on flaky segfault  VITEST_SEGFAULT_RETRY: 3 # Remove default permissions of GITHUB_TOKEN for security# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobspermissions: {} on:  push:    branches:      - main      - release/*      - feat/*      - fix/*      - perf/*      - "v[0-9]+" # v1, v2, ...      - "v[0-9]+.[0-9]+" # v4.0, v4.1, ...  pull_request:  workflow_dispatch: concurrency:  group: ${{ github.workflow }}-${{ github.event.number || github.sha }}  cancel-in-progress: true jobs:  changed:    timeout-minutes: 30    name: Get changed files    runs-on: latchkey-small    outputs:      should_skip: ${{ steps.changed-files.outputs.only_changed == 'true' }}     steps:      - name: Checkout        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7        with:          # Assume PRs are less than 50 commits          fetch-depth: 50          persist-credentials: false       - name: Get changed files        id: changed-files        uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6        with:          files: |            docs/**            .github/**            !.github/workflows/ci.yml            packages/create-vite/template**            **.md   test:    needs: changed    if: needs.changed.outputs.should_skip != 'true'    timeout-minutes: 20    runs-on: latchkey-small    strategy:      matrix:        os: [ubuntu-latest]        node_version: [20, 22, 24, 26]        include:          # Active LTS + other OS          - os: macos-latest            node_version: 24          - os: windows-latest            # use older minor to workaround https://github.com/nodejs/node/issues/63638            node_version: 24.15.0      fail-fast: false     name: "Build&Test: node-${{ matrix.node_version }}, ${{ matrix.os }}"    steps:      - name: Checkout        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7        with:          persist-credentials: false       - name: Install pnpm        uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9       - name: Set node version to ${{ matrix.node_version }}        uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6        with:          node-version: ${{ matrix.node_version }}          cache: "pnpm"       - name: Install deps        run: pnpm install       # Install playwright's binary under custom directory to cache      - name: (non-windows) Set Playwright path and Get playwright version        if: runner.os != 'Windows'        run: |          echo "PLAYWRIGHT_BROWSERS_PATH=$HOME/.cache/playwright-bin" >> $GITHUB_ENV          PLAYWRIGHT_VERSION="$(pnpm ls --depth 0 --json -w playwright-chromium | jq --raw-output '.[0].devDependencies["playwright-chromium"].version')"          echo "PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION" >> $GITHUB_ENV      - name: (windows) Set Playwright path and Get playwright version        if: runner.os == 'Windows'        run: |          echo "PLAYWRIGHT_BROWSERS_PATH=$HOME\.cache\playwright-bin" >> $env:GITHUB_ENV          $env:PLAYWRIGHT_VERSION="$(pnpm ls --depth 0 --json -w playwright-chromium | jq --raw-output '.[0].devDependencies["playwright-chromium"].version')"          echo "PLAYWRIGHT_VERSION=$env:PLAYWRIGHT_VERSION" >> $env:GITHUB_ENV       - name: Cache Playwright's binary        uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6        with:          key: ${{ runner.os }}-playwright-bin-v1-${{ env.PLAYWRIGHT_VERSION }}          path: ${{ env.PLAYWRIGHT_BROWSERS_PATH }}          restore-keys: |            ${{ runner.os }}-playwright-bin-v1-       - name: Install Playwright        # does not need to explicitly set chromium after https://github.com/microsoft/playwright/issues/14862 is solved        run: pnpm playwright install chromium       - name: Build        run: pnpm run build       - name: Test unit        run: pnpm run test-unit       - name: Test serve        run: pnpm run test-serve       - name: Test build        run: pnpm run test-build   test-passed:    timeout-minutes: 30    if: (!cancelled() && !failure())    needs: test    runs-on: latchkey-small    name: Build & Test Passed or Skipped    steps:      - run: echo "Build & Test Passed or Skipped"   test-failed:    timeout-minutes: 30    if: (!cancelled() && failure())    needs: test    runs-on: latchkey-small    name: Build & Test Failed    steps:      - run: echo "Build & Test Failed"   lint:    timeout-minutes: 10    runs-on: latchkey-small    name: "Lint: node-24, ubuntu-latest"    steps:      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7        with:          persist-credentials: false       - name: Install pnpm        uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9       - name: Set node version to 24        uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6        with:          node-version: 24          cache: "pnpm"       - name: Install deps        run: pnpm install       - name: Build        run: pnpm run build       - name: Lint        run: pnpm run lint       - name: Check formatting        run: pnpm format && git diff --exit-code       - name: Typecheck        run: pnpm run typecheck       - name: Test docs        run: pnpm run test-docs       # From https://github.com/rhysd/actionlint/blob/main/docs/usage.md#use-actionlint-on-github-actions      - name: Check workflow files        run: |          bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)          ./actionlint -color -shellcheck="" 

What changed

  • Run on Latchkey managed runners with one line (runs-on), which apply the fixes below automatically and self-heal transient failures. This example uses latchkey-small; pick the runner size that fits the job.
  • Add a job timeout so a hung step cannot burn hours of runner time.

What Latchkey heals here

This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:

  • Dependency installs
  • End-to-end and browser tests

This workflow runs 5 jobs (8 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.

Actions used in this workflow

Frequently asked questions

What does the CI workflow (vitejs/vite) workflow do?
This is the CI workflow from the vitejs/vite repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.
What CI health grade does this workflow get?
This Node.js workflow grades A. Paste your own workflow into the Latchkey grader to see its grade and the exact fixes.
How can I improve this Node.js workflow?
Apply job timeouts. Latchkey applies these automatically on managed runners when you point runs-on at Latchkey.

References