0

I have built an Angular SSR app using Angular 19, and I'm trying to deploy it on AWS Amplify. Below is my setup and the challenges I'm facing:

Package.json

{
  "name": "ssr-app",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "serve:ssr:ssr-app": "node dist/ssr-app/server/server.mjs",
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^19.0.0",
    "@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/platform-browser-dynamic": "^19.0.0",
    "@angular/platform-server": "^19.0.0",
    "@angular/router": "^19.0.0",
    "@angular/ssr": "^19.0.6",
    "aws-amplify": "^6.12.0",
    "express": "^4.18.2",
    "rxjs": "~7.8.0",
    "tslib": "^2.3.0",
    "zone.js": "~0.15.0"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^19.0.6",
    "@angular/cli": "^19.0.6",
    "@angular/compiler-cli": "^19.0.0",
    "@aws-amplify/backend": "^1.12.0",
    "@aws-amplify/backend-cli": "^1.4.6",
    "@types/express": "^4.17.17",
    "@types/jasmine": "~5.1.0",
    "@types/node": "^18.18.0",
    "aws-cdk": "^2.173.4",
    "aws-cdk-lib": "^2.173.4",
    "constructs": "^10.4.2",
    "esbuild": "^0.24.2",
    "jasmine-core": "~5.4.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",
    "tsx": "^4.19.2",
    "typescript": "^5.6.3"
  }
}

Build folder structure

dist/
  ssr-app/
    browser/  # Contains client-side files
    server/   # Contains server-side files, including `server.mjs`

Aws ampliy.yml

version: 1
frontend:
  phases:
    preBuild:
      commands:
        - nvm install 20
        - nvm use 20
        - npm install
    build:
      commands:
        - |
          if [ "$AWS_BRANCH" == "master" ]; then
            npm run build
          else
            echo "Branch not configured for specific build commands."
            exit 1
          fi
  artifacts:
    baseDirectory: dist/ssr-app
    files:
      - '**/*'
  cache:
    paths:
      - .npm/**/*
  runtime:
    nodejs: 20

Build Logs

134 2024-12-31T10:32:53.727Z [INFO]: Output location: /codebuild/output/src2186657907/src/g99-landingpages-ui-copy/dist/ssr-app
135 2024-12-31T10:32:53.843Z [INFO]: # Completed phase: build
136 ## Completed Frontend Build
137 2024-12-31T10:32:53.857Z [INFO]: ## Build completed successfully
138 2024-12-31T10:32:53.858Z [INFO]: # Starting caching...
139 2024-12-31T10:32:53.862Z [INFO]: # Creating cache artifact...
140 2024-12-31T10:32:53.865Z [INFO]: # Created cache artifact
141 2024-12-31T10:32:53.865Z [INFO]: # Uploading cache artifact...
142 2024-12-31T10:32:53.947Z [INFO]: # Uploaded cache artifact
143 2024-12-31T10:32:53.947Z [INFO]: # Caching completed
144 2024-12-31T10:32:53.967Z [WARNING]: !! No index.html detected in deploy folder: /codebuild/output/src2186657907/src/g99-landingpages-ui-copy/dist/ssr-app
145 2024-12-31T10:32:53.969Z [INFO]: # Starting build artifact upload process...
146 2024-12-31T10:32:54.072Z [INFO]: # Uploading build artifact '__artifacts.zip'...
147 2024-12-31T10:32:54.171Z [INFO]: # Build artifact upload completed
148 2024-12-31T10:32:54.172Z [INFO]: # Starting environment caching...
149 2024-12-31T10:32:54.172Z [INFO]: # Uploading environment cache artifact...
150 2024-12-31T10:32:54.239Z [INFO]: # Uploaded environment cache artifact
151 2024-12-31T10:32:54.239Z [INFO]: # Environment caching completed

Problem: After the build completes, AWS Amplify expects an index.html file in the deployment folder, but my app is an SSR application. Instead of serving static files, the app needs to run the server file (dist/ssr-app/server/server.mjs) to handle requests.

What I Need Help With:

  • How can I configure AWS Amplify to run the server-side file (server.mjs) instead of looking for index.html?
  • Is it possible to override the build and start commands in AWS Amplify to suit an SSR application?

Below is my folder structure after build enter image description here

1 Answer 1

0

You can follow sbalfour's comment on how you can modify your Angular SSR application to have it working with Amplify. His solution for Angular 17 SSR is also working with Angular 19 SSR.

deploy-manifest.json at root of project

{
  "version": 1,
  "framework": { "name": "express", "version": "4.18.2" },
  "routes": [
    {
      "path": "/*.*",
      "target": {
        "kind": "Static",
        "cacheControl": "public, max-age=1, immutable"
      },
      "fallback": {
        "kind": "Compute",
        "src": "default"
      }
    },
    {
      "path": "/*",
      "target": {
        "kind": "Compute",
        "src": "default"
      }
    }
  ],
  "computeResources": [
    {
      "name": "default",
      "runtime": "nodejs20.x",
      "entrypoint": "server.mjs"
    }
  ]
}

postbuild.sh in /bin

#!/bin/bash

rm -rf ./.amplify-hosting

mkdir -p ./.amplify-hosting/compute

cp -r ./dist/your-project/server ./.amplify-hosting/compute/default

cp -r ./dist/your-project/browser ./.amplify-hosting/static

cp deploy-manifest.json ./.amplify-hosting/deploy-manifest.json

Add the postbuild command to package.json scripts

"postbuild": "chmod +x bin/postbuild.sh && ./bin/postbuild.sh",

Adjust the server.ts browserDistFolder to point the static folder

const browserDistFolder = resolve(serverDistFolder, '../../static');

and to use port 3000

const port = process.env['PORT'] || 3000;

Update amplify.yml in the AWS amplify

version: 1
frontend:
  phases:
    preBuild:
      commands:
        - npm ci
    build:
      commands:
        - npm run build
  artifacts:
    baseDirectory: .amplify-hosting
    files:
      - '**/*'
  cache:
    paths:
      - node_modules/**/*

And finally, in Rewrites and redirects, remove or adjust the 200 rewrite rule to index.html that looks like this:

</^[^.]+$|\\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf|map|json)$)([^.]+$)/>

A clean solution would be to have an adapter for Angular SSR but there is none currently... And creating one would require to have build process hooks.

Sign up to request clarification or add additional context in comments.

3 Comments

How is the "postbuild" command being executed? I've followed your / sbalfour's suggestion and get an error during the build which suggests that postbuild script hasn't run: "[ERROR]: !!! CustomerError: Artifact directory doesn't exist: .amplify-hosting" Any idea what I'm missing?
postbuild should be executed after build, it's part of pre/post scripts npm lifecyle: docs.npmjs.com/cli/v8/using-npm/scripts#pre--post-scripts
Thanks you got me on the right track. My build script is called "build:ssr" so I renamed my postbuild script from "postbuild" to "postbuild:ssr" and it progressed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.