Skip to content

Production build

marksvc edited this page Sep 3, 2025 · 14 revisions

You can do a production build of the backend and frontend locally, and running with development settings, by doing the following. This blending may fail in various ways. For example, the authentication callback does not complete (but the frontend can still be used).

cd "$SF_REPO" &&
cp src/SIL.XForge.Scripture/ClientApp/src/environments/{environment.ts,environment.prod.ts} &&
cp src/SIL.XForge.Scripture/{hosting.Development.json,hosting.json}

Modify src/SIL.XForge.Scripture/Migrator.cs to prevent the migrator from failing:

     public static void RunMigrations(string environment)
     {
+        return;

Copy from src/SIL.XForge.Scripture/appsettings.Development.json into src/SIL.XForge.Scripture/appsettings.json the following, overwriting the values. Don't forget to have commas where necessary for json formatting.

  • Site.Origin
  • Site.SendEmail
  • DataAccess.ConnectionString
  • Realtime.SecurePort
  • BugSnag.ReleaseStage
  • Auth.Domain
  • Auth.ManagementAudience
  • Auth.FrontendClientId
  • Auth.BackendClientId
  • Paratext.HgExe
  • Serval.ApiServer
  • Serval.TokenUrl
  • Kestrel

You can do that with jq, such as with these commands:

cd "$SF_REPO"
DEV="src/SIL.XForge.Scripture/appsettings.Development.json"
BASE="src/SIL.XForge.Scripture/appsettings.json"
TMP="$(mktemp)"

jq --argjson dev "$(cat "$DEV")" '
  .Site       = (.Site       // {}) |
  .DataAccess = (.DataAccess // {}) |
  .Realtime   = (.Realtime   // {}) |
  .Bugsnag    = (.Bugsnag    // {}) |
  .Auth       = (.Auth       // {}) |
  .Paratext   = (.Paratext   // {}) |
  .Serval     = (.Serval     // {}) |

  .Site.Origin                 = ($dev.Site.Origin                 // .Site.Origin) |
  .Site.SendEmail              = ($dev.Site.SendEmail              // .Site.SendEmail) |
  .DataAccess.ConnectionString = ($dev.DataAccess.ConnectionString // .DataAccess.ConnectionString) |
  .Realtime.SecurePort         = ($dev.Realtime.SecurePort         // .Realtime.SecurePort) |
  .Bugsnag.ReleaseStage        = ($dev.Bugsnag.ReleaseStage        // .Bugsnag.ReleaseStage) |
  .Auth.Domain                 = ($dev.Auth.Domain                 // .Auth.Domain) |
  .Auth.ManagementAudience     = ($dev.Auth.ManagementAudience     // .Auth.ManagementAudience) |
  .Auth.FrontendClientId       = ($dev.Auth.FrontendClientId       // .Auth.FrontendClientId) |
  .Auth.BackendClientId        = ($dev.Auth.BackendClientId        // .Auth.BackendClientId) |
  .Paratext.HgExe              = ($dev.Paratext.HgExe              // .Paratext.HgExe) |
  .Serval.ApiServer            = ($dev.Serval.ApiServer            // .Serval.ApiServer) |
  .Serval.TokenUrl             = ($dev.Serval.TokenUrl             // .Serval.TokenUrl) |
  .Kestrel                     = ($dev.Kestrel                     // .Kestrel)
' "$BASE" > "$TMP" && mv "$TMP" "$BASE"

Build, put secrets into the right place, and run:

cd "$SF_REPO" && 
  scripts/build-production &&
  cp ~/.microsoft/usersecrets/4d0606c3-0fc7-4d76-b43b-236485004e81/secrets.json artifacts/app/ &&
  cd artifacts/app &&
  ./SIL.XForge.Scripture

Development build with dotnet publish

You can run the production build process, but doing a development build, by doing the following. Note that this will fail when dotnet tries to run the angular server (which is not actually done in production). But this might be useful for various investigations.

Modify scripts/build-production to add argument:

-  --self-contained
+  --self-contained -p:ErrorOnDuplicatePublishOutputFiles=false

Modify src/SIL.XForge.Scripture/Migrator.cs to prevent the migrator from failing:

     public static void RunMigrations(string environment)
     {
+        return;

Build and run:

cd "$SF_REPO"
CONFIGURATION=Debug ANGULAR_CONFIG=development scripts/build-production
cd artifacts/app
ASPNETCORE_ENVIRONMENT=Development ./SIL.XForge.Scripture
Clone this wiki locally