Skip to content

Frontend Build & Deployment

This page covers how to install dependencies, run apps locally, build for each environment, and deploy to Azure.


Installation

bash
cd MFE-Apps
npm i --f

Force flag is required

The --f (force) flag is mandatory due to peer dependency conflicts between Angular packages. Never run npm i without it — the install will fail or produce a broken node_modules.


Local Development

Start individual apps

bash
# Host shell (Module Federation dashboard)
nx serve apps/dashboard              # http://localhost:4200

# Business Owner portal
npm run start:bussiness-owners       # http://localhost:4301

# ERP modules
npm run start:erp-home               # http://localhost:4401
npm run start:accounting             # http://localhost:4402
npm run start:hr                     # http://localhost:4403
npm run start:finance                # http://localhost:4404
npm run start:sales                  # http://localhost:4405
npm run start:purchase               # http://localhost:4406
npm run start:inventory              # http://localhost:4407
npm run start:distribution           # http://localhost:4408
npm run start:fixed-assets           # http://localhost:4409

Start groups

bash
npm run start:erp       # Starts all ERP apps (ports 4401-4409) in parallel
npm run start:all       # Starts ALL apps including bussinessOwners

Run only what you need

You do not need to run all apps simultaneously. Keycloak SSO automatically handles authentication when you switch between apps on different ports. Just run the specific app you are developing.


Building

Single app builds

bash
# Production (default)
npm run build:apps-accounting
npm run build:apps-hr
npm run build:erp-home
npm run build:apps-sales
npm run build:apps-finance
npm run build:apps-inventory
npm run build:app-distribution
npm run build:fixed-assets
npm run build:apps-purchase
npm run build:bussiness-owners
npm run build:templates
npm run build:dashboard

# Cloud configuration
npm run build:cloud:apps-accounting
npm run build:cloud:bussiness-owners
# ... same pattern for all apps

Parallel build all apps

bash
# All apps — production config
npm run build:all

# All apps — cloud config
npm run build:all:cloud

# All apps — UAT config
npm run build:all:uat

# All apps — pre-production config
npm run build:all:preprod

# All apps — prod config
npm run build:all:prod

Parallel build command

build:all runs 11+ apps in parallel with 7 max concurrent processes:

bash
cross-env NODE_OPTIONS=--max-old-space-size=32768 concurrently --max-processes 7 \
  "npm run build:dashboard" \
  "npm run build:bussiness-owners" \
  "npm run build:apps-inventory" \
  "npm run build:apps-hr" \
  "npm run build:erp-home" \
  "npm run build:apps-sales" \
  "npm run build:apps-finance" \
  "npm run build:apps-purchase" \
  "npm run build:apps-accounting" \
  "npm run build:app-distribution" \
  "npm run build:fixed-assets" \
  "npm run publishAssets"

Build Configurations

Each build configuration changes API base URLs and Keycloak realm URLs:

Configuration--configuration= flagWhen to Use
productionproductionDefault local/dev builds
cloudcloudAzure cloud deployment (non-prod)
uatuatUAT environment
preprodpreprodPre-production environment
prodprodProduction environment

Environment files are at apps/<app>/src/environments/:

environments/
├── environment.ts               # Default (production config)
├── environment.development.ts   # Local development
├── environment.cloud.ts         # Cloud
├── environment.uat.ts           # UAT
├── environment.preprod.ts       # Pre-production
└── environment.prod.ts          # Production

Key values that differ per config:

typescript
export const environment = {
  production: true,
  isDevelopment: false,
  apiBaseUrl: 'https://gateway.onlinemicrotec.com.sa',
  keycloakUrl: 'https://keycloak.onlinemicrotec.com.sa',
  keycloakRealm: 'microtec',
  keycloakClientId: 'angular',
};

Build Output

bash
dist/
├── dashboard/          # Host shell static files
├── bussinessOwners/    # BO portal static files
├── accounting/         # Accounting module static files
└── ...                 # One folder per app

Each app's dist folder contains:

  • index.html
  • Hashed JS/CSS bundles (output-hashing=all)
  • web.config for IIS/Azure hosting rules
  • Assets (fonts, images, i18n files)

Shared Assets Publishing

After all app builds complete, publishAssets runs automatically as the last step:

bash
npm run publishAssets

This copies shared translation files and assets from libs/shared-assets/ into each app's dist folder. It runs node ./publish_assets.js.


Azure Deployment

ERP Apps — Azure Blob Storage

All ERP apps (dashboard + remotes except bussinessOwners) are deployed to an Azure Blob Storage account with static website hosting enabled:

EnvironmentStorage AccountContainer
devmicerpfrdevsa$web
stagemicerpfrstagesa$web
preprodmicerpfrpreprodsa$web
uatmicerpfruatsa$web
productionmicerpfrprodsa$web

Deployment uploads the dist folder to the $web container using az storage blob upload-batch.

Business Owners — Azure Static Web Apps

The bussinessOwners app is deployed separately to an Azure Static Web App (SWA):

  • Provides SWA-specific routing rules (staticwebapp.config.json)
  • Supports custom authentication providers if needed
  • CDN is automatically managed by Azure SWA

Azure DevOps Pipeline

The frontend pipeline is defined at:

Devops/azure/pipelines/frontApps/deploy/unified-frontend-pipeline.yml

Pipeline stages:

Branch-to-environment mapping:

BranchEnvironment
main / master / productionProduction
stage / stagingStage
PreProd / preprodPre-production
All othersDev

Testing

bash
# Test all projects
nx run-many --target=test --all

# Test specific project
nx test accounting

# Test with coverage
nx test accounting --codeCoverage

# Test affected projects only (CI)
nx affected:test

Code Quality

bash
# Lint all projects
nx run-many --target=lint --all

# Lint specific project
nx lint accounting

# Check affected projects
nx affected:lint

Troubleshooting

Build runs out of memory

bash
# Increase Node.js heap limit manually
export NODE_OPTIONS=--max-old-space-size=32768
npm run build:all

Module Federation remote not loading

  1. Ensure the remote app is running on its expected port.
  2. Check apps/dashboard/webpack.config.js — verify the remote entry URL matches.
  3. In production, verify the CDN routing rules forward the correct path prefixes.

Keycloak login loop

  1. Verify keycloakUrl and keycloakRealm in the environment file.
  2. Ensure the Keycloak client has the app's origin in its "Valid Redirect URIs".
  3. Check that isDevelopment is set correctly in the environment file.

Internal Documentation — Microtec Platform Team