feat: Docker deployment + JS minification#278
Merged
Conversation
Adds esbuild as a devDependency and an MSBuild target that minifies the hand-written JS interop layer (leafletInterop, aisLayer, etc.) during Release publish. Drops 30-40% off the raw JS payload; brotli stacks on top. Skipped in Debug to keep dev iterations fast. Also excludes *.test.js / *.test.mjs / __tests__/ from the published bundle so test code doesn't end up in the static asset tree.
New OnaPlotter.Server project hosts the published Blazor WASM
bundle via UseBlazorFrameworkFiles + MapFallbackToFile. PublishAot
is gated on Release so 'dotnet run --project OnaPlotter.Server'
stays fast for local dev; the AOT-compiled binary is what Docker
ships.
Two env vars template the static bundle at startup:
SK_SERVER_URL - rewrites wwwroot/appsettings.json SignalK:ServerUrl
BASE_HREF - rewrites the <base href> in wwwroot/index.html
JSON / HTML mutation is hand-rolled to keep the AOT graph free of
JsonSerializer + Regex. The standalone WASM dev path ('dotnet run
--project OnaPlotter') keeps working unchanged.
Multi-stage Dockerfile based on dotnet/runtime-deps:10.0-alpine. Build stage compiles the WASM bundle (AOT) + the Kestrel host (NativeAOT) in one publish; runtime stage carries only the self-contained binary + the static bundle. Final image lands around 35-50 MB depending on arch. GH Actions workflow builds linux/amd64 + linux/arm64 on their native runners (no QEMU), pushes per-arch tags to GHCR, then composes a multi-arch manifest as :version and :latest. Pre- release tags (v*-alpha/beta/rc) publish :version but skip :latest.
The new MinifyPublishedJs MSBuild target needs node_modules/esbuild to exist when 'dotnet publish' runs in Release. Adding npm ci to publish.yml mirrors what the Dockerfile and local deploy.ps1 users already do; without it the workflow would fail with the clear CheckEsbuildPresent error at publish time.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a standalone Docker shape for OnaPlotter and minifies the hand-written JS interop layer on Release publish.
Three deliverables
1. JS minification on Release publish
OnaPlotter.csprojrunsesbuild --minifyagainstwwwroot/js/**/*.jsin publish output (Release only). Cuts ~30-40% off the raw JS payload; brotli stacks on top. Skipped in Debug to keep dev iterations fast. Test files (*.test.js,__tests__/) are also excluded from publish entirely so they don't ship to clients.Requires
npm cibeforedotnet publishin Release.publish.ymlupdated to install.CheckEsbuildPresentMSBuild target surfaces a clear error if node_modules/esbuild is missing.2.
OnaPlotter.ServerKestrel hostNew project hosts the published Blazor WASM bundle via
UseBlazorFrameworkFiles+MapFallbackToFile.PublishAot=truegated on Release sodotnet run --project OnaPlotter.Serverstays fast for local dev; the AOT-compiled binary is what Docker ships.Runtime config via env vars:
SK_SERVER_URL→ rewriteswwwroot/appsettings.jsonSignalK:ServerUrlBASE_HREF→ rewrites the<base href>inwwwroot/index.htmlMutations are hand-rolled (no
JsonSerializer/Regex) to keep the AOT graph minimal. The standalone WASM dev path (dotnet run --project OnaPlotter) is untouched.3. Multi-arch Docker image + GHCR workflow
Dockerfileis multi-stage ondotnet/runtime-deps:10.0-alpine. Build stage compiles both AOTs (WASM AOT for the client + NativeAOT for the host); runtime stage carries only the self-contained binary + the static bundle. Final image ~35-50 MB depending on arch..github/workflows/docker.ymlbuildslinux/amd64+linux/arm64on their native runners (no QEMU), pushes per-arch tags toghcr.io/msallin/ona-plotter, then composes a multi-arch manifest. Pre-release tags (v*-alpha/beta/rc) skip the:latestmove so it stays on the last GA.Verification
dotnet build OnaPlotter.slnx— passesdotnet run --project OnaPlotter.Server— serves/and/_framework/blazor.webassembly.js(200 OK, ~10 KB index, ~60 KB blazor.webassembly.js)dotnet publish OnaPlotter.Server -c Debug -o ...— produces a publish layout withwwwroot/index.html+_framework/merged correctlyRun
After a release tag fires the new workflow:
For local dev: