Appearance
Static Web Apps
Azure Static Web Apps (SWA) provides global hosting with built-in CDN for the Microtec ERP Angular micro-frontend applications. Each Angular MFE app gets its own SWA instance per environment, giving independent deployment, custom domain, and configuration management.
Naming Convention
mic-erp-fr-{env}-{app-short-name}-swa| App | Short Name | Example (dev) |
|---|---|---|
| erp-home | erp-home | mic-erp-fr-dev-erp-home-swa |
| apps-accounting | accounting | mic-erp-fr-dev-accounting-swa |
| apps-hr | hr | mic-erp-fr-dev-hr-swa |
| apps-finance | finance | mic-erp-fr-dev-finance-swa |
| apps-sales | sales | mic-erp-fr-dev-sales-swa |
| apps-purchase | purchase | mic-erp-fr-dev-purchase-swa |
| apps-inventory | inventory | mic-erp-fr-dev-inventory-swa |
| app-distribution | distribution | mic-erp-fr-dev-distribution-swa |
| fixed-assets | fixed-assets | mic-erp-fr-dev-fixed-assets-swa |
SKU
| Environment | SKU | Features |
|---|---|---|
| dev / stage | Free | 0.5 GB storage, 100 GB bandwidth/month |
| preprod / uat | Standard | 2 GB storage, unlimited bandwidth, custom domains |
| production | Standard | Custom domains, staging environments, managed functions |
Free Tier Limitations
The Free tier does not support custom domains with APEX records (bare domain). Use a subdomain (*.microtec-test.com) for dev/stage, or upgrade to Standard for APEX support.
staticwebapp.config.json
Each Angular MFE must include a staticwebapp.config.json at the build output root. This file controls routing, headers, and authentication:
json
{
"routes": [
{
"route": "/api/*",
"statusCode": 404
},
{
"route": "/*",
"rewrite": "/index.html"
}
],
"responseOverrides": {
"404": {
"rewrite": "/index.html",
"statusCode": 200
}
},
"globalHeaders": {
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "DENY",
"X-XSS-Protection": "1; mode=block",
"Referrer-Policy": "strict-origin-when-cross-origin",
"Permissions-Policy": "camera=(), microphone=(), geolocation=()",
"Content-Security-Policy": "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https://*.microtec-test.com https://*.microtecstage.com https://*.onlinemicrotec.com.sa"
},
"mimeTypes": {
".json": "application/json",
".wasm": "application/wasm"
},
"navigationFallback": {
"rewrite": "/index.html",
"exclude": [
"*.{css,scss,js,ts,map,json,woff,woff2,ttf,eot,svg,ico,png,jpg,jpeg,gif,webp}"
]
}
}SPA Routing Fallback
The navigationFallback rewrite to index.html is critical for Angular's PathLocationStrategy. Without it, refreshing the browser on any route other than / returns a 404.
Custom Domains
Each SWA in non-dev environments has a custom domain configured:
| App | dev | stage | production |
|---|---|---|---|
| erp-home | *.microtec-test.com/erp-home | *.microtecstage.com/erp-home | *.onlinemicrotec.com.sa/erp-home |
| accounting | *.microtec-test.com/accounting | *.microtecstage.com/accounting | *.onlinemicrotec.com.sa/accounting |
In practice, Azure Front Door serves all apps under a single domain and routes to the correct SWA based on path prefix. The SWA's built-in domain is used as the AFD origin.
Bicep Configuration
bicep
resource swa 'Microsoft.Web/staticSites@2022-09-01' = {
name: '${resourcePrefix}-${appShortName}-swa'
location: 'eastus2' // SWA is a global resource; region is metadata only
sku: {
name: environment == 'production' || environment == 'uat' ? 'Standard' : 'Free'
tier: environment == 'production' || environment == 'uat' ? 'Standard' : 'Free'
}
properties: {
stagingEnvironmentPolicy: 'Enabled'
allowConfigFileUpdates: true
provider: 'DevOps'
enterpriseGradeCdnStatus: environment == 'production' ? 'Enabled' : 'Disabled'
}
}Deployment via Pipeline
SWA deployment uses the AzureStaticWebApp@0 task:
yaml
# From unified-frontend-pipeline.yml (SWA deploy step)
- task: AzureStaticWebApp@0
displayName: 'Deploy $(projectName) to SWA'
inputs:
azure_static_web_apps_api_token: $(swaDeployToken)
app_location: 'FrontApps'
output_location: 'dist/$(projectName)'
skip_app_build: true # Build already done in matrix strategy
deployment_environment: $(environment)
env:
AZURE_STATIC_WEB_APPS_API_TOKEN: $(swaDeployToken)The swaDeployToken is a per-SWA deployment token stored in the Azure DevOps variable group for each environment. It is not stored in Key Vault (it is a pipeline-only secret).
Environment-Specific Builds
Each Angular app is built with the correct --configuration flag for the target environment:
| Environment | Angular Config | API Base URL |
|---|---|---|
| dev | development | https://gateway.microtec-test.com |
| stage | stage | https://gateway.microtecstage.com |
| preprod | preprod | https://gateway.microtec-preprod.com |
| uat | uat | https://gateway.microtec-uat.com |
| production | prod | https://gateway.onlinemicrotec.com.sa |
bash
# Build command per environment
ng build apps-accounting --configuration=stage --output-path=dist/apps-accountingThe angular.json fileReplacements array swaps environment.ts for the target-specific file.
Staging Environments (Production Only)
The Standard SKU in production allows up to 10 staging environments per SWA. These are used for PR previews:
yaml
# PR preview deployment
- task: AzureStaticWebApp@0
inputs:
deployment_environment: 'pr-$(System.PullRequest.PullRequestNumber)'PR preview URLs follow the pattern:
https://{swa-name}-{pr-number}.{region}.azurestaticapps.netStaging environments are automatically deleted when the PR is closed.
Cache Headers
SWA respects the Cache-Control headers set during blob upload. The pipeline sets:
| File Pattern | Cache-Control |
|---|---|
index.html | no-cache, no-store, must-revalidate |
*.js, *.css | max-age=31536000, immutable (1 year, content-hashed) |
*.json | no-cache |
assets/* | max-age=86400 (1 day) |
Troubleshooting
| Symptom | Likely Cause | Resolution |
|---|---|---|
| 404 on page refresh | navigationFallback missing in config | Verify staticwebapp.config.json is in build output |
| Wrong API URL in deployed app | Wrong --configuration flag used | Check pipeline environment parameter mapping |
| Deployment token expired | SWA token rotated | Regenerate token in Azure Portal → SWA → Manage Deployment Token; update ADO variable group |
| CSP blocking Keycloak | connect-src missing auth domain | Update Content-Security-Policy in staticwebapp.config.json |
| SWA deploy task fails | swaDeployToken not in variable group | Check ADO variable group for swaDeployToken variable |
Related Documentation
- Build Angular — Full Angular build pipeline
- Azure Front Door — Frontend origin group routing to SWAs
- Storage Accounts — Alternative Blob Storage hosting for large bundles
- Bicep Modules —
static-web-apps.bicepmodule