DEV Community

Cover image for I built shipshape-cli: a preflight check for JavaScript and React projects before you ship
mhk sameera
mhk sameera

Posted on

I built shipshape-cli: a preflight check for JavaScript and React projects before you ship

Most broken builds I've seen weren't caused by hard bugs. They were caused by small things:

  • an import pointing at a file someone renamed
  • an environment variable that never made it into .env.example
  • an empty lint script in package.json
  • a repo with no .gitignore, and node_modules sitting there waiting to be committed

None of these are difficult to fix. They're just easy to miss, and you usually find out at the worst time: when CI goes red, or when a teammate clones the repo and nothing runs.

So I built shipshape-cli, a small preflight check you run before handoff, CI or deployment.

npx shipshape-cli check .
Enter fullscreen mode Exit fullscreen mode

It's on npm now as v0.1.0: shipshape-cli

What it checks

shipshape-cli runs four groups of checks in one pass.

Package configuration. Missing or invalid package.json, invalid package names or versions, empty scripts, no test script, or no build script even though Vite, webpack or Next.js is a dependency.

Import integrity. Relative imports (./ and ../) that don't resolve to a real file. It handles import, export ... from, import(), require() and TypeScript's import type. It also tries the usual extensions and index.* files, the same way your bundler would.

Environment configuration. Variables your code reads through process.env or import.meta.env but that are missing from .env.example, plus entries in .env.example that nothing uses any more.

Project hygiene. No README, no .gitignore, or generated folders like dist or node_modules that aren't ignored.

Here's what it prints for a deliberately broken React app:

IMPORTS
  ✗ IMP001 Cannot resolve import "./components/Footer" (src/App.jsx:2:20)
      Fix: Check the path and file name (including letter case), or create the missing file.

ENVIRONMENT
  ! ENV001 VITE_SENTRY_DSN is referenced but missing from .env.example (src/App.jsx:6:35)
      Fix: Add "VITE_SENTRY_DSN=" with a placeholder value to .env.example.

Summary: 4 errors, 4 warnings, 2 info
Enter fullscreen mode Exit fullscreen mode

Every finding has a rule ID, a file and line, and a suggested fix.

Design decisions

It parses code, it doesn't pattern-match it. Imports and env variables are found with @babel/parser, not regular expressions, so comments and strings that only look like imports don't produce false alarms.

It's strictly read-only. This was the rule I cared about most. A tool you point at your project shouldn't be able to change it, leak it or run it. shipshape-cli:

  • never writes, moves or deletes files
  • never runs npm scripts, installs packages or executes project code
  • never opens your real .env files; it reads only .env.example, and keeps only the variable names
  • makes no network requests and sends no telemetry
  • never prints your source code in its output

All of these are covered by tests.

"Skipped" is not "passed". If a check has nothing to analyse, for example no JavaScript files, it's reported as skipped, never as a green tick. A preflight tool that quietly passes things it never looked at is worse than no tool.

Ignores are never silent. You can leave out intentionally broken folders with a .shipshapeignore file, but every report lists the patterns in use, so nobody can hide a problem without it showing.

Using it in CI

Install it as a dev dependency and add a script:

npm install --save-dev shipshape-cli
Enter fullscreen mode Exit fullscreen mode
{
  "scripts": {
    "preflight": "shipshape check ."
  }
}
Enter fullscreen mode Exit fullscreen mode

The exit codes are built for pipelines: 0 means no errors, 1 means errors were found, and 2 means the scan itself couldn't run. Add --strict to fail on warnings too, or --json for a machine-readable report.

One thing to watch: use npx shipshape-cli, not npx shipshape. The unscoped shipshape package on npm is an unrelated project.

What it doesn't do (yet)

This is a first release, and I'd rather be clear about its limits:

  • Path aliases such as @/components/Button aren't resolved yet, so those imports aren't checked.
  • On macOS and Windows, an import with the wrong letter case still resolves locally, so it isn't caught, even though it will fail on Linux CI.
  • .vue, .svelte and .astro files aren't parsed yet.

Path alias support is the most obvious next step.

Try it

npx shipshape-cli check .
Enter fullscreen mode Exit fullscreen mode

It needs Node.js 20 or later and works on Node 20, 22 and 24.

If you run it on one of your projects, I'd really like to hear what it found, and what it got wrong. Issues and suggestions for new checks are very welcome.

Top comments (0)