feat(node): add build output annotation#13999
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 13999Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 13999" |
|
@dotnet-policy-service agree |
There was a problem hiding this comment.
Pull request overview
This PR adds a build output annotation for Node.js apps to inform the default Docker publisher which files need to be copied to the final container image. The feature allows developers to specify which paths from the build process should be included when containerizing Node.js applications.
Changes:
- Added
JavaScriptBuildOutputAnnotationclass to specify build output paths - Added
WithBuildOutputextension method for configuring build output paths - Modified Docker generation logic to use annotation-specified paths instead of copying all
/appcontent - Updated playground example to demonstrate the new feature with dependency updates
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| JavaScriptBuildOutputAnnotation.cs | New annotation class to specify build output paths with validation |
| JavaScriptHostingExtensions.cs | Added WithBuildOutput method and updated Docker generation to use annotation paths |
| AppHost.cs | Updated to use the new WithBuildOutput API |
| package.json | Updated OpenTelemetry dependencies and added tsdown build tool |
| pnpm-lock.yaml | Dependency lockfile updates |
| tsdown.config.ts | New build configuration file |
| run.mjs | New entry point file |
| Dockerfile | Removed (now using auto-generated Docker support) |
| .dockerignore | Added to exclude dist and node_modules |
|
This needs tests too. |
| /// <summary> | ||
| /// Represents an annotation that specifies the output file/directory paths to be included in the final image. | ||
| /// </summary> | ||
| public sealed class JavaScriptBuildOutputAnnotation : IResourceAnnotation |
There was a problem hiding this comment.
One thing that jumped out at me is that this annotation isn't respected for "non-Node" javascript apps (i.e. client apps). I wonder if we should give this annotation a different name to differentiate it. But I'm not sure what that name should be.
The client apps already have an annotation for this - ContainerFilesSourceAnnotation - which is a general annotation that indicates which files from one container should be copied to another.
Maybe that fits here too? Would it make sense to reuse ContainerFilesSourceAnnotation?
There was a problem hiding this comment.
I already thought of making it also work with "non-Node" javascript apps, but the default Dockerfile builder for client apps has no build stage. Should we add build stage in case JavaScriptBuildScriptAnnotation/JavaScriptBuildOutputAnnotation exist in the resource? I think it would be better to have a common Dockerfile builder for both Node & JavaScript as they already very similar.
As of ContainerFilesSourceAnnotation in the client apps:
I found that the above has no effect on the output Dockerfile. maybe I'm missing something
There was a problem hiding this comment.
Node and JavaScript dockerfiles are similar, but have different purposes.
The Node app is "runnable" - it has a web server in it and can host the application.
The client-side JavaScript apps aren't runnable by themselves, they need a host (asp.net, yarp, nginx, node, etc.). That's why they only have 1 stage: a build stage. Someone else comes along and picks up the files that were built and puts them in the host.
There was a problem hiding this comment.
I think a new annotation here is fine. If you have thoughts on a more specific name, we should come up with the best name. But this one will work if there isn't anything better.
There was a problem hiding this comment.
It would be better to keep the name as is, I'm sure client apps can benefit from it, just need to figure out how.
There was a problem hiding this comment.
I got an idea in how can client apps benefit from it, should I implement it here or in another pr ?
There was a problem hiding this comment.
Let's keep this PR focused. It still needs tests before this can be merged.
What is the idea?
There was a problem hiding this comment.
Right now the default JavaScript builder have one stage that contains all the app files (source, dependencies, build output ...). When used with a host (by PublishWithContainerFiles) it would copy /app/dist (defined by ContainerFilesSourceAnnotation) to the host destination.
The problem is it always assumes that all JavaScript apps output to /app/dist even if it has no build script.
To resolve this issue, we could have a build stage for client apps, and final stage that would take the needed files (configurable with WithBuildOutput) from the build stage, e.g.:
FROM node:22-slim AS build
WORKDIR /app
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm npm ci
COPY . .
RUN npm run build
FROM node:22-slim
WORKDIR /app
COPY --from=build /app/dist /app # Defined by JavaScriptBuildOutputAnnotationNow we could update the ContainerFilesSourceAnnotation to point to /app and when it used with a host it would only contains the build output.
Note that currently the JavaScriptBuildOutputAnnotation generate COPY command that match source with destination, e.g.:
COPY --from=build /app/dist /app/dist
There is a few reasons I did it this way:
- Preserve the app directory hierarchy.
- Node app
scriptPathis expected to be relative to the app directory. - Support multiple output paths (as demonstrated in e6c09fc#diff-7a1ccee4a1a881d9ce4e94f711b0ae94485dd8ed89fd18a5f539c7a4d5131072R20)
If we would use JavaScriptBuildOutputAnnotation with client apps (as mentioned above) while avoiding breaking behavior, when should make it only accepts one output directory path, and document that when WithBuildOutput is used with Node app scriptPath should be relative to the output directory not the app directory.
There was a problem hiding this comment.
I've implemented the client apps use of JavaScriptBuildOutputAnnotation on a new branch 937f144 .
Instead of adding extra build stage I was thinking of mapping JavaScriptBuildOutputAnnotation to ContainerFilesSourceAnnotation , but I'm not sure what is the right place to add this code:
aspire/src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs
Lines 458 to 465 in 937f144
Description
Add build output annotation that can be used with Node apps to inform the default docker publisher which files need to be copied to the final container image.
Fixes #13907
Checklist
<remarks />and<code />elements on your triple slash comments?doc-ideatemplatebreaking-changetemplatediagnostictemplate