Skip to content

fix(create): force devDependency install; add missing-binary preflight in run#1261

Draft
DaveHanns wants to merge 1 commit into
apify:masterfrom
DaveHanns:fix/f58-force-include-dev
Draft

fix(create): force devDependency install; add missing-binary preflight in run#1261
DaveHanns wants to merge 1 commit into
apify:masterfrom
DaveHanns:fix/f58-force-include-dev

Conversation

@DaveHanns

Copy link
Copy Markdown
Contributor

Summary

When a caller has NODE_ENV=production set — a common state after apify push (which pushes an image whose Dockerfile installs with --omit=dev), inside a Docker build, or in a shell that persists env across commands — the npm install that apify create runs after unpacking the template inherits that env and skips devDependencies. TypeScript templates rely on devDependencies (tsx, typescript, etc.), so apify run on the resulting scaffold fails immediately with a bare sh: tsx: not found, even though the success banner of apify create still points at apify run as the next step.

This PR:

  • Forces --include=dev on npm install and sets NODE_ENV=development in the child env for the post-scaffold install, so scaffolds are runnable regardless of the caller's environment (src/commands/create.ts).
  • Adds a preflight in apify run that, for npm run <script> style entrypoints, checks whether the script's leading binary exists in node_modules/.bin. On miss, it emits an actionable error instead of leaving the user with the raw sh: <bin>: not found (src/commands/run.ts).
  • Switches the post-create git init to git init -b main (with a fallback for older git), so scaffolded projects start on main regardless of the host's init.defaultBranch config.

Reproducer

$ NODE_ENV=production apify create tmp -t ts-empty
Info: Installing dependencies...
...
Success: Actor 'tmp' was created. To run it, run "cd tmp" and "apify run".

$ cd tmp
$ apify run
Run: npm run start
> tmp@0.0.1 start
> tsx src/main.ts
sh: tsx: not found

After this PR:

  • The post-scaffold install produces a node_modules that contains tsx, so the reproducer above just works.

  • Even if the user managed to arrive at a scaffold whose devDependencies were skipped (e.g. they ran npm install --omit=dev themselves, or ran apify create in a shell where the fix isn't yet applied), apify run now bails out early with:

    Error: "tsx" was not found in node_modules/.bin. This usually means devDependencies
    were skipped during install (e.g. NODE_ENV=production). Run `npm install --include=dev`
    (or `pnpm install --prod=false`) and retry.
    

Rationale

The install and the run are separate commands, but users treat apify create + apify run as a single "does it work?" flow — that's what the success banner promises. Making the install robust to the caller's env is the primary fix; the preflight is defense in depth (and gives an actionable error rather than a bare shell miss) for anyone who lands on a scaffold whose devDependencies were skipped for any other reason.

The preflight is intentionally conservative: it only fires when the script's leading token looks like a bare binary name (no /, not a known package manager / shell / node), and it only checks node_modules/.bin/<name> — so it won't false-positive on scripts that use absolute paths, node ./dist/main.js, npx ..., etc.

Test plan

  • NODE_ENV=production apify create tmp-node-env -t ts-empty — resulting node_modules/.bin contains tsx.
  • apify run in a scaffold whose node_modules/.bin/tsx has been deleted prints the new actionable error, not the raw sh: tsx: not found.
  • apify run on an unaffected scaffold (start script is node dist/main.js etc.) is unchanged.
  • apify create on a git repo host with init.defaultBranch=trunk still produces a scaffold initialised on main.

Notes

  • I did not add a new integration test that spins up a real NODE_ENV=production create+run cycle — the existing test/e2e/commands/create.test.ts uses --skip-dependency-install for speed, and adding a full install-and-run test would be a meaningful CI cost. Happy to add one if you'd like — let me know your preference (e2e, or a smaller unit test for the preflight helper).
  • The comments I added on the changed lines are load-bearing (they explain why the override / preflight exists); happy to trim them if that's not the house style.

Surfaced during an evaluation of Apify surfaces for agent-driven Actor development.

…t in run

When a caller has `NODE_ENV=production` set — a common state after `apify
push` (which pushes an image whose Dockerfile installs with `--omit=dev`)
or inside a Docker build — the `npm install` that `apify create` runs
after unpacking the template inherits that env and skips
devDependencies. TypeScript templates rely on devDependencies (`tsx`,
`typescript`, etc.), so `apify run` on the resulting scaffold fails
immediately with a bare `sh: tsx: not found`, while the success banner
of `apify create` still points at `apify run` as the next step.

This change:

- Forces `--include=dev` on npm and sets `NODE_ENV=development` in the
  child env for the post-scaffold install, so scaffolds are runnable
  regardless of the caller's environment.
- Adds a preflight in `apify run` that, for `npm run <script>` style
  entrypoints, checks whether the script's leading binary exists in
  `node_modules/.bin`. On miss, it emits an actionable error
  (`"tsx" was not found in node_modules/.bin. This usually means
  devDependencies were skipped ...`) instead of leaving the user with
  the raw `sh: tsx: not found`.
- Uses `git init -b main` (with a fallback for older git) so scaffolded
  projects start on `main` regardless of the host's
  `init.defaultBranch` config.

Reproducer:

  NODE_ENV=production apify create tmp -t ts-empty
  cd tmp && apify run
  # before: sh: tsx: not found
  # after:  "tsx" was not found in node_modules/.bin. ...

Surfaced during an evaluation of Apify surfaces for agent-driven Actor development.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@DaveHanns DaveHanns requested a review from l2ysho as a code owner July 4, 2026 23:02
@DaveHanns DaveHanns marked this pull request as draft July 5, 2026 11:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants