Troubleshooting the deployment issues of an Angular 17 web application on Google App Engine

I'm facing an issue with deploying my Angular web app project on Google App Engine. The project builds and runs locally without any problems, but when I deploy it using 'gcloud app deploy', the app is not served properly.

Even though GAE can build the project, when it serves the 'index.html' file, I encounter a "404 Not Found" error.

https://i.sstatic.net/0kcOAMFC.png

The only intriguing message in the GAE build log is as follows:

Using config appstart.Config{Runtime:"nodejs22", Entrypoint:appstart.Entrypoint{Type:"Default", Command:"/serve", WorkDir:""}, MainExecutable:""}

The presence of MainExecutable:"" raises some questions for me. Is this correct?


I've extensively reviewed the documentation related to 'app.yaml', 'angular.json', and 'tsconfig.json' configuration files and their possible attributes, but I haven't been able to identify what could be wrong.

As a troubleshooting step, I even created a new Angular example project using 'ng new' and tried deploying it with default settings, but encountered the same issue.


Below are snippets from my configuration files:

app.yaml:

runtime: nodejs22

service: [app-name]

handlers:

- url: /(.*\.css)
  static_files: dist/[app-name]/\1
  upload: dist/[app-name]/(.*\.css)

... (remaining content omitted for brevity)

angular.json:

{
  // Angular JSON configuration snippet 
  // ... (content omitted for brevity)
}

tsconfig.json:

{
  // TypeScript configuration snippet
  // ...(content omitted for brevity)
}


.gcloudignore:

# List of files not uploaded to Google Cloud using gcloud
# ... (content omitted for brevity)

.gcloudignore

# Include the dist directory where build output is stored
!dist/

// Other exclusion/inclusion rules...

If more information or logs are required for better analysis, please let me know. Any assistance in resolving this issue would be highly appreciated!

Answer №2

After spending an entire week troubleshooting this issue, I finally managed to identify the root cause.

It seems that I had mistakenly assumed that Google App Engine would automatically build the project whenever I used the command gcloud app deploy. Due to this misconception, I decided to comment out the line in my .gcloudignore file that specified the dist folder for deployment (!dist/). I must give credit to @Deivid Drenkhan for his insightful post on Stack Overflow from years ago (link provided) as it prompted me to review my own configuration regarding the skip_files section.

I also made a slight tweak by modifying the moduleResolution element in the tsconfig.json file, changing it from "node" to "bundler". This adjustment seemed appropriate considering that Angular 18 projects default to this setting. Furthermore, after consulting the documentation on this topic (link provided), it all started to make sense. Given the numerous adjustments and investigations carried out, there is a possibility that other elements of the setup were incorrect or suboptimal, thereby contributing to the issue at hand.

It may be pertinent to note that deploying to a Flex environment enables SSH access to the VM where the application runs (link provided). I had contemplated exploring this option if my previous efforts did not yield clarity on the problem.


The final version of my app.yaml configuration appears as follows:

runtime: nodejs22

service: [app-name]

handlers:

- url: /([^.]+)/?$  
  static_files: dist/index.html
  upload: dist/index.html

# Serve index.html for the root URL ('/')
- url: /
  static_files: dist/index.html
  upload: dist/index.html
  secure: always
  redirect_http_response_code: 301
  login: admin

# Serve CSS files from the root 'dist/' directory
- url: /(.+)\.css
  static_files: dist/\1.css
  upload: dist/.+\.css

# Serve JavaScript files from the root 'dist/' directory
- url: /(.+)\.js
  static_files: dist/\1.js
  upload: dist/.+\.js

# Serve HTML files from the root 'dist/' directory
- url: /(.+)\.html
  static_files: dist/\1.html
  upload: dist/.+\.html

# Serve files from the 'assets/' directory
- url: /assets/(.*)
  static_files: dist/assets/\1
  upload: dist/assets/(.*)

# Catch-all rule to serve index.html for any path not matched above
- url: /.*
  static_files: dist/index.html
  upload: dist/index.html
  secure: always
  redirect_http_response_code: 301
  login: admin




Any suggestions for improvement, hints, comments, or corrections to any inaccuracies in my explanation are greatly appreciated.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Optimizing the utilization of multiple ngIf statements in Angular 5

I am new to Angular development and I'm currently working with *ngIf statements in my components. While researching, I came across articles advising against using complex logic in *ngIf statements. For instance: <user-component *ngIf="role= ...

Encountering a Geolocation API issue during the troubleshooting of an Angular application on

Currently, I'm in the process of developing an angular application that utilizes the GeoLocation API to retrieve user location. To achieve this, I make use of the navigator.geolocation.getCurrentPosition() function. Surprisingly, everything works perf ...

The AWSAppSyncClient in Angular 17+ fails to trigger the subscription error handler when facing Authorization errors on the websocket

My Angular client (Version 17+) interacts with AWSAppSync via the AWSAppSyncClient library. client!: AWSAppSyncClient<any>; this.client = new AWSAppSyncClient({ url: 'https://<AppSync EndPoint domain>/graphql', ...

One-Of-A-Kind Typescript Singleton Featuring the Execute Method

Is it feasible to create a singleton or regular instance that requires calling a specific method? For instance: logger.instance().setup({ logs: true }); OR new logger(); logger.setup({ logs: true }); If attempting to call the logger without chaining the ...

Tips for developing a web-based whiteboard application

I am tasked with developing a web application that allows users to design factory layouts by dragging and dropping pre-built components like robots, manufacturing cells, and conveyors onto a canvas. The goal is to create something similar to websites such ...

Hello there! I am just starting to learn about Bootstrap and I'm excited to create a responsive layout that will be centered on the page

I am aiming for this specific layout design. https://i.sstatic.net/JHvSY.png Here is the current code snippet that I have: <div class="container"> <h2 class="title mt-3 mb-4">Title</h2> <div class="container"> <div ...

What is the method for returning a string array?

My query is about how to return a string[]. Currently, TypeScript is throwing an error because each element of the array has a type of ( T[keyof T] extends readonly (infer InnerArr)[] ? InnerArr : T[keyof T] ). How can I accept the 'property' arg ...

Checking the functionality of a feature with Jasmine framework in an Angular application

I am working on writing unit test cases and achieving code coverage for the code snippet below. Any advice on how to proceed? itemClick($event: any) { for (let obj of this.tocFiles) { let results = this.getchildren(obj, label); if (results) { conso ...

Mastering Typescript generics for accurate mapping between keys and values through indirection

I've been struggling to understand how to create a specialized mapper that can indirectly map methods based on one object's values corresponding to another object's keys. The mapper used in the code snippet below is not mine; it's an e ...

Establish a user profile and define custom claims using Firebase Authentication

When a new user is registered, certain values for user access control are set up immediately. The issue arises when the data set is only visible in the subsequent sessions after logging out of the authenticated user session that was created. My challenge ...

Bringing a JavaScript file into an Ionic/Angular 2 project

I have been attempting to integrate a simple JS library into Angular 2. The library in question is JIC.js. var jic = { /** * This function takes an Image Object (JPG or PNG) and returns a compressed new Image Object * @param {Ima ...

The object created from winRef.nativeWindow.Razorpay is not a valid constructor

I am currently using Angular 4 for a project and I need to integrate razorpay into the project. While it works perfectly fine in the test and development environments, I encounter an error in a specific environment, the live environment. vendor.cdeb9a87 ...

Variety of part ingredients

In my component, I have a button and include another component which also contains a button. How can I align these two buttons next to each other without using absolute positioning? When I try positioning them using absolute right and top values, the lay ...

Using V-For with data fetched from an axios request: A step-by-step guide

How can I dynamically populate V-Cards after making an Axios request to retrieve data? The Axios request is successful, but the v-for loop does not populate with V-Cards. I've also attempted to make the request before the rendering is completed (usin ...

Angular Placeholder Positioned at the Top

Hello, I am a beginner in Angular and need to create an input field that looks like this: https://i.sstatic.net/LUXfJ.png Everything is going fine except for the Vorname placeholder at the top. How can I place it there? Currently, I am utilizing Angular ...

Adjust website content depending on user's authentication status

My goal is to display a logout button when the user is logged in and a login button if they are not. I am using JSON tokens to determine if a user is logged in or not, by checking if the token is null. However, this approach does not seem to be working. Ca ...

What is the best folder structure guideline for storing custom typings in a Vue project that utilizes TypeScript?

Where is the best place to store your custom type definition files in a Vue project? I typically use a directory called ./src/types along with this type of tsconfig: { "compilerOptions": { ... "typeRoots": [ "node_modules/@types", " ...

Learn how to host a singular instance of an Angular application for every unique route, similar to the setup utilized in meet.jit.si

Is there a way to create an Angular app that loads a new instance of itself on every route/url? For example, visiting http://happy-app.com/happy would show the app in one state, and going to http://happy-app.com/happier would load the same app in a differe ...

Utilizing async/await to pass a variable instead of subscribing to it

In my attempt to utilize the async/await method for a dual API call, I encountered an issue where variables within the second async function were not functioning properly or being rendered by Angular. const pokemon = this.httpClient .get(`https://pokeapi ...

Troubleshooting issues with Angular Material's basic mat-autocomplete functionality

After spending more than 72 hours trying to resolve this issue, I have hit a roadblock. Oddly enough, when I create a minimal working example in stackblitz, everything functions perfectly. The problem lies within a simple mat-autocomplete embedded within ...