Add aspire-py-starter template for Python and JavaScript applications#12136
Conversation
Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com>
Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com>
…e 13.0 Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com>
|
@copilot - Remove the Aspire.png and instead use the one from https://github.com/dotnet/aspire/blob/main/src/Shared/Aspire_icon_256.png. Ensure that the template packages it correctly. |
The Aspire.png in the template was already identical to src/Shared/Aspire_icon_256.png (MD5: 9413c7a1b425b3137eb3f58a926c98f6). I've verified that the template packages it correctly - the file is included in the NuGet package and appears in generated projects with the correct content. |
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 12136Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 12136" |
1 similar comment
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 12136Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 12136" |
|
|
||
| <TemplateFiles Include="$(MSBuildThisFileDirectory)templates\**\*" | ||
| Exclude="$(MSBuildThisFileDirectory)templates\**\bin\**;$(MSBuildThisFileDirectory)templates\**\obj\**;$(MSBuildThisFileDirectory)templates\**\*.csproj"> | ||
| Exclude="$(MSBuildThisFileDirectory)templates\**\bin\**;$(MSBuildThisFileDirectory)templates\**\obj\**;$(MSBuildThisFileDirectory)templates\**\*.csproj;$(MSBuildThisFileDirectory)templates\aspire-apphost-singlefile\**\apphost.cs;$(MSBuildThisFileDirectory)templates\aspire-py-starter\**\apphost.cs"> |
There was a problem hiding this comment.
@copilot - is this change correct? I think it should be reverted.
There was a problem hiding this comment.
I added the exclusions to prevent duplicate packaging errors. Without excluding apphost.cs files from TemplateFiles, the build fails with:
error NU5118: File 'content/templates/aspire-py-starter/13.0/apphost.cs' is not added because the package already contains file 'content/templates/aspire-py-starter/13.0/apphost.cs'
The same exclusion should likely apply to aspire-apphost-singlefile as well (which I also added). Should I remove both exclusions or is there a different approach you'd prefer?
| "aspire-13.0-tfms": "net8.0;net9.0;net10.0" | ||
| }, | ||
| "precedence": "9000", | ||
| "identity": "Aspire.PyStarter.CSharp.8.0", |
There was a problem hiding this comment.
This can just be Aspire.PyStarter.CSharp as we haven't been using the version suffix.
There was a problem hiding this comment.
Updated to Aspire.PyStarter.CSharp in commit a2b37b1.
| "language": "C#", | ||
| "type": "solution", | ||
| "editorTreatAs": "solution", | ||
| "aspire-13.0-tfms": "net8.0;net9.0;net10.0" |
There was a problem hiding this comment.
This isn't required any template except the empty template and is only used by the VS "Add Aspire orchestration" experience.
There was a problem hiding this comment.
Removed the aspire-13.0-tfms tag in commit a2b37b1.
| "type": "solution", | ||
| "editorTreatAs": "solution", |
There was a problem hiding this comment.
Hmmm not sure if this is the right choice given this is using file-based app host and no projects or laying down a solution.
There was a problem hiding this comment.
Changed type from "solution" to "project" in commit a2b37b1.
| } | ||
| ], | ||
| "replaces": "net8.0", | ||
| "defaultValue": "net9.0" |
There was a problem hiding this comment.
I think we can remove this entire option as this uses a file-based AppHost so only works on .NET 10
There was a problem hiding this comment.
Removed the Framework symbol entirely in commit a2b37b1 since this is a file-based AppHost for .NET 10+.
| "skipRestore": { | ||
| "type": "parameter", | ||
| "datatype": "bool", | ||
| "description": "If specified, skips the automatic restore of the project on create.", | ||
| "defaultValue": "false" | ||
| } |
There was a problem hiding this comment.
I think this whole option can be removed as we don't have the restore post-create action defined here anyway.
There was a problem hiding this comment.
Removed the skipRestore symbol in commit a2b37b1.
| @@ -0,0 +1,28 @@ | |||
| #:sdk Aspire.AppHost.Sdk@!!REPLACE_WITH_LATEST_VERSION!! | |||
There was a problem hiding this comment.
Need to add a apphost.run.cs file too with the launch profiles. Should be able to copy it from the existing aspire-apphost-singlefile template.
There was a problem hiding this comment.
Added apphost.run.json with launch profiles in commit a2b37b1.
… host configs and apphost.run.json Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com>
Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com>
Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com>
Updated DotnetTemplateFactory to include aspire-py-starter template (gated by SingleFileAppHostEnabled feature) in commit 4e89b52. |
There was a problem hiding this comment.
Pull Request Overview
Adds a new aspire-py-starter template enabling a Python (FastAPI) backend with a React + Vite TypeScript frontend orchestrated via a single-file AppHost for Aspire 13.0.
- Introduces Python service (Redis-backed weather endpoint + OpenTelemetry) and a Vite React frontend.
- Adds packaging/configuration updates (template.json, localization, CLI integration, Dockerfile, AppHost).
- Extends CLI template factory and updates project template packaging rules (NoDefaultExcludes, apphost.cs handling).
Reviewed Changes
Copilot reviewed 52 out of 58 changed files in this pull request and generated 20 comments.
Show a summary per file
| File | Description |
|---|---|
| vite.config.ts | Adds Vite config with API proxy for Python service. |
| tsconfig.node.json | TypeScript config for Node/Vite tooling. |
| tsconfig.json | Project references setup. |
| tsconfig.app.json | TS compiler options for frontend app code. |
| src/main.tsx | React root bootstrapping. |
| src/index.css | Base/reset and accessibility styles. |
| src/App.tsx | Main UI logic fetching weather forecast. |
| src/App.css | Extensive theming and layout styling for the app. |
| package.json | Declares React/Vite/TypeScript dependencies and scripts. |
| index.html | Frontend entry HTML document. |
| eslint.config.js | ESLint configuration for TS/React. |
| .gitignore | Frontend ignore rules. |
| apphost.run.json | Launch profiles for single-file AppHost. |
| apphost.cs | Orchestrates Redis, Python API, and Vite frontend resources. |
| telemetry.py | OpenTelemetry setup for traces, metrics, logs. |
| pyproject.toml | Python project metadata and dependencies. |
| app.py | FastAPI application with Redis caching and health endpoint. |
| .python-version | Specifies Python 3.13 version. |
| Dockerfile | Multi-stage build for frontend + Python runtime image. |
| template.json | Defines template metadata/configuration. |
| localization JSON files | Localized template name/description entries. |
| ide.host.json | Hides template from Visual Studio. |
| dotnetcli.host.json | CLI hosting metadata. |
| Aspire.ProjectTemplates.csproj | Adds template packaging rules for new starter. |
| DotNetTemplateFactory.cs | Exposes new template via Aspire CLI. |
| TemplatingStrings.*.xlf / .resx | Adds localized resource string for template description. |
Files not reviewed (1)
- src/Aspire.Cli/Resources/TemplatingStrings.Designer.cs: Language not supported
| # Stage 3: Create the final runtime image | ||
| FROM python:3.13-slim-bookworm AS app | ||
|
|
||
| COPY --from=frontend-stage /dist /app/static |
There was a problem hiding this comment.
The Vite build output in the first stage (working directory /frontend) will be located at /frontend/dist, not /dist. This COPY will result in an empty static directory. Change to COPY --from=frontend-stage /frontend/dist /app/static.
| COPY --from=frontend-stage /dist /app/static | |
| COPY --from=frontend-stage /frontend/dist /app/static |
| // Proxy API calls to the backend service and strip 'api' prefix | ||
| '/api': { | ||
| target: process.env.services__apiservice__https__0 || process.env.services__apiservice__http__0, | ||
| changeOrigin: true |
There was a problem hiding this comment.
The comment states the prefix 'api' is stripped, but no path rewrite is configured; the proxy forwards /api/* unchanged. Either adjust the comment to reflect behavior or add a rewrite: path => path.replace(/^/api/, '').
| changeOrigin: true | |
| changeOrigin: true, | |
| rewrite: (path) => path.replace(/^\/api/, '') |
| {weatherData.length > 0 && ( | ||
| <div className="weather-grid"> | ||
| {weatherData.map((forecast, index) => ( | ||
| <article key={index} className="weather-card" aria-label={`Weather for ${formatDate(forecast.date)}`}> |
There was a problem hiding this comment.
Using the loop index as a React key can cause inefficient re-renders if the array changes; prefer a stable identifier such as forecast.date (e.g., key={forecast.date}).
| <article key={index} className="weather-card" aria-label={`Weather for ${formatDate(forecast.date)}`}> | |
| <article key={forecast.date} className="weather-card" aria-label={`Weather for ${formatDate(forecast.date)}`}> |
| "compilerOptions": { | ||
| "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", | ||
| "target": "ES2022", | ||
| "lib": ["ES2023"], |
There was a problem hiding this comment.
[nitpick] lib is set higher (ES2023) than target (ES2022), which can surface types for features that downlevel target may not support at runtime; align target and lib (e.g., both ES2023) or lower lib to match target for consistency.
| "lib": ["ES2023"], | |
| "lib": ["ES2022"], |
| gap: 0.25rem; | ||
| border: 1px solid var(--weather-card-border); | ||
| margin: 0; | ||
| padding: 0.25rem; |
There was a problem hiding this comment.
The padding property is duplicated (lines 297 and 301); remove the redundant declaration to reduce noise.
| padding: 0.25rem; |
Co-authored-by: davidfowl <95136+davidfowl@users.noreply.github.com>
|
@copilot Fix the translations to match the english name of the tempalte |
…late Co-authored-by: davidfowl <95136+davidfowl@users.noreply.github.com>
Updated all 14 localization files to correctly describe the Python + JavaScript starter template instead of "empty app" in commit [hash]. |
|
Tested run and deploy. @maddymontaquila and @DamianEdwards are going to follow up and clean up the wording and ux. |
Updated all 14 localization files to correctly describe the template as a Python API + JavaScript (React/Vite) starter instead of an "empty app". Each translation now reflects:
This addresses feedback from @davidfowl to fix the translations to match the English template description.
Original prompt
This pull request was created as a result of the following prompt from Copilot chat.
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.