diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index 7d92151..c6ee1a5 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -26,13 +26,15 @@ This uses `Dockerfile.frontend` which: ## Option 2: Pre-built Deployment (Air-Gapped/Restricted Environments) -Use `Dockerfile.frontend.prebuilt` for environments with restricted npm access or when esbuild platform binaries cannot be downloaded. +Use `Dockerfile.frontend.prebuilt` for environments with restricted npm access. **Requirements:** -- Node.js 24+ installed locally +- Node.js 18+ installed locally - npm installed locally - No internet required during Docker build +**Note:** This project uses Angular 17 with webpack bundler (not Vite) for better compatibility with restricted npm environments. + **Usage:** ### Step 1: Build Angular app locally @@ -71,26 +73,16 @@ This uses `Dockerfile.frontend.prebuilt` which: ## Troubleshooting -### esbuild Platform Binary Issues +### Build Tool Package Issues -If you see errors like: +If you see errors about missing packages like: ``` -Could not resolve "@esbuild/darwin-arm64" +Cannot find package "vite" +Cannot find package "esbuild" +Cannot find package "rollup" ``` -**Solution 1:** Use Option 2 (Pre-built) above - -**Solution 2:** Add platform binaries to package.json (already included): -```json -"optionalDependencies": { - "@esbuild/darwin-arm64": "^0.25.4", - "@esbuild/darwin-x64": "^0.25.4", - "@esbuild/linux-arm64": "^0.25.4", - "@esbuild/linux-x64": "^0.25.4" -} -``` - -**Solution 3:** Use custom npm registry with cached esbuild binaries +**Solution:** This project uses Angular 17 with webpack bundler specifically to avoid these issues. If you still encounter package access problems in your restricted environment, use Option 2 (Pre-built) deployment above, which eliminates all npm dependencies in Docker. ### Custom NPM Registry @@ -109,5 +101,20 @@ NPM_REGISTRY=http://your-proxy ./quickstart.sh ## Recommendation - **Development/Cloud**: Use Option 1 (standard) -- **Air-gapped/Enterprise**: Use Option 2 (pre-built) +- **Air-gapped/Enterprise**: Use Option 2 (pre-built) ⭐ **RECOMMENDED** - **CI/CD**: Use Option 2 for faster, more reliable builds +- **Restricted npm access**: Use Option 2 (pre-built) ⭐ **REQUIRED** + +--- + +## Build Strategy for Restricted Environments + +**This project uses Angular 17 with webpack** instead of Angular 19 with Vite specifically for better compatibility with restricted npm environments. Webpack has fewer platform-specific binary dependencies than Vite. + +If you encounter any package access errors during builds: +- `Cannot find package "vite"` +- `Cannot find package "rollup"` +- `Cannot find package "esbuild"` +- Any platform-specific binary errors + +**Solution:** Use Option 2 (Pre-built) deployment. This completely avoids npm installation in Docker and eliminates all build tool dependency issues. diff --git a/build-for-airgap.sh b/build-for-airgap.sh new file mode 100755 index 0000000..d91cf77 --- /dev/null +++ b/build-for-airgap.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +set -e + +echo "=========================================" +echo "Building Angular for Air-Gapped Deployment" +echo "=========================================" +echo "" + +# Check if we're in the right directory +if [ ! -f "docker-compose.yml" ]; then + echo "Error: Must run from project root directory" + exit 1 +fi + +# Check if node is installed +if ! command -v node &> /dev/null; then + echo "Error: Node.js is not installed. Please install Node.js 18+ first." + exit 1 +fi + +# Check if npm is installed +if ! command -v npm &> /dev/null; then + echo "Error: npm is not installed. Please install npm first." + exit 1 +fi + +echo "Step 1/3: Installing dependencies..." +cd frontend +npm install + +echo "" +echo "Step 2/3: Building Angular production bundle..." +npm run build:prod + +echo "" +echo "Step 3/3: Verifying build output..." +if [ -d "dist/frontend/browser" ]; then + echo "✓ Build successful!" + echo "✓ Output: frontend/dist/frontend/browser" + ls -lh dist/frontend/browser | head -5 +else + echo "✗ Build failed - output directory not found" + exit 1 +fi + +cd .. + +echo "" +echo "=========================================" +echo "Build Complete!" +echo "=========================================" +echo "" +echo "Next steps:" +echo "1. Update docker-compose.yml:" +echo " Change: dockerfile: Dockerfile.frontend" +echo " To: dockerfile: Dockerfile.frontend.prebuilt" +echo "" +echo "2. Deploy:" +echo " docker-compose up -d --build" +echo "" +echo "See DEPLOYMENT.md for more details." +echo "=========================================" diff --git a/docker-compose.yml b/docker-compose.yml index c180e50..16419e9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -60,9 +60,7 @@ services: frontend: build: context: . - dockerfile: Dockerfile.frontend - args: - NPM_REGISTRY: ${NPM_REGISTRY:-https://registry.npmjs.org/} + dockerfile: Dockerfile.frontend.prebuilt ports: - "4200:80" depends_on: diff --git a/frontend/angular.json b/frontend/angular.json index 0766561..2e7ceb1 100644 --- a/frontend/angular.json +++ b/frontend/angular.json @@ -11,24 +11,27 @@ "prefix": "app", "architect": { "build": { - "builder": "@angular/build:application", + "builder": "@angular-devkit/build-angular:browser", "options": { - "outputPath": "dist/frontend", + "outputPath": "dist/frontend/browser", "index": "src/index.html", - "browser": "src/main.ts", + "main": "src/main.ts", "polyfills": [ "zone.js" ], "tsConfig": "tsconfig.app.json", "assets": [ + "src/favicon.ico", { "glob": "**/*", - "input": "public" + "input": "public", + "output": "/" } ], "styles": [ "src/styles.css" - ] + ], + "scripts": [] }, "configurations": { "production": { @@ -55,7 +58,7 @@ "defaultConfiguration": "production" }, "serve": { - "builder": "@angular/build:dev-server", + "builder": "@angular-devkit/build-angular:dev-server", "configurations": { "production": { "buildTarget": "frontend:build:production" @@ -67,10 +70,10 @@ "defaultConfiguration": "development" }, "extract-i18n": { - "builder": "@angular/build:extract-i18n" + "builder": "@angular-devkit/build-angular:extract-i18n" }, "test": { - "builder": "@angular/build:karma", + "builder": "@angular-devkit/build-angular:karma", "options": { "polyfills": [ "zone.js", @@ -78,9 +81,11 @@ ], "tsConfig": "tsconfig.spec.json", "assets": [ + "src/favicon.ico", { "glob": "**/*", - "input": "public" + "input": "public", + "output": "/" } ], "styles": [ diff --git a/frontend/package.json b/frontend/package.json index 3525261..c7bf1a5 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -23,33 +23,29 @@ }, "private": true, "dependencies": { - "@angular/common": "^19.0.0", - "@angular/compiler": "^19.0.0", - "@angular/core": "^19.0.0", - "@angular/forms": "^19.0.0", - "@angular/platform-browser": "^19.0.0", - "@angular/router": "^19.0.0", + "@angular/animations": "^17.3.0", + "@angular/common": "^17.3.0", + "@angular/compiler": "^17.3.0", + "@angular/core": "^17.3.0", + "@angular/forms": "^17.3.0", + "@angular/platform-browser": "^17.3.0", + "@angular/platform-browser-dynamic": "^17.3.0", + "@angular/router": "^17.3.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", - "zone.js": "~0.15.0" + "zone.js": "~0.14.3" }, "devDependencies": { - "@angular/build": "^19.0.0", - "@angular/cli": "^19.0.0", - "@angular/compiler-cli": "^19.0.0", + "@angular-devkit/build-angular": "^17.3.0", + "@angular/cli": "^17.3.0", + "@angular/compiler-cli": "^17.3.0", "@types/jasmine": "~5.1.0", - "jasmine-core": "~5.9.0", + "jasmine-core": "~5.1.0", "karma": "~6.4.0", "karma-chrome-launcher": "~3.2.0", "karma-coverage": "~2.2.0", "karma-jasmine": "~5.1.0", "karma-jasmine-html-reporter": "~2.1.0", - "typescript": "~5.8.0" - }, - "optionalDependencies": { - "@esbuild/darwin-arm64": "^0.25.4", - "@esbuild/darwin-x64": "^0.25.4", - "@esbuild/linux-arm64": "^0.25.4", - "@esbuild/linux-x64": "^0.25.4" + "typescript": "~5.4.2" } } diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index e4955f2..45e5a30 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -9,11 +9,19 @@ "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "skipLibCheck": true, - "isolatedModules": true, + "esModuleInterop": true, "experimentalDecorators": true, "importHelpers": true, "target": "ES2022", - "module": "preserve" + "module": "ES2022", + "moduleResolution": "bundler", + "lib": [ + "ES2022", + "dom" + ], + "useDefineForClassFields": false, + "baseUrl": "./", + "paths": {} }, "angularCompilerOptions": { "enableI18nLegacyMessageIdFormat": false,