Skip to content

Conversation

@eerhardt
Copy link
Member

@eerhardt eerhardt commented Oct 30, 2025

Description

Refactor JavaScript Integration

  • Obsolete AddNpmApp.
  • Add JavaScriptAppResource and AddJavaScriptApp extension method
  • Refactor AddViteApp to be a specialization of AddJavaScriptApp
  • Replace NodeInstallerResource with JavaScriptInstallerResource
  • Add JavaScriptPackageManagerAnnotation to handle different package managers
  • Replace JavaScriptRunCommandAnnotation with JavaScriptRunScriptAnnotation
  • Replace JavaScriptBuildCommandAnnotation with JavaScriptBuildScriptAnnotation
  • Adds WithContainerFilesSource extension method for configuring container file paths

Contributes to #8350

Checklist

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

- Obsolete AddNpmApp.
- Add JavaScriptAppResource and AddJavaScriptApp extension method
- Refactor AddViteApp to be a specialization of AddJavaScriptApp
- Replace NodeInstallerResource with JavaScriptInstallerResource
- Add JavaScriptPackageManagerAnnotation to handle different package managers
- Replace JavaScriptRunCommandAnnotation with JavaScriptRunScriptAnnotation
- Replace JavaScriptBuildCommandAnnotation with JavaScriptBuildScriptAnnotation

Contributes to dotnet#8350
@eerhardt eerhardt requested a review from mitchdenny as a code owner October 30, 2025 22:30
Copilot AI review requested due to automatic review settings October 30, 2025 22:30
@github-actions
Copy link
Contributor

github-actions bot commented Oct 30, 2025

🚀 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/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 12530

Or

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

Copy link
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

This PR refactors Node.js application hosting in Aspire by renaming core types and introducing a new AddJavaScriptApp method as the primary API for JavaScript applications. The refactoring establishes a cleaner type hierarchy with JavaScriptAppResource as the base class for both Node.js and Vite applications.

Key Changes:

  • Introduces AddJavaScriptApp as the main entry point for JavaScript apps, with AddNpmApp now obsoleted
  • Renames resource types from NodeAppResource/NodeInstallerResource to JavaScriptAppResource/JavaScriptInstallerResource
  • Refactors package manager annotations from storing executable commands to storing script configurations
  • Updates default install commands to use npm ci in publish mode instead of npm install
  • Adds WithContainerFilesSource extension method for configuring container file paths

Reviewed Changes

Copilot reviewed 26 out of 26 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/Aspire.Hosting.NodeJs/JavaScriptAppResource.cs New base resource class for JavaScript applications with service discovery and container files support
src/Aspire.Hosting.NodeJs/NodeAppResource.cs Updated to inherit from JavaScriptAppResource instead of ExecutableResource
src/Aspire.Hosting.NodeJs/ViteAppResource.cs Updated to inherit from JavaScriptAppResource, removed IResourceWithContainerFiles (now on base)
src/Aspire.Hosting.NodeJs/NodeExtensions.cs Major refactoring: added AddJavaScriptApp, obsoleted AddNpmApp, refactored package manager configuration
src/Aspire.Hosting.NodeJs/JavaScriptPackageManagerAnnotation.cs New annotation to track package manager executable and script command
src/Aspire.Hosting.NodeJs/JavaScriptRunScriptAnnotation.cs New annotation for run scripts (replaces JavaScriptRunCommandAnnotation)
src/Aspire.Hosting.NodeJs/JavaScriptBuildScriptAnnotation.cs New annotation for build scripts (replaces JavaScriptBuildCommandAnnotation)
src/Aspire.Hosting.NodeJs/JavaScriptInstallCommandAnnotation.cs Simplified to only store args (command now in JavaScriptPackageManagerAnnotation)
src/Aspire.Hosting.NodeJs/JavaScriptInstallerResource.cs Renamed from NodeInstallerResource
src/Aspire.Hosting/ResourceBuilderExtensions.cs Added WithContainerFilesSource extension method
tests/* Comprehensive test updates to use new API and verify new behavior
playground/* Updated sample applications to use new AddJavaScriptApp API
templates/* Removed explicit WithNpm(install: true) call (now default behavior)

{
// Arguments to the executable often contain physical paths that are not valid in the container
// Clear them out so that the container can be set up with the correct arguments
existingBuilder.WithArgs(c => c.Args.Clear());
Copy link
Member Author

Choose a reason for hiding this comment

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

@davidfowl - this test was failing before this change -

public async Task PublishAsDockerFileConfigureContainer()
{
var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);
using var tempDir = CreateDirectoryWithDockerFile();
var path = tempDir.Path;
var secret = builder.AddParameter("secret", secret: true);
var frontend = builder.AddNpmApp("frontend", path, "watch")
.WithArgs("/usr/foo")
.PublishAsDockerFile(c =>
{
c.WithBuildSecret("buildSecret", secret);
c.WithArgs("/app");
c.WithVolume("vol", "/app/node_modules");
});
// There should be an equivalent container resource with the same name
// as the npm app resource.
var containerResource = Assert.Single(builder.Resources.OfType<ContainerResource>());
Assert.Equal("frontend", containerResource.Name);
var manifest = await ManifestUtils.GetManifest(frontend.Resource, manifestDirectory: path).DefaultTimeout();
var expected =
$$"""
{
"type": "container.v1",
"build": {
"context": ".",
"dockerfile": "Dockerfile",
"secrets": {
"buildSecret": {
"type": "env",
"value": "{secret.value}"
}
}
},
"args": [
"/app"
],
"volumes": [
{
"name": "vol",
"target": "/app/node_modules",
"readOnly": false
}
],
"env": {
"NODE_ENV": "{{builder.Environment.EnvironmentName.ToLowerInvariant()}}"
}
}
""";
var actual = manifest.ToString();
Assert.Equal(expected, actual, ignoreLineEndingDifferences: true, ignoreWhiteSpaceDifferences: true);
}

The issue is that AddJavaScriptApp calls PublishAsDockerFile, then the test calls WithArgs and then PublishAsDockerFile again. The args in the WithArgs call wasn't getting cleared.

@eerhardt eerhardt mentioned this pull request Oct 31, 2025
7 tasks
Clarified npm install command requirement for clean install.
@davidfowl
Copy link
Member

@eerhardt We should default to npm run dev not npm run start

@davidfowl davidfowl merged commit ad6efe8 into dotnet:main Oct 31, 2025
296 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the 13.0 milestone Oct 31, 2025
@eerhardt
Copy link
Member Author

eerhardt commented Oct 31, 2025

@eerhardt We should default to npm run dev not npm run start

Done in #12538

@eerhardt
Copy link
Member Author

/backport to release/13.0

@github-actions
Copy link
Contributor

Started backporting to release/13.0: https://github.com/dotnet/aspire/actions/runs/18970941140

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