Trim Laravel Cloud Build Time
I've been using Laravel Cloud a bunch lately. Build times take about 18 seconds on the app that I'm working on. My entire build script used to be:
1composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader2npm ci --audit false3npm run build
Simple and clean.
The problem is, it's also doing a lot of waiting around. We have to wait 5–10 seconds for composer to finish installing before we can kick of npm. That drives me nuts. So I wrote a little shell
script to fix that. It's called parallel.sh and works like this:
1chain "install dependencies" \2 "composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader"3 4chain "build assets" \5 "npm ci --audit false" \6 "npm run build"7 8run
You start by defining any "chains" of commands that need to happen in sequence (in this case, we need to run npm ci before we can build our assets). Once your chains are defined, you call run
and everything runs in parallel.
Here are some benchmarks:
| Scenario | Before | After | Speedup |
|---|---|---|---|
| Typical Composer + NPM build | 11.01s | 7.09s | 1.6x |
| Four CI checks | 12.01s | 5.03s | 2.4x |
| A failing step late in the build | 6.01s | 1.03s | 5.8x |
| One long process + several quick ones | 10.01s | 6.04s | 1.7x |
In my real-world testing, this has brought my Laravel Cloud build down from ~18s to ~11s.
Check the parallel-build repo out. It's a single script you can just copy-and-paste into your project.
The earlier implementation
Before I abstracted this away into a shell function, I had a much less elegant solution. Below you'll find the earlier version of this page:
The ugly solution
Well, if you want something less simple and clean, but a little bit faster, you can speed up your builds by parallelizing (almost) everything. Here's my current script. It:
- Runs everying it can in parallel
- Fails as fast as possible
- Still gets you the command output in the end
Maybe it's not worth it, but while I'm iterating fast, the 11s build feels a lot better than the 18s one!
1composer_log=$(mktemp) 2npm_log=$(mktemp) 3build_log=$(mktemp) 4 5cleanup() { 6 rm -f "$composer_log" "$npm_log" "$build_log" 7} 8trap cleanup EXIT 9 10# Start composer install in bg11composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader > "$composer_log" 2>&1 &12composer_pid=$!13 14# Start npm install in fg because "run build" depends on it15echo "--- npm install ---"16npm ci --audit false17npm_status=$?18 19if [ $npm_status -ne 0 ]; then20 echo "[!] npm ci failed"21 kill $composer_pid 2>/dev/null22 wait $composer_pid 2>/dev/null23 echo "--- composer install (maybe partial) ---"24 cat "$composer_log"25 exit 126fi27 28npm run build > "$build_log" 2>&1 &29build_pid=$!30 31wait $composer_pid32composer_status=$?33 34echo "--- composer install ---"35cat "$composer_log"36 37if [ $composer_status -ne 0 ]; then38 echo "[!] composer failed"39 kill $build_pid 2>/dev/null40 wait $build_pid 2>/dev/null41 echo "--- npm build (maybe partial) ---"42 cat "$build_log"43 exit 144fi45 46wait $build_pid47build_status=$?48 49echo "--- npm build ---"50cat "$build_log"51 52if [ $build_status -ne 0 ]; then53 echo "[!] npm build failed"54 exit 155fi
Enjoy!