Vite predev/prebuild: chaining scripts without losing your mind

Published: (May 25, 2026 at 09:16 AM EDT)
2 min read
Source: Dev.to

Source: Dev.to

What I tried first

{
  "scripts": {
    "predev": "node scripts/hash.js && node scripts/split.js && node scripts/gen.js",
    "prebuild": "node scripts/hash.js && node scripts/split.js && node scripts/gen.js",
    "dev": "vite",
    "build": "vite build"
  }
}

Problems

  • Duplicationpredev and prebuild are identical; adding a fourth step requires editing both entries.
  • Hard to debug – if a middle step fails, the chain stops without giving context about which step failed.

The cleaner pattern

Create a single orchestrator script that runs each step sequentially and logs progress.

// scripts/prebuild.js
import { spawnSync } from 'node:child_process';

const STEPS = [
  ['hash-legal', 'scripts/hash-legal-content.cjs'],
  ['split-geojson', 'scripts/split_parcelas_by_sm.cjs'],
  ['gen-landings', 'scripts/generate_landings.js'],
];

for (const [name, file] of STEPS) {
  console.log(`▶ ${name}`);
  const start = Date.now();
  const res = spawnSync('node', [file], { stdio: 'inherit' });
  if (res.status !== 0) {
    console.error(`✗ ${name} failed (exit ${res.status})`);
    process.exit(res.status);
  }
  console.log(`✓ ${name} (${Date.now() - start}ms)`);
}

Update package.json to use the orchestrator for both hooks:

{
  "scripts": {
    "predev": "node scripts/prebuild.js",
    "prebuild": "node scripts/prebuild.js",
    "dev": "vite",
    "build": "vite build"
  }
}
  • Adding a fourth step? Just add another entry to STEPS.
  • Want to skip a step during development? Filter STEPS based on an environment variable.
  • Need timing per step? The script already logs it.

Bonus: parallel steps

If two steps are independent (they don’t write to the same files), they can be run in parallel to cut down overall time:

// Example snippet inside scripts/prebuild.js
async function runStep(name, file) {
  console.log(`▶ ${name}`);
  const start = Date.now();
  const { status } = await import('child_process').then(cp =>
    cp.spawn('node', [file], { stdio: 'inherit' })
  );
  if (status !== 0) {
    console.error(`✗ ${name} failed (exit ${status})`);
    process.exit(status);
  }
  console.log(`✓ ${name} (${Date.now() - start}ms)`);
}

// Parallel execution
await Promise.all([
  runStep('hash', 'scripts/hash-legal-content.cjs'),
  runStep('split', 'scripts/split_parcelas_by_sm.cjs')
]);

await runStep('gen-landings', 'scripts/generate_landings.js');

Running independent steps concurrently roughly halves the predev time in the author’s project, while keeping the workflow simple and maintainable.

0 views
Back to Blog

Related posts

Read more »