feat(app-tools): support programmatic dev/build lifecycle - #8783
Merged
Conversation
Use the app context command to initialize builders and resolve occupied ports for programmatic dev and start calls. Export closeServer from the package root, await Node close callbacks, and propagate close errors.
✅ Deploy Preview for modernjs-byted ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
🦋 Changeset detectedLatest commit: 4a2d422 The changes in this PR will be included in the next version bump. This PR includes changesets to release 118 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Contributor
Rsdoctor Bundle Diff Analysis📊 Quick Summary
Generated by Rsdoctor GitHub Action |
Remove the in-flight close tracking and callback waiting added for PIA test-kit. Keep the existing fire-and-forget singleton shutdown behavior.
The dist cleanup lived in the plugin `onPrepare` hook and gated on the CLI
argv command via `getCommand()`, so programmatic `dev`/`build`/`deploy`
(whose command lives in `appContext.command`, with a test-runner argv) never
emptied dist. Combined with the builder forcing `output.cleanDistPath: false`,
programmatic build/deploy kept stale chunks/server output that the deploy
preset could bundle.
Move the cleanup into the `dev` and `build` commands (new `cleanDistPath`
helper honoring `output.cleanDistPath`). This makes CLI and programmatic paths
behave identically and lets `deploy({ skipBuild: true })` preserve existing
dist for free (no build call -> no clean), since `onPrepare` could not see the
programmatic `skipBuild` flag. Dev restarts still clean on each (re)start,
matching prior behavior.
Add real-filesystem tests for the helper and for `build` cleaning/preserving
dist per `cleanDistPath`.
Co-Authored-By: Riff <noreply@aicu.bytedance.net>
The previous commits moved dist cleanup into the `build`/`dev` commands, but
those run after the analyze plugin's `onPrepare` has already generated
`dist/nestedRoutes.json` (router `onBeforeGenerateRoutes`). Cleaning there
deleted that file on every `build`/`dev` — including the CLI — and
`generateRoutes` never rebuilds it, so server-side route-level SSR
(`ssrByRouteIds`) silently regressed.
Move cleanup back into the plugin `onPrepare` hook, where app-tools' `post`
ordering guarantees it runs before analyze generates the routes. Detect both
the CLI argv command and the programmatic `appContext.command`, so programmatic
`dev`/`build` clean stale output like the CLI does.
`deploy` is intentionally excluded from the programmatic fallback: a
programmatic `deploy({ skipBuild: true })` only opts out when `deploy()` runs
(after `onPrepare`), so cleaning here could wipe the dist it means to reuse.
Programmatic `deploy` dist cleanup remains a known limitation. CLI
`deploy --skip-build` keeps its existing argv guard.
Remove the temporary `cleanDistPath` helper and its tests; add
`onPrepareCleanup.test.ts` covering argv and programmatic command detection,
`cleanDistPath` honoring, and skipBuild/deploy exclusions.
Co-Authored-By: Riff <noreply@aicu.bytedance.net>
deepcoldy
approved these changes
Jul 31, 2026
deepcoldy
left a comment
Contributor
There was a problem hiding this comment.
LGTM. Reviewed the programmatic dev/build/deploy lifecycle changes; second review by an independent reviewer confirmed no blockers.
Verified:
- Dist cleanup restored to
onPrepare(runs before analyze'sgenerateEntryCode), sodist/nestedRoutes.jsonis preserved — confirmed via a realmodern buildon the routes integration fixture. Command detection now recognizes both the CLI argv command and the programmaticappContext.command. - Programmatic
deployis intentionally excluded from the context fallback sodeploy({ skipBuild: true })preserves existing dist; programmatic-deploy dist cleanup is an accepted known limitation. CLIdeploy --skip-buildkeeps its original semantics. - Dev restart behavior is equivalent to the previous implementation.
pnpm --filter @modern-js/app-tools build+tsc --noEmitpass; app-tools tests 110/110 pass; Biome clean; CI all green.
Non-blocking nit: the PR description still mentions closeServer "await Node close callbacks, and propagate close errors", which no longer matches the reverted fire-and-forget implementation — worth removing.
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.

Use the app context command to initialize builders and resolve occupied ports for programmatic dev and start calls.
Export closeServer from the package root, await Node close callbacks, and propagate close errors.
Summary
Related Links
Checklist
pnpm run change.