'How do I publish a .NET Core + Angular single page app for different environments?
Some additional context: I created a solution using the Angular project template with ASP.NET Core in Visual Studio 2019. The app has several different environments: DEV, STG, and Production. There are corresponding "appsettings.json" files for the .NET project ("appsettings.DEV.json", "appsettings.STG.json", "appsettings.Production.json"), as well as "environment.ts" files in the "ClientApp" folder ("environment.DEV.ts", "environment.STG.ts", "environment.Production.ts"). This app will be deployed to IIS on a Windows Server, and I have created ".pubxml" publish profiles targeting a folder for each of these environments.
The project template generates the following in the .csproj file:
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build -- --prod" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build:ssr -- --prod" Condition=" '$(BuildServerSideRenderer)' == 'true' " />
</Target>
The .pubxml files I created set the value of ASPNETCORE_ENVIRONMENT
like this:
<environmentVariables>
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="DEV" />
</environmentVariables>
I have also added build scripts for the Angular client app in the "package.json" file for each environment:
"scripts": {
"build-dev": "ng build -c DEV",
"build-stg": "ng build -c STG",
"build-prod": "ng build -c Production",
}
However, I would like to specify which of those scripts to run, depending on which publish profile was selected. I tried modifying the ".csproj" file with the following, but it does not work. I can't figure out how to get the value of ASPNETCORE_ENVIRONMENT
in the .csproj file:
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build-dev" Condition="'$(ASPNETCORE_ENVIRONMENT)' == 'DEV'" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build-stg" Condition="'$(ASPNETCORE_ENVIRONMENT)' == 'STG'" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build-production" Condition="'$(ASPNETCORE_ENVIRONMENT)' == 'Production'" />
</Target>
What is the correct way to publish the entire app, building both the .NET app and the Angular app in the "ClientApp" folder for different environments?
Solution 1:[1]
I was able to resolve my issue. Here are the changes I made in order to successfully publish the entire .NET 5 & Angular 11 single page app to be deployed to IIS on Windows Server:
Solution configurations for each environment (DEV, STG, and Production) were added:
The ".csproj" file was updated with the following ($(Configuration)
was used instead of $(ASPNETCORE_ENVIRONMENT)
):
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build-dev" Condition="'$(Configuration)' == 'DEV'" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build-stg" Condition="'$(Configuration)' == 'STG'" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build-production" Condition="'$(Configuration)' == 'Production'" />
<!-- Include the newly-built files in the publish output -->
<ItemGroup>
<!--<DistFiles Include="$(SpaRoot)dist\**; $(SpaRoot)dist-server\**" />-->
<DistFiles Include="$(SpaRoot)dist\**;" />
<DistFiles Include="$(SpaRoot)node_modules\**" Condition="'$(BuildServerSideRenderer)' == 'true'" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>%(DistFiles.Identity)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</ResolvedFileToPublish>
</ItemGroup>
</Target>
The scripts
section of the "package.json" file was updated with the following:
"scripts": {
"build-dev": "ng build -c DEV --base-href=/MyAppName/",
"build-stg": "ng build -c STG --base-href=/MyAppName/",
"build-prod": "ng build -c Production --base-href=/MyAppName/",
}
Setting the base-href
value in the scripts for building the Angular app solved errors 404 I was seeing when the app is not published at the site root.
Finally, the ".pubxml" publish pofiles I created were removed, and instead I used the dotnet publish
command with the -c
configuration argument. Ex:
dotnet publish -c DEV
dotnet publish -c STG
dotnet publish -c Production
The files to deploy are output to the "\MyAppName\bin\{CONFIGURATION}\net5.0\publish\" folder.
Solution 2:[2]
You can set your environment configuration in each of your pubxml files as explained in the official documentation:
<PropertyGroup>
...
<EnvironmentName>Development</EnvironmentName>
</PropertyGroup>
And then create one PublishRunWebpack... Target section for each environment in your csproj file:
<Target Name="PublishRunWebpackDevelopment" AfterTargets="ComputeFilesToPublish" Condition="'$(EnvironmentName)' == 'Development'">
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build-dev" />
...
</Target>
<Target Name="PublishRunWebpackStaging" AfterTargets="ComputeFilesToPublish" Condition="'$(EnvironmentName)' == 'Staging'">
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build-stg" />
...
</Target>
...
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | mfcallahan |
Solution 2 | Rafael Neto |