angularprogressive-web-appsangular-pwaangularbuild

How to run Angular PWA directly on http-server? files throw 404 not found


So, I have tried making a fresh new angular app work with the PWA capabilities that Angular provides, but all I get is 404 when I try to access my PWA app. I have read hundreds of posts both here and on other sites, with no luck.

What do I want?

-Run a fresh new angular project and add the pwa package through angular cli

What have I done so far?

-I have done everything according to the angular docs. I made a new project on angular 17 with the cli command: ng new myProject, where I pressed "yes" when being asked if I wanted to add routing. Without altering anything, I just added pwa capabilities through the command ng add @angular/pwa . This did indeed add all needed files such as webmanifest, icons etc. and did alter some files just like it is supposed to. Then, without doing ANY changes at all, I built the project with ng build. Then at last, I ran the server like this: http-server -p 8080 -c-1 -o dist/

What is then the problem?

When the server runs and I go to http://127.0.0.1:8080/dist/ I am met with a page that says: Index of /dist/ and it list some files. When I then click on the folder "myProject", five network calls fail with 404 not found and I am met with a blank page...

What have I tried in order to fix this?

Many things! First I did try it with angular 17, but I suspected it could be a problem with the new angular version, so I tried with angular 16. Same problem! I have tried running the http server differently, with npx, without the parameters, without specifying port... Same problem! Then I read that you would need the project to be built with production, so I tried with ng build --configuration="production", still no cigar... I tried building inside the src folder, outside the src folder... Same problem. I tried running the http server on the project root, further down inside the dist/...Still no cigar!! I feel I have tried everything, and it seems like my project(s) just won't work with the PWA stuff. ng serve works, but then of course without the much needed functionality from PWA.

Details:

What do I think the problem is?

I think it might have something to do with folder structure. It says 404 not found on several of these files, so I think it somehow cannot find these files... But why? I can understand how this should not work out of the box when I just made a ng new, ng add pwa, ng build and then serve, without doing any other changes at all.

Thanks so much in advance to those who want to help me. I have tried everything I can in order to make this work, but I only came so far...

serving How it looks localhost network tab when entering keyProject dev console when entering keyProject


Solution

  • TLDR; http-server path should match the build base-href


    There's two issues with steps you described, when using ng build, you'll get this folder structure:

    // Note: in old versions of angular, folders `key-project` and `browser` are not 
    // created, `index.html` would be a direct child of `dist`.
    
    dist
     └── key-project
          └── browser
               └── index.html
    
    1. That folder structure is not meant to be "seen" directly from a webserver because in order to open your app you'll need to navigate to http://localhost:8080/dist/key-project/browser (the issue is caused by this)
    2. You're building your app with no name, the deployment name can be set with the --base-href parameter

    You can check by yourself by looking at your compilled index.html source file, you'll see this line:

    <base href="/">
    

    That line means that all the internal js/css/etc files that your application needs must be inside that relative path to your server domain.

    With that in mind, if you run http-server -p 8080 -c-1 -o dist/key-project/browser, you'll sure be able to see your web application static content, but all the JS/CSS file references will show 404 errors because of your current folder structure. So, you'll have to "fix" your compillation to match the one of http-server.


    Solution #1

    Instead of ng build alone, add the base-href param to indicate the correct urls:

    // very important to keep both slashes, at start and the end
    ng build --base-href=/dist/key-project/browser/
    

    With that, you'll get this for your base href:

    <base href="/dist/key-project/browser/">
    

    After that, you should be able to run http-server without any 404 errors:

    npx http-server -p 8080 -c-1 -o dist/key-project/browser
    

    Solution #2

    Unless you're migrating an old angular application to the latest version; this solution is not recommended, as it basically sets the configuration back to how it was before the angular default build changes, the configuration is done inside your angular.json file, this are the attributes you should set:

    // Note: This configuration, basically removes `ssr` and `ssg` capabilities.
    {
      "projects": {
         "architect": {
            "builder": "@angular-devkit/build-angular:browser", // <-- Modify
            "build": {
              "options": {
                 "outputPath": "dist",                          // <-- Modify
                 "main": "src/main.ts",                         // <-- Add
                 "baseHref": "/dist/"                           // <-- Add
                 // "browser": "src/main.ts",                   // <-- Remove
                 // "server": "src/main.server.ts",             // <-- Remove
                 // "prerender": true,                          // <-- Remove
                 // "ssr": "..."                                // <-- Remove
                 ...
              },
              "configurations": {
                 "production": {
                     "serviceWorker": true,                     // <-- Modify
                     ...                     
                 }
                 ...
              },
              ...
            }
            ...
         } 
      }
    }
    

    After those changes, you should be able to execute exactly the steps mentioned in the documentation:

    // (1) build directly
    ng build
    // (2) run http-server directly
    npx http-server -p 8080 -c-1 dist/
    

    Alternatively, for development is preferred that you use ng serve and only for production set the base-href value, as those builds are meant to be deployed, usually in production you won't have to navigate that whole path, so it'll do to just set it to --base-href=key-project