[docs] Document run script and Dockerfile conflict for AddJavaScriptApp#1014
Conversation
When AddJavaScriptApp is configured with an explicit runScriptName or WithRunScript and an existing user-authored Dockerfile is present, Aspire now fails at publish time with a clear error instead of silently ignoring the requested run script. Document the conflict, the error message, and the two resolution paths: remove/rename the Dockerfile, or use PublishAsDockerFile with an explicit container entrypoint. Documents changes from microsoft/aspire#16969. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Documents a new Aspire 13.4 publish-time validation behavior for AddJavaScriptApp when a user-authored Dockerfile is present and a run script override is configured, explaining the resulting error and how to resolve it.
Changes:
- Added a “Run script and existing Dockerfile conflict” subsection describing when the validation triggers, including the error text and resolution options.
- Added a related bullet to the “Common mistakes” section.
Comments suppressed due to low confidence (1)
src/frontend/src/content/docs/deployment/javascript-apps.mdx:1277
- This “Common mistakes” bullet says any explicit
runScriptName/.WithRunScript(...)with an existing user Dockerfile causes the conflict, but the section above notes that the defaultrunScriptName("dev") without custom args is allowed. Consider tightening the bullet to match the actual conflict condition (non-default script name and/or custom args).
- Passing an explicit `runScriptName` or calling `.WithRunScript(...)` when the app directory already has a user-authored Dockerfile, which causes a publish-time conflict error. Remove the Dockerfile or use `PublishAsDockerFile(...)` with an explicit container entrypoint to resolve the conflict.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| ### Run script and existing Dockerfile conflict | ||
|
|
||
| When `AddJavaScriptApp` finds an existing user-authored `Dockerfile` in the app directory, Aspire uses that Dockerfile as the publish container image and cannot safely replace its `ENTRYPOINT`. If you also pass an explicit `runScriptName` to `AddJavaScriptApp` or call `.WithRunScript(...)` with a non-default script name, Aspire fails at publish time with a clear error rather than silently emitting an image that ignores the requested script: |
| ```csharp title="AppHost.cs" | ||
| builder | ||
| .AddJavaScriptApp("js", "./js", runScriptName: "migrate") | ||
| .WithBun() | ||
| .PublishAsDockerFile(container => container |
IEvangelist
left a comment
There was a problem hiding this comment.
Summary
Review generated by running the doc-tester skill against the changed page in this PR.
I checked out pr-1014, started the docs site locally with aspire start --isolated against the AppHost in this worktree, and read the rendered page at /deployment/javascript-apps/#run-script-and-existing-dockerfile-conflict in Playwright as a new user would. I followed the skill's user‑centric methodology: only the documentation site was consulted to validate behavior; nothing was inferred from Aspire source.
Net assessment: the new subsection lands cleanly. The added narrative, error block, two‑option resolution, code samples on both tabs, and the new bullet under "Common mistakes" all render correctly, are internally consistent, and use API surface that matches established patterns elsewhere on the same page. Two minor nits and one knowledge gap below — none of them block.
Verdict: Approve.
What I verified
| Check | Result |
|---|---|
Page renders at /deployment/javascript-apps/ |
✅ |
New anchor #run-script-and-existing-dockerfile-conflict resolves and is reachable from the in-page "On this page" nav and from the section breadcrumb |
✅ |
| Section heading level (H3 under the H2 "What JavaScript app resources mean in production") matches its sibling "Build-only container validation" | ✅ |
| C# code sample renders with correct syntax highlighting in the C# tab | ✅ |
TypeScript code sample renders with correct syntax highlighting in the TypeScript tab; switching tabs updates ?aspire-lang=typescript via the shared syncKey='aspire-lang' |
✅ |
Quoted error message in the text code block renders verbatim and matches what the PR body says Aspire throws |
✅ |
New "Common mistakes" bullet renders alongside the existing list with consistent formatting and terminology (runScriptName, .WithRunScript(...), PublishAsDockerFile(...)) |
✅ |
AddJavaScriptApp("js", "./js", runScriptName: "migrate") — same 3‑arg runScriptName: overload pattern that the rest of deployment/javascript-apps.mdx already uses (e.g. AddViteApp("react", "./frameworks/react", runScriptName: "dev"), AddNextJsApp("nextjs", "./frameworks/nextjs", runScriptName: "dev")) |
✅ |
WithBun() / withBun() matches usage in integrations/frameworks/javascript.mdx and integrations/frameworks/bun-apps.mdx |
✅ |
WithEntrypoint("bun") matches the .WithEntrypoint("/bin/sh") pattern shown in architecture/resource-api-patterns.mdx and architecture/resource-examples.mdx |
✅ |
| No internal links were added by this change; nothing to validate for trailing‑slash / target‑exists | ✅ |
| Editorial polish (grammar, spelling, capitalization, "Dockerfile" vs "dockerfile" consistency) | ✅ |
Findings
Nit — TS publishAsDockerFile callback signature is new shape for this doc
Severity: nit (advisory)
Location: src/frontend/src/content/docs/deployment/javascript-apps.mdx, lines 1252‑1260
The new TS snippet uses a configure‑style callback that receives a container builder:
.publishAsDockerFile(async container => {
container.withEntrypoint('bun');
container.withArgs(['src/migrate.ts']);
});Every other TypeScript publishAsDockerFile call elsewhere in this same page (lines 617, 674) — and the only other one on the site at app-host/executable-resources.mdx (lines 298, 337) — uses the no‑argument form:
.publishAsDockerFile(async () => {});So the callback‑with‑container shape is correct (it mirrors the C# overload right above it), but this is the first place in the docs that demonstrates it for TS. A reader who has only seen the no‑arg form may briefly wonder whether the parameter is real. A one‑line lead‑in such as "the callback receives the container builder so you can configure it directly" would smooth this over, or alternatively normalize the existing publishAsDockerFile(async () => {}) examples in this file to also show the parameter when relevant. Not blocking.
Nit — Both samples start mid‑pipeline
Severity: nit (advisory)
Location: lines 1240‑1247 (C#) and 1252‑1260 (TS)
Both code blocks begin with builder.… / await builder.… without showing the surrounding var builder = DistributedApplication.CreateBuilder(args); / const builder = await createBuilder(); and the closing builder.Build().Run(); / await builder.build().run();. The immediately preceding "Build-only container validation" example (lines 1188‑1215) shows the full builder bootstrap; the new snippets are shorter. This is consistent with several earlier inline examples in the same file (e.g. line 593‑596) so I'm flagging it as advisory only — the truncated form helps the snippet focus on the conflict resolution, which is the right tradeoff.
Knowledge gap — TS API surface for publishAsDockerFile is not documented on the site
What I needed to know: Does the TS publishAsDockerFile accept an async (container) => … callback whose argument exposes withEntrypoint and withArgs?
Source of my knowledge: I confirmed the C# PublishAsDockerFile(container => container.WithEntrypoint(…).WithArgs(…)) shape against architecture/resource-api-patterns.mdx and architecture/resource-examples.mdx. For TS, I could not find a published API reference on the docs site under /reference/ or anywhere else that pins the callback signature. As a new user following only the docs, I would have to trust the example.
User impact: TS users won't be able to verify the callback contract against a reference. They'll likely succeed by copy‑paste, but they can't discover that, say, container.withImage(...) or container.withBuildArg(...) are also reachable from the same callback.
Recommendation: Reasonable to assume for this PR; opening or referencing a TS API reference page for publishAsDockerFile would be a follow‑up doc task and is out of scope here.
Suggested wording (optional)
A small clarification could be added inline above the TS tab without rewriting the diff:
The
publishAsDockerFilecallback receives the container resource builder, which you can configure with methods likeWithEntrypoint(...)/withEntrypoint(...)andWithArgs(...)/withArgs(...).
This would also pre‑answer the "what else can I call on container?" question for both C# and TS readers.
Things explicitly tested
- Navigated to
http://localhost:62292/deployment/javascript-apps/(local frontend resource URL discovered viaaspire resources --format Json). - Confirmed
document.querySelector('#run-script-and-existing-dockerfile-conflict')resolves to anH3with text "Run script and existing Dockerfile conflict". - Read the rendered error code block — it matches the PR's quoted text character‑for‑character.
- Switched between the C# and TypeScript tabs on the new section. The shared
syncKey='aspire-lang'propagates across the whole page as expected. - Confirmed the new entry appears in the page's "On this page" sidebar navigation as
Run script and existing Dockerfile conflict. - Confirmed the new "Common mistakes" bullet renders inside the existing
<ul>without breaking formatting.
Out of scope / not tested
- I did not actually trigger the runtime conflict against a live
AddJavaScriptApp+Dockerfilerepo, because that would require an Aspire CLI build that includes the change from microsoft/aspire#16969 (the source change this PR documents). The PR body says the behavior is new in13.4, andrelease/13.4is the base branch, so the documented behavior matches the targeted release. - I did not run the docs build/lint locally — CI on the PR is already green.
Generated by the doc‑tester skill in a local worktree of microsoft/aspire.dev, against the rendered docs site started with aspire start --isolated.
Documents changes from microsoft/aspire#16969
Authored by
@sebastienros.Targeting
release/13.4based on the source PR milestone13.4(exact match).Why this PR is needed
Aspire 13.4 introduces publish-time validation that fails fast when
AddJavaScriptAppis configured with an explicitrunScriptNameor.WithRunScript(...)but the app directory already contains a user-authoredDockerfile. Previously, Aspire would silently ignore the requested run script and use the DockerfileENTRYPOINTinstead. Now it throws aDistributedApplicationExceptionwith a clear error message and guidance on how to fix the conflict.This is a user-visible behavior change that requires documentation so developers understand why they get the error and what their resolution options are.
What was added
A new subsection "Run script and existing Dockerfile conflict" under the "What JavaScript app resources mean in production" section in
deployment/javascript-apps.mdx. The subsection:PublishAsDockerFile(...)and set the container entrypoint explicitly (with C# and TypeScript examples).runScriptName("dev") without custom arguments is always allowed.A new bullet was also added to the "Common mistakes" section.
Files modified
src/frontend/src/content/docs/deployment/javascript-apps.mdx— updated (new subsection + new common-mistakes bullet)