# ========================================================================= # STAGE 1: Build & Compile Tailwind CSS (Node.js + Yarn) # ========================================================================= FROM node:20-alpine AS tailwind-builder WORKDIR /src # Copy package descriptors first to leverage Docker layer caching COPY Tmt.SaqaTravel/package.json Tmt.SaqaTravel/yarn.lock ./Tmt.SaqaTravel/ # Install Node dependencies using Yarn with frozen lockfile for deterministic builds WORKDIR /src/Tmt.SaqaTravel RUN yarn install --frozen-lockfile # Copy the minimum files required for Tailwind CSS compilation. # Tailwind scans Razor components and pages to identify and compile used utility classes. WORKDIR /src COPY Tmt.SaqaTravel/Components/ ./Tmt.SaqaTravel/Components/ COPY Tmt.SaqaTravel/Styles/ ./Tmt.SaqaTravel/Styles/ COPY Tmt.SaqaTravel/tailwind.config.js* ./Tmt.SaqaTravel/ # Run the Tailwind CSS build script to output the compiled app.min.css inside wwwroot WORKDIR /src/Tmt.SaqaTravel RUN mkdir -p wwwroot && \ (yarn run build || npx tailwindcss -i Styles/app.css -o wwwroot/app.min.css --minify) # ========================================================================= # STAGE 2: Restore, Build, & Publish .NET 10 Application # ========================================================================= FROM mcr.microsoft.com/dotnet/sdk:10.0 AS dotnet-builder # Install Node.js & Yarn in the .NET builder stage to support MSBuild frontend compilation targets RUN apt-get update && apt-get install -y curl && \ curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \ apt-get install -y nodejs && \ npm install -g yarn WORKDIR /src # Copy the XML-based solution (.slnx) and project file for package restoration COPY Tmt.SaqaTravel.slnx ./ COPY Tmt.SaqaTravel/Tmt.SaqaTravel.csproj ./Tmt.SaqaTravel/ # Restore NuGet dependencies RUN dotnet restore Tmt.SaqaTravel/Tmt.SaqaTravel.csproj # Copy the full C# source code COPY Tmt.SaqaTravel/ ./Tmt.SaqaTravel/ # Overwrite / insert the pre-compiled, minified Tailwind CSS stylesheet from Stage 1 COPY --from=tailwind-builder /src/Tmt.SaqaTravel/wwwroot/app.min.css ./Tmt.SaqaTravel/wwwroot/app.min.css # Compile and publish the release-ready Blazor app (No AppHost, single-file DLL bundle) WORKDIR /src/Tmt.SaqaTravel RUN dotnet publish Tmt.SaqaTravel.csproj -c Release -o /app/publish /p:UseAppHost=false # ========================================================================= # STAGE 3: Slim, Secure, and Lightweight Runtime Container # ========================================================================= FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine AS final WORKDIR /app # Expose standard web traffic ports EXPOSE 8080 EXPOSE 8081 # Copy the published C# binaries and static wwwroot files COPY --from=dotnet-builder /app/publish . # Configure ASP.NET Core URL bindings to listen on non-privileged port ENV ASPNETCORE_URLS=http://+:8080 ENV ASPNETCORE_ENVIRONMENT=Production # Leverage the default .NET non-root user ($APP_UID is 1654 in alpine) for secure container execution USER $APP_UID ENTRYPOINT ["dotnet", "Tmt.SaqaTravel.dll"]