Answer to the Core Questions
1. Version‑locking strategy
Use composer.lock for PHP, yarn.lock (or package-lock.json) for Node, and pin the runtime in Docker with ARG PHP_VERSION and ARG NODE_VERSION. Add a .nvmrc and a package.json engines field so local installs follow the same versions. This guarantees identical dependency trees and build outputs.
2. Integrating the Inertia build step
In the deployment pipeline run npm ci (or yarn install --frozen-lockfile) followed by npm run build. The resulting public/build folder is then copied to the production image or served from the same container. If using Docker, add a separate node stage that mirrors the dev build and copies the assets into the PHP stage.
3. CI verification steps
• Run composer install --no-interaction --no-progress --prefer-dist and npm ci.
• Execute npm run build.
• Spin up a short‑lived Laravel container and run php artisan test.
• Verify the X-Inertia header and the presence of the asset manifest in public/build/manifest.json.
• Optionally compute a SHA‑256 hash of the public/build directory and compare it against a stored reference to catch accidental changes.
Why This Works
composer.lock and yarn.lock freeze the exact versions of every transitive dependency, eliminating “works on my machine” drift.
- Docker
ARG values and FROM tags lock the runtime environment; the same image is built in CI and locally.
- Running
npm ci (instead of npm install) ensures the lockfile is respected and the node_modules tree is deterministic.
- The Inertia build step is part of the Docker image build, so the assets are always regenerated under the same Node and Vite configuration.
- CI checks that the compiled assets contain the expected
manifest.json and that the server responds with the X-Inertia header, surfacing mismatches early.
Implementation Sketch
# Dockerfile (PHP & Node multi‑stage)
ARG PHP_VERSION=8.2
ARG NODE_VERSION=18
FROM node:${NODE_VERSION}-alpine AS node
WORKDIR /app
COPY package.json yarn.lock .
RUN yarn install --frozen-lockfile
COPY . .
RUN yarn run build
FROM php:${PHP_VERSION}-fpm-alpine AS php
WORKDIR /var/www/html
COPY --from=node /app/public/build ./public/build
COPY composer.json composer.lock .
RUN composer install --no-dev --no-interaction --prefer-dist
COPY . .
RUN php artisan view:clear && php artisan route:clear && php artisan config:clear
CMD ["php-fpm"]
CI Pipeline Snippet (GitHub Actions)
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.2
extensions: mbstring, pdo_mysql
- name: Install Composer
run: composer install --no-interaction --no-progress --prefer-dist
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
- name: Install JS deps
run: yarn install --frozen-lockfile
- name: Build assets
run: yarn run build
- name: Run tests
run: php artisan test
- name: Verify Inertia header
run: |
curl -s -D- http://localhost:8000 | grep -i X-Inertia
Missing Diagnostic Detail
Do you currently use Yarn or npm for the front‑end? The exact lockfile name and build script command differ slightly, and the CI steps need to match that choice.