fix(create): force devDependency install; add missing-binary preflight in run#1261
Draft
DaveHanns wants to merge 1 commit into
Draft
fix(create): force devDependency install; add missing-binary preflight in run#1261DaveHanns wants to merge 1 commit into
DaveHanns wants to merge 1 commit into
Conversation
…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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When a caller has
NODE_ENV=productionset — a common state afterapify push(which pushes an image whose Dockerfile installs with--omit=dev), inside a Docker build, or in a shell that persists env across commands — thenpm installthatapify createruns after unpacking the template inherits that env and skipsdevDependencies. TypeScript templates rely ondevDependencies(tsx,typescript, etc.), soapify runon the resulting scaffold fails immediately with a baresh: tsx: not found, even though the success banner ofapify createstill points atapify runas the next step.This PR:
--include=devonnpm installand setsNODE_ENV=developmentin the child env for the post-scaffold install, so scaffolds are runnable regardless of the caller's environment (src/commands/create.ts).apify runthat, fornpm run <script>style entrypoints, checks whether the script's leading binary exists innode_modules/.bin. On miss, it emits an actionable error instead of leaving the user with the rawsh: <bin>: not found(src/commands/run.ts).git inittogit init -b main(with a fallback for older git), so scaffolded projects start onmainregardless of the host'sinit.defaultBranchconfig.Reproducer
After this PR:
The post-scaffold install produces a
node_modulesthat containstsx, so the reproducer above just works.Even if the user managed to arrive at a scaffold whose
devDependencieswere skipped (e.g. they rannpm install --omit=devthemselves, or ranapify createin a shell where the fix isn't yet applied),apify runnow bails out early with:Rationale
The install and the run are separate commands, but users treat
apify create+apify runas 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 whosedevDependencieswere 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 checksnode_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— resultingnode_modules/.bincontainstsx.apify runin a scaffold whosenode_modules/.bin/tsxhas been deleted prints the new actionable error, not the rawsh: tsx: not found.apify runon an unaffected scaffold (start script isnode dist/main.jsetc.) is unchanged.apify createon a git repo host withinit.defaultBranch=trunkstill produces a scaffold initialised onmain.Notes
NODE_ENV=productioncreate+run cycle — the existingtest/e2e/commands/create.test.tsuses--skip-dependency-installfor 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).Surfaced during an evaluation of Apify surfaces for agent-driven Actor development.