HarperFast / HarperFast/harper
Component deploys install devDependencies; omitting them needs build-at-start gating, not a global default
- Dominant language
- JavaScript
- Stars
- 89
- Forks
- 10
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 200
Description
## Summary
Component deploys currently run `npm install --force --ignore-scripts`, which installs `devDependencies`. The suggestion on the table is to make deploys production-only (`npm install --omit=dev --no-audit --no-fund`). The reasoning is sound — but a naive global default breaks the most common non-trivial deploy shape, so the gating needs to be derived rather than flagged.
## Current behavior
`installApplication` in `components/Application.ts` has three install paths:
1. **Custom command** — `install.command` is spawned verbatim (`Application.ts:892`). Unaffected by any default-args change.
2. **`devEngines.packageManager`** — ` install`, plus `--ignore-scripts` unless `install.allowInstallScripts` (`Application.ts:962`).
3. **Default** — `npm install --force --ignore-scripts` unless `install.allowInstallScripts` (`Application.ts:1011-1013`).
Separately, the deprecated `install_node_modules` operation **already** passes `--omit=dev` (`utility/npmUtilities.ts:40`), so the two installation paths disagree today.
## Why omitting dev deps is mostly safe
The obvious objection is "some apps keep build tools in `devDependencies` and build on deploy." In the default configuration that build **cannot happen**: `--ignore-scripts` is the default, so a component's `prepare` / `postinstall` never runs on deploy unless the operator sets `install_allow_scripts`. In that default config the installed `devDependencies` are already dead weight — no code path can consume them.
Git-reference deploys are also unaffected. `npm pack` on a git ref clones the repo and runs its own install (including dev deps) plus `prepare` inside the clone; that's where a git-sourced build actually happens, and it does not go through the args above.
## Why a global default still breaks today
The gap is not npm scripts — it's **framework plugins that build in-process at component start**, bypassing the npm script mechanism entirely and therefore unaffected by `--ignore-scripts`.
`@harperfast/nextjs` defaults to `prebuilt: false` and calls `nextBuild` when the component starts (`src/plugin.ts:246`). `next build` requires typescript / postcss / tailwind / swc at build time, and `create-next-app` places all of those in `devDependencies`. A real customer Next.js app on Harper has `typescript` and `@swc/core` in `devDependencies` with `build: "next build --webpack"`.
So `--omit=dev` as a global default would break source-deployed Next.js apps — likely our most common non-trivial deploy.
## Proposal
Rather than "default on with an opt-out," tie dev-dependency omission to whether a build is possible at all:
- Omit `devDependencies` **unless** `install.allowInstallScripts` is set, **or** a loaded plugin declares that it builds at component start.
- `@harperfast/nextjs` either declares that need, or — preferably, and more consistent with the staged-artifact model — defaults `prebuilt` to `true` and expects a real prior build step.
This adds no operator-facing flag, changes nothing for anyone whose build works today, and stops installing dev dependencies in the (common) case where nothing can consume them.
Interim option if the plugin-declaration mechanism is too large for one change: add `install.omitDev` defaulting to `false`, then flip the default in a major once nextjs declares or changes its `prebuilt` default.
## Split out: `--no-audit --no-fund`
These two are unambiguous — pure output-noise and latency reduction with no semantic effect on the installed tree. Worth adding to the default args independently of the `--omit=dev` decision.
## Acceptance
- [ ] `--no-audit --no-fund` added to default deploy install args
- [ ] Mechanism for a plugin to declare "builds at component start"
- [ ] `--omit=dev` applied when no build is possible (no install scripts, no build-at-start plugin)
- [ ] `@harperfast/nextjs` declares its build-at-start need or defaults `prebuilt: true`
- [ ] `install_node_modules` / deploy install behavior reconciled
- [ ] Documented, including how an operator restores dev dependencies
Contributor guide
Research direction
Start by reading installApplication in components/Application.ts, the deprecated path in utility/npmUtilities.ts, and the Next.js build-at-start entry point in src/plugin.ts. Trace how install scripts and plugins determine whether a build can consume devDependencies, then verify the acceptance items, including reconciled install behavior and documentation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, next.js, node.js
- Domain
- build-system, devops
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100