Skip to content

Add JavaScript publish methods, AddNextJsApp, and switch to YARP#15736

Merged
davidfowl merged 4 commits intomainfrom
davidfowl/default-js-runtime
Apr 3, 2026
Merged

Add JavaScript publish methods, AddNextJsApp, and switch to YARP#15736
davidfowl merged 4 commits intomainfrom
davidfowl/default-js-runtime

Conversation

@davidfowl
Copy link
Copy Markdown
Contributor

@davidfowl davidfowl commented Mar 31, 2026

Description

Add JavaScript publish methods and AddNextJsApp to Aspire.Hosting.JavaScript, using YARP for static site serving.

Publish methods (generic patterns)

  • PublishAsStaticWebsite — YARP reverse proxy serving built static files with optional API reverse-proxy via service discovery. Accepts PublishAsStaticWebsiteOptions for OutputPath, StripPrefix, and TargetEndpointName.
  • PublishAsNodeServer — Node.js runtime container running a self-contained build artifact directly (SvelteKit, TanStack Start). Sets HOST=0.0.0.0 and HOSTNAME=0.0.0.0 for container networking.
  • PublishAsNpmScript — Multi-stage Dockerfile with production node_modules, using package manager script as entrypoint with exec for proper SIGTERM handling. Sets HOST=0.0.0.0 and HOSTNAME=0.0.0.0.

Framework-specific method

  • AddNextJsApp — Dedicated method for Next.js applications:
    • Run mode: Starts next dev with correct port binding (-p, not Vite's --port)
    • Publish mode: Generates a multi-stage Dockerfile using Next.js standalone output
    • Deploy-time validation: Checks next.config.ts/js/mjs for output: "standalone" via pipeline prereq step. Opt out with .DisableBuildValidation().

API design

  • Two C# overloads for PublishAsStaticWebsite: no proxy + with proxy (apiPath, apiTarget)
  • Options pattern: Action<PublishAsStaticWebsiteOptions>? for OutputPath, StripPrefix (default: false), TargetEndpointName
  • apiTarget accepts IResourceBuilder<IResourceWithServiceDiscovery> — YARP resolves endpoints via service discovery, preferring HTTPS
  • Polyglot overload for TypeScript/Python/Java with all-optional params
  • All publish methods marked [Experimental]
  • ProductionInstallArgs moved to JavaScriptInstallCommandAnnotation per review feedback
  • JavaScriptContainerImageTags.cs for YARP image tags (tooling-compatible)

Key technical decisions

  • YARP instead of Caddy — native HTTPS, service discovery, OTEL support. No Caddyfile generation or path-matching workarounds needed.
  • StripPrefix defaults to false — forwards the full path to the backend. Opt in with stripPrefix: true.
  • Endpoint target port set to 5000 for PublishAsStaticWebsite to match YARP image default.
  • HOST=0.0.0.0 and HOSTNAME=0.0.0.0 set via WithEnvironment (not Dockerfile) on PublishAsNodeServer and PublishAsNpmScript so containers bind to all interfaces.

E2E Validation

All 10+ framework configurations deployed and verified locally with aspire deploy to Docker Compose:

Framework Method Result
Vite PublishAsStaticWebsite + API proxy
React PublishAsStaticWebsite + API proxy
Vue PublishAsStaticWebsite + API proxy
Astro (static) PublishAsStaticWebsite
SvelteKit PublishAsNodeServer ✅ SSR
TanStack Start PublishAsNodeServer ✅ SSR
Next.js AddNextJsApp (standalone) ✅ SSR
Nuxt PublishAsNpmScript ✅ SSR
Astro SSR PublishAsNpmScript ✅ SSR
Remix PublishAsNpmScript ✅ SSR

E2E test (AllPublishMethodsBuildDockerImages) verifies pipeline deploys and services respond, with checked-in verify.sh for diagnostics.

Fixes #12697

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <see> and <code/> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
    • No
  • Does the change require an update in our Aspire docs?

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 31, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 15736

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 15736"

@davidfowl davidfowl changed the title Add JavaScript publish methods: PublishAsStaticWebsite, PublishAsNodeServer, PublishAsNpmScript, PublishAsNextStandalone Add JavaScript publish methods and AddNextJsApp Apr 1, 2026
Comment thread playground/AspireWithJavaScript/AspireJavaScript.AppHost/AppHost.cs Outdated
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs Outdated
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs
/// </example>
/// </remarks>
[AspireExport("addNextJsApp", Description = "Adds a Next.js application resource")]
public static IResourceBuilder<NextJsAppResource> AddNextJsApp(this IDistributedApplicationBuilder builder, [ResourceName] string name, string appDirectory, string runScriptName = "dev")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a slippery slope, are we going to ever see APIs like AddAngularApp, AddVueApp, or AddSvelte... you know? What makes NextJs special?

Copy link
Copy Markdown
Contributor Author

@davidfowl davidfowl Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the publish pattern can't be expressed with the generic methods, the framework needs its own Add*. That's the litmus test.

Next.js passes that test:

  1. Publish is unique — 3-COPY pattern (public/, .next/standalone/, .next/static/) can't be expressed with publishAsNodeServer or publishAsNpmScript
  2. Run mode is wrong on addViteApp — Next.js uses next dev -p , not Vite's --port
  3. Needs HOSTNAME=0.0.0.0 — container binding quirk

Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs
@davidfowl davidfowl marked this pull request as ready for review April 1, 2026 06:36
Copilot AI review requested due to automatic review settings April 1, 2026 06:36
@davidfowl davidfowl force-pushed the davidfowl/default-js-runtime branch from 2936940 to ada8362 Compare April 1, 2026 06:39
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds deployable JavaScript publish patterns to Aspire.Hosting.JavaScript (addressing #12697) and introduces a Next.js-specific AddNextJsApp API to support both run-mode (next dev) and publish-mode (standalone output) workflows.

Changes:

  • Add publish APIs for JS apps: PublishAsStaticWebsite, PublishAsNodeServer, and PublishAsNpmScript.
  • Add AddNextJsApp + supporting resource/annotations and Dockerfile generation logic.
  • Expand unit/snapshot coverage and add a CLI E2E test with checked-in JS fixtures.

Reviewed changes

Copilot reviewed 28 out of 30 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs Implements new publish methods, Next.js support, and Dockerfile generation updates.
src/Aspire.Hosting.JavaScript/NextJsAppResource.cs Adds a dedicated public resource type for Next.js apps.
src/Aspire.Hosting.JavaScript/JavaScriptStaticWebsiteAnnotation.cs Adds internal annotation to drive static website publish behavior.
src/Aspire.Hosting.JavaScript/JavaScriptNodeServerAnnotation.cs Adds internal annotation to drive node-server publish behavior.
src/Aspire.Hosting.JavaScript/JavaScriptNpmScriptAnnotation.cs Adds internal annotation to drive npm-script runtime publish behavior.
src/Aspire.Hosting.JavaScript/JavaScriptNextStandaloneAnnotation.cs Adds internal marker annotation to drive Next.js standalone publish behavior.
tests/Aspire.Hosting.JavaScript.Tests/NodeJsPublicApiTests.cs Adds argument validation tests for new public APIs.
tests/Aspire.Hosting.JavaScript.Tests/AddViteAppTests.cs Adds publish-mode Dockerfile verification tests (static, node server, Next standalone).
tests/Aspire.Hosting.JavaScript.Tests/AddJavaScriptAppTests.cs Adds publish-mode Dockerfile verification tests for all new publish patterns.
tests/Aspire.Hosting.JavaScript.Tests/Snapshots/AddViteAppTests.VerifyDockerfileWhenPublishedAsStaticWebsite.verified.txt Snapshot for static-website Dockerfile output.
tests/Aspire.Hosting.JavaScript.Tests/Snapshots/AddViteAppTests.VerifyDockerfileWhenPublishedAsStaticWebsiteWithCustomOutputPath.verified.txt Snapshot for static-website Dockerfile with custom output path.
tests/Aspire.Hosting.JavaScript.Tests/Snapshots/AddViteAppTests.VerifyDockerfileWhenPublishedAsNodeServer.verified.txt Snapshot for node-server Dockerfile output.
tests/Aspire.Hosting.JavaScript.Tests/Snapshots/AddViteAppTests.VerifyDockerfileWhenPublishedAsNextStandalone.verified.txt Snapshot for Next.js standalone Dockerfile output.
tests/Aspire.Cli.EndToEnd.Tests/JavaScriptPublishTests.cs New E2E test that initializes a TS AppHost, adds packages, deploys, and builds images.
tests/Aspire.Cli.EndToEnd.Tests/Fixtures/JsPublish/api/package.json Fixture backend API package config.
tests/Aspire.Cli.EndToEnd.Tests/Fixtures/JsPublish/api/server.js Fixture backend API implementation.
tests/Aspire.Cli.EndToEnd.Tests/Fixtures/JsPublish/staticsite/package.json Fixture static-site package config.
tests/Aspire.Cli.EndToEnd.Tests/Fixtures/JsPublish/staticsite/index.html Fixture static-site page calling /api/*.
tests/Aspire.Cli.EndToEnd.Tests/Fixtures/JsPublish/nodeserver/package.json Fixture node-server package config.
tests/Aspire.Cli.EndToEnd.Tests/Fixtures/JsPublish/nodeserver/server.js Fixture node-server implementation.
tests/Aspire.Cli.EndToEnd.Tests/Fixtures/JsPublish/npmscript/package.json Fixture npm-script package config.
tests/Aspire.Cli.EndToEnd.Tests/Fixtures/JsPublish/npmscript/server.js Fixture npm-script server implementation.
tests/Aspire.Cli.EndToEnd.Tests/Fixtures/JsPublish/nextjs/tsconfig.json Next.js fixture TypeScript config.
tests/Aspire.Cli.EndToEnd.Tests/Fixtures/JsPublish/nextjs/public/.gitkeep Ensures public/ exists for Next.js standalone output.
tests/Aspire.Cli.EndToEnd.Tests/Fixtures/JsPublish/nextjs/package.json Next.js fixture dependencies/scripts.
tests/Aspire.Cli.EndToEnd.Tests/Fixtures/JsPublish/nextjs/package-lock.json Next.js fixture lockfile for deterministic installs.
tests/Aspire.Cli.EndToEnd.Tests/Fixtures/JsPublish/nextjs/next.config.ts Enables output: 'standalone' for the Next.js fixture.
tests/Aspire.Cli.EndToEnd.Tests/Fixtures/JsPublish/nextjs/app/page.tsx Next.js fixture page.
tests/Aspire.Cli.EndToEnd.Tests/Fixtures/JsPublish/nextjs/app/layout.tsx Next.js fixture layout.
playground/AspireWithJavaScript/AspireJavaScript.AppHost/AppHost.cs Demonstrates usage of the new publish methods in the playground AppHost.
Files not reviewed (1)
  • tests/Aspire.Cli.EndToEnd.Tests/Fixtures/JsPublish/nextjs/package-lock.json: Language not supported

Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs Outdated
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs Outdated
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs Outdated
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs Outdated
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs Outdated
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs Outdated
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs Outdated
Comment thread tests/Aspire.Hosting.JavaScript.Tests/AddViteAppTests.cs
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs
// Example: SvelteKit with adapter-node builds to build/index.js, Nuxt/TanStack build to .output/server/index.mjs
// Uncomment the following if you add a SvelteKit or Nuxt app to this playground:
// builder.AddViteApp("sveltekit", "../SvelteKitApp")
// .PublishAsNodeServer(entryPoint: "build/index.js", outputPath: "build");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand this scenario. Why doesn't this use AddNodeApp?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dev time uses the vite dev server, publish time uses a node based server.

})
.WithHttpEndpoint(env: "PORT")
.WithAnnotation(new JavaScriptPublishModeAnnotation(JavaScriptPublishMode.NextStandalone))
.ClearContainerFilesSources()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean I can't use AddNextJsApp and pass it into server.PublishWithContainerFiles?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right. Those do not compose, just like it doesnt work with addNodeApp. NextJS does support emitting a static site, but this doesn't cover that scenario.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are users supposed to know what they can use PublishWithContainerFiles and what they can't?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My folllow ups are to:

  • My first plan is to get rid of these pits of failure https://aspire.dev/deployment/javascript-apps/#pits-of-failure. That means throwing errors when you don't use PublishWithContainerFiles, or one of the above methods.
  • Next I'll look into invalid combinations and see if we shoud constrain these methods to specific types (just vite and JavaScript?)

Comment thread playground/AspireWithJavaScript/AspireJavaScript.AppHost/AppHost.cs Outdated
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs Outdated
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptPackageManagerAnnotation.cs Outdated
@davidfowl davidfowl force-pushed the davidfowl/default-js-runtime branch 3 times, most recently from e3111a6 to 3e78970 Compare April 2, 2026 07:48
Copy link
Copy Markdown
Member

@JamesNK JamesNK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the JavaScript publish methods and AddNextJsApp additions. Found 5 issues:

  • 1 definite bug in the E2E test (swapped nodeserver/npmscript assertions)
  • 1 definite bug in PublishAsStaticWebsiteCore (apiPath "/" produces a catch-all that shadows static files)
  • 1 likely issue with signal propagation in NpmScript containers (sh -c without exec)
  • 2 design concerns in ValidateNextJsStandaloneOutput (silent pass on missing config file; overly loose keyword match)

Comment thread tests/Aspire.Cli.EndToEnd.Tests/JavaScriptPublishTests.cs Outdated
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptPackageManagerAnnotation.cs Outdated
/// </para>
/// </remarks>
[AspireExportIgnore(Reason = "Use the polyglot-compatible overload instead.")]
public static IResourceBuilder<TResource> PublishAsStaticWebsite<TResource>(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you want to make these [Experimental] for a release?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so yeah

[AspireExportIgnore(Reason = "Use the polyglot-compatible overload instead.")]
public static IResourceBuilder<TResource> PublishAsStaticWebsite<TResource>(
this IResourceBuilder<TResource> builder,
Action<PublishAsStaticWebsiteOptions>? configure = null)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why a callback and not just take PublishAsStaticWebsiteOptions??

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you seen our APIs eric, we love callbacks! Seriously though its usually when the control could be deferred. This one is pretty simple though.

Comment thread src/Aspire.Hosting.JavaScript/JavaScriptPackageManagerAnnotation.cs Outdated
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs Outdated
Copy link
Copy Markdown
Member

@joperezr joperezr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Findings (High Severity)

Reviewed across the Dockerfile generation logic in JavaScriptHostingExtensions.cs. Five issues that could cause runtime failures for users:


1️⃣ glibc → musl ABI mismatch (build=slim, runtime=alpine)

Lines 678, 743, 757, 811

The build stage defaults to node:22-slim (Debian/glibc, line 678) but the runtime stages for NodeServer, NpmScript, and NextStandalone all default to node:22-alpine (musl). Apps with native Node addons (sharp, sqlite3, Prisma engines, etc.) will compile for glibc during the build and then crash on the musl-based runtime.

Consider aligning the runtime distro with the build distro (e.g. both slim or both alpine), or documenting this limitation.


2️⃣ PublishAsNpmScript with pnpm/bun: package manager missing in runtime image

Lines 806, 1390–1398

The NpmScript entrypoint can emit pnpm run start or bun run start, but:

  • pnpm is only enabled via corepack enable pnpm in the build/prod-deps stages (InitializeDockerBuildStage at line 1397) — it's never run in the runtime stage.
  • bun only sets BuildImage = "oven/bun:1" but the runtime still defaults to node:*-alpine.

The container will fail immediately on start because the package manager binary doesn't exist in the runtime image.


3️⃣ Yarn Berry (v2+) ProductionInstallArgs is broken

Line 1337

ProductionInstallArgs is hardcoded to "install --production" for all Yarn versions, but Yarn Berry (v2+) doesn't recognize the --production flag. The code already detects Berry vs v1 for regular install args in GetDefaultYarnInstallArgs() (lines 1345–1365) using --immutable for Berry and --frozen-lockfile for v1. Should this use the same detection to conditionally set the production args? For Berry, the typical approach is NODE_ENV=production yarn install (without --production).


4️⃣ sh -c entrypoint with unescaped user strings

Lines 796–806

startScriptName and runScriptArguments are string-concatenated into a raw sh -c "exec {runCommand}" entrypoint without any shell escaping. While the risk is low in practice (developers control these values), any shell metacharacters (;, &&, $(), etc.) in runScriptArguments would be interpreted by the shell. Consider using exec-form ENTRYPOINT without sh -c, or sanitizing/quoting the values.


5️⃣ devDependencies leak into NpmScript runtime image

Lines 803–804

Line 803 copies the entire /app from the build stage (including node_modules with dev deps), then line 804 overlays prod-only node_modules on top. However, Docker COPY merges directories — it doesn't delete files that only exist in the destination. Dev-only packages from the build stage survive into the final image.

Consider either excluding node_modules from the first copy (e.g., via .dockerignore in the build context or a selective copy), or adding RUN rm -rf node_modules before the prod-deps overlay.

Add PublishAsStaticWebsite, PublishAsNodeServer, PublishAsNpmScript,
and AddNextJsApp to Aspire.Hosting.JavaScript.

PublishAsStaticWebsite:
- Uses YARP reverse proxy image for static file serving
- Optional API reverse-proxy with service discovery (accepts resource,
  YARP resolves HTTPS/HTTP endpoints automatically)
- Options pattern: OutputPath, StripPrefix, TargetEndpointName
- Two C# overloads (no proxy / with proxy) + polyglot overload
- Bridges PORT to ASPNETCORE_HTTP_PORTS for Kestrel

PublishAsNodeServer:
- Node.js runtime container running a self-contained build artifact
- exec in entrypoint for proper SIGTERM forwarding

PublishAsNpmScript:
- Multi-stage Dockerfile with production node_modules
- Package-manager aware (npm/yarn/pnpm/bun)
- ProductionInstallArgs on JavaScriptInstallCommandAnnotation

AddNextJsApp:
- Standalone 3-COPY Dockerfile pattern
- Deploy-time validation: checks next.config for 'standalone'
- DisableBuildValidation() opt-out via pipeline prereq step

All publish methods marked [Experimental].
E2E test verifies pipeline deploys and API responds correctly.

Fixes #12697

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@davidfowl davidfowl force-pushed the davidfowl/default-js-runtime branch from e66f347 to b661852 Compare April 3, 2026 01:39
- verify.sh is a checked-in fixture (no generation, no line ending issues)
- Phase 1: captures docker state, all curl responses, ports, and
  container logs unconditionally to diagnostics/
- Phase 2: asserts expected content in captured responses
- On failure, CaptureWorkspaceOnFailure uploads diagnostics/ with
  all raw responses for debugging

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@davidfowl davidfowl changed the title Add JavaScript publish methods and AddNextJsApp Add JavaScript publish methods, AddNextJsApp, and switch to YARP Apr 3, 2026
CopyFixtures only copied subdirectories, missing verify.sh at the
fixtures root. Now copies root files first, then subdirectories.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptContainerImageTags.cs Outdated
Comment thread src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs Outdated
…RP tags, publish-mode-only HOST

- Use lockfile-aware install for prod-deps stage: ProductionInstallArgs
  is now just the flag (--omit=dev, --production, --prod), appended to
  the base install args. npm gets 'ci --omit=dev', pnpm gets
  'install --frozen-lockfile --prod', yarn gets 'install --immutable
  --production'. (eerhardt feedback)
- Source-share YarpContainerImageTags.cs via Compile Include instead of
  duplicating in JavaScriptContainerImageTags.cs. (eerhardt feedback)
- Move HOST/HOSTNAME to publish-mode-only WithEnvironment — not needed
  in dev mode where apps run on the host, not in containers. Remove
  from Dockerfile ENV to avoid duplication.
- Add IsPublishMode early-return guards to PublishAsNodeServer and
  PublishAsNpmScript, matching PublishAsStaticWebsite pattern.
- AddNextJsApp: publish annotation + HOSTNAME conditional on publish
  mode, WithOtlpExporter stays in both modes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 3, 2026

🎬 CLI E2E Test Recordings — 55 recordings uploaded (commit 811273f)

View recordings
Test Recording
AddPackageInteractiveWhileAppHostRunningDetached ▶️ View Recording
AddPackageWhileAppHostRunningDetached ▶️ View Recording
AgentCommands_AllHelpOutputs_AreCorrect ▶️ View Recording
AgentInitCommand_DefaultSelection_InstallsSkillOnly ▶️ View Recording
AgentInitCommand_MigratesDeprecatedConfig ▶️ View Recording
AllPublishMethodsBuildDockerImages ▶️ View Recording
AspireAddPackageVersionToDirectoryPackagesProps ▶️ View Recording
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps ▶️ View Recording
Banner_DisplayedOnFirstRun ▶️ View Recording
Banner_DisplayedWithExplicitFlag ▶️ View Recording
Banner_NotDisplayedWithNoLogoFlag ▶️ View Recording
CertificatesClean_RemovesCertificates ▶️ View Recording
CertificatesTrust_WithNoCert_CreatesAndTrustsCertificate ▶️ View Recording
CertificatesTrust_WithUntrustedCert_TrustsCertificate ▶️ View Recording
ConfigSetGet_CreatesNestedJsonFormat ▶️ View Recording
CreateAndRunAspireStarterProject ▶️ View Recording
CreateAndRunAspireStarterProjectWithBundle ▶️ View Recording
CreateAndRunEmptyAppHostProject ▶️ View Recording
CreateAndRunJavaEmptyAppHostProject ▶️ View Recording
CreateAndRunJsReactProject ▶️ View Recording
CreateAndRunPythonReactProject ▶️ View Recording
CreateAndRunTypeScriptEmptyAppHostProject ▶️ View Recording
CreateAndRunTypeScriptStarterProject ▶️ View Recording
CreateJavaAppHostWithViteApp ▶️ View Recording
CreateStartAndStopAspireProject ▶️ View Recording
CreateTypeScriptAppHostWithViteApp ▶️ View Recording
DescribeCommandResolvesReplicaNames ▶️ View Recording
DescribeCommandShowsRunningResources ▶️ View Recording
DetachFormatJsonProducesValidJson ▶️ View Recording
DoctorCommand_DetectsDeprecatedAgentConfig ▶️ View Recording
DoctorCommand_WithSslCertDir_ShowsTrusted ▶️ View Recording
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted ▶️ View Recording
GlobalMigration_HandlesCommentsAndTrailingCommas ▶️ View Recording
GlobalMigration_HandlesMalformedLegacyJson ▶️ View Recording
GlobalMigration_PreservesAllValueTypes ▶️ View Recording
GlobalMigration_SkipsWhenNewConfigExists ▶️ View Recording
GlobalSettings_MigratedFromLegacyFormat ▶️ View Recording
InvalidAppHostPathWithComments_IsHealedOnRun ▶️ View Recording
LegacySettingsMigration_AdjustsRelativeAppHostPath ▶️ View Recording
LogsCommandShowsResourceLogs ▶️ View Recording
PsCommandListsRunningAppHost ▶️ View Recording
PsFormatJsonOutputsOnlyJsonToStdout ▶️ View Recording
PublishWithDockerComposeServiceCallbackSucceeds ▶️ View Recording
RestoreGeneratesSdkFiles ▶️ View Recording
RestoreSupportsConfigOnlyHelperPackageAndCrossPackageTypes ▶️ View Recording
RunFromParentDirectory_UsesExistingConfigNearAppHost ▶️ View Recording
RunWithMissingAwaitShowsHelpfulError ▶️ View Recording
SecretCrudOnDotNetAppHost ▶️ View Recording
SecretCrudOnTypeScriptAppHost ▶️ View Recording
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels ▶️ View Recording
StopAllAppHostsFromAppHostDirectory ▶️ View Recording
StopAllAppHostsFromUnrelatedDirectory ▶️ View Recording
StopNonInteractiveMultipleAppHostsShowsError ▶️ View Recording
StopNonInteractiveSingleAppHost ▶️ View Recording
StopWithNoRunningAppHostExitsSuccessfully ▶️ View Recording

📹 Recordings uploaded automatically from CI run #23949654140

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.

JavaScript/Vite Apps Are Always Build-Only - No Way to Deploy as Standalone Services

7 participants