webpack-dev-server workflow (webpack/webpack-dev-server)
The webpack-dev-server workflow from webpack/webpack-dev-server, explained and optimized by Latchkey.
CI health: C - fair
Run this on Latchkey for self-healing, caching, and up to 58% lower cost.
Grade your own workflow free or run it on Latchkey →What it does
This is the webpack-dev-server workflow from the webpack/webpack-dev-server 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
name: webpack-dev-server
on:
push:
branches:
- main
- next
- v4
pull_request:
branches:
- main
- next
- v4
permissions:
contents: read
jobs:
lint:
name: Lint - ${{ matrix.os }} - Node v${{ matrix.node-version }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
strategy:
matrix:
os: [ubuntu-latest]
node-version: [lts/*]
runs-on: ${{ matrix.os }}
concurrency:
group: lint-${{ matrix.os }}-v${{ matrix.node-version }}-${{ github.ref }}
cancel-in-progress: true
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: ${{ matrix.node-version }}
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint
- name: Build types
run: npm run build:types
- name: Check types
run: if [ -n "$(git status types --porcelain)" ]; then echo "Missing types. Update types by running 'npm run build:types'"; exit 1; else echo "All types are valid"; fi
- name: Validate PR commits with commitlint
if: github.event_name == 'pull_request'
run: npx commitlint --from ${{ github.event.pull_request.head.sha }}~${{ github.event.pull_request.commits }} --to ${{ github.event.pull_request.head.sha }} --verbose
- name: Validate changeset format
if: github.event_name == 'pull_request'
run: npm run validate:changeset
test:
name: Test - ${{ matrix.os }} - Node v${{ matrix.node-version == '24.15' && '24.x' || matrix.node-version }}, Webpack ${{ matrix.webpack-version }} (${{ matrix.shard }})
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
# 24.15 is pinned on purpose: Node 24.16 is broken for Puppeteer. Do not bump to 24.x.
node-version: [22.x, 24.15, 25.x]
shard: ["1/4", "2/4", "3/4", "4/4"]
webpack-version: [latest]
runs-on: ${{ matrix.os }}
concurrency:
group: test-${{ matrix.os }}-v${{ matrix.node-version }}-${{ matrix.webpack-version }}-${{ matrix.shard }}-${{ github.ref }}
cancel-in-progress: true
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: ${{ matrix.node-version }}
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Setup firefox
if: matrix.os != 'windows-latest'
uses: browser-actions/setup-firefox@0bc507ddf224827e3b1af68e014d5e42ab93e795 # v1.7.2
with:
firefox-version: latest
- name: Link webpack-dev-server
run: |
cp -R client tmp-client
npm link --ignore-scripts || true
npm link webpack-dev-server --ignore-scripts || true
rm -r client
cp -R tmp-client client
- name: Run tests for webpack version ${{ matrix.webpack-version }}
run: npm run test:coverage -- --test-shard=${{ matrix.shard }}
- name: Submit coverage data to codecov
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
with:
token: ${{ secrets.CODECOV_TOKEN }}
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: webpack-dev-server on: push: branches: - main - next - v4 pull_request: branches: - main - next - v4 permissions: contents: read concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: lint: timeout-minutes: 30 name: Lint - ${{ matrix.os }} - Node v${{ matrix.node-version }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} strategy: matrix: os: [ubuntu-latest] node-version: [lts/*] runs-on: ${{ matrix.os }} concurrency: group: lint-${{ matrix.os }}-v${{ matrix.node-version }}-${{ github.ref }} cancel-in-progress: true steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: ${{ matrix.node-version }} cache: "npm" - name: Install dependencies run: npm ci - name: Lint run: npm run lint - name: Build types run: npm run build:types - name: Check types run: if [ -n "$(git status types --porcelain)" ]; then echo "Missing types. Update types by running 'npm run build:types'"; exit 1; else echo "All types are valid"; fi - name: Validate PR commits with commitlint if: github.event_name == 'pull_request' run: npx commitlint --from ${{ github.event.pull_request.head.sha }}~${{ github.event.pull_request.commits }} --to ${{ github.event.pull_request.head.sha }} --verbose - name: Validate changeset format if: github.event_name == 'pull_request' run: npm run validate:changeset test: timeout-minutes: 30 name: Test - ${{ matrix.os }} - Node v${{ matrix.node-version == '24.15' && '24.x' || matrix.node-version }}, Webpack ${{ matrix.webpack-version }} (${{ matrix.shard }}) strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] # 24.15 is pinned on purpose: Node 24.16 is broken for Puppeteer. Do not bump to 24.x. node-version: [22.x, 24.15, 25.x] shard: ["1/4", "2/4", "3/4", "4/4"] webpack-version: [latest] runs-on: ${{ matrix.os }} concurrency: group: test-${{ matrix.os }}-v${{ matrix.node-version }}-${{ matrix.webpack-version }}-${{ matrix.shard }}-${{ github.ref }} cancel-in-progress: true steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: ${{ matrix.node-version }} cache: "npm" - name: Install dependencies run: npm ci - name: Setup firefox if: matrix.os != 'windows-latest' uses: browser-actions/setup-firefox@0bc507ddf224827e3b1af68e014d5e42ab93e795 # v1.7.2 with: firefox-version: latest - name: Link webpack-dev-server run: | cp -R client tmp-client npm link --ignore-scripts || true npm link webpack-dev-server --ignore-scripts || true rm -r client cp -R tmp-client client - name: Run tests for webpack version ${{ matrix.webpack-version }} run: npm run test:coverage -- --test-shard=${{ matrix.shard }} - name: Submit coverage data to codecov uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1 with: token: ${{ secrets.CODECOV_TOKEN }}
What changed
- Cancel superseded runs when a branch or PR gets a newer push.
- 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 2 jobs (37 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.