Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2, Angular-cli, Webpack - image assets not loading on github:pages after prod deploy


This is NOT a duplicate question:

This question explains the problem but that project was not built with angular-cli, as mine is, hence I do not have a webpack.config file.

Whilst the issue I describe below is clearly about getting the base_url setting correct, it is not the same as this issue, which is about setting up angular to send requests to a base_url like an api.


My project builds and runs on localhost and also on github:pages (even the css all loads correctly). The only thing which does not work on github:pages are the images, which all return 404s (even though I can see them if I navigate to the assets folder directly in the browser).

The problem is that on localhost, angular-cli runs the project with no subfolder after the hostname. But on github:pages it does.

Say for example the project name is testapp then on github:pages it is deployed here:

https://<username>.github.io/testapp

The images are in

src/assets/images

They are referenced in css inside angular-2 component using relative paths like this:

background-image: url('../../assets/images/dining-room.png');

So how do I configure angular-2 production deployment file so that in production the path becomes:

background-image: url('testapp/assets/dining-room.png');

I understand that github:pages is based off Jekyll and I understand this explanation, but what I don't understand is how do you configure an angular-cli project to be aware that github:pages is using a folder to deploy the app.


UPDATE 1

So far I have figured out that the command line for deploying to github:pages has a base_href option. So I can do this:

ng github-pages:deploy --base-href /testapp/

I can then see in the /dist folder that the html file has been changed to include the base href, like this:

<base href="/testapp/">

I would have expected this to fix the problem automatically, but the images still return a 404. This base_href is not being automatically injected into the relative paths, as you would expect. Locally the index.html file has <base href="/"> and obviously that works.


UPDATE 2

In trying to solve this I am coming to believe this is related to the way Angular builds components. A very good explanation of that can be found here.


EDIT added angular-cli.json
{
  "project": {
    "version": "1.0.0-beta.22-1",
    "name": "floorbook"
  },
  "apps": [
    {
      "root": "src",
      "outDir": "dist",
      "assets": [
        "assets",
        "favicon.ico"
      ],
      "index": "index.html",
      "main": "main.ts",
      "test": "test.ts",
      "tsconfig": "tsconfig.json",
      "prefix": "fb",
      "mobile": false,
      "styles": [
        "styles.css"
      ],
      "scripts": [],
      "environments": {
        "source": "environments/environment.ts",
        "dev": "environments/environment.ts",
        "prod": "environments/environment.prod.ts"
      }
    }
  ],
  "addons": [],
  "packages": [],
  "e2e": {
    "protractor": {
      "config": "./protractor.conf.js"
    }
  },
  "test": {
    "karma": {
      "config": "./karma.conf.js"
    }
  },
  "defaults": {
    "styleExt": "css",
    "prefixInterfaces": false,
    "inline": {
      "style": false,
      "template": false
    },
    "spec": {
      "class": false,
      "component": true,
      "directive": true,
      "module": false,
      "pipe": true,
      "service": true
    }
  }
}
like image 688
rmcsharry Avatar asked Dec 29 '16 14:12

rmcsharry


1 Answers

Understanding that ALL components in Angular2 are declared as relative paths was the key to solving this. Simply put this means when ng is building/compiling your project, everything is relative to ROOT. See the link UPDATE 2 in the question.

So, my CSS files is local to the component and 2 folders deep in my app/src hierarchy. This is why I was referencing images like so:

../../assets/images/<file>.png

But when angular builds /assets/images is at ROOT - you can see that in the DIST folder after building (i.e. after running ng github-pages:deploy)

So all I needed to do was change the css to reference directly from root (ie. ignore that this css file is 2 folders deep in a component):

assets/images/<file>.png

Then build with:

ng github-pages:deploy --base-href /testapp/

In production, those images links will then work since /testapp/ is now the root, and they are relative to root, hence:

/testapp/assets/images/<file>.png


Answer to what I thought was the problem - how to access APP_BASE_HREF from inside a component

For future reference, others coming to this question might be thinking as I was and that access is needed to base-href directly in the component to solve this problem. Since I figured out how to do that, I thought I would add it here:

1 - In your app.module.ts you need to import it and provide it:

import { APP_BASE_HREF } from '@angular/common';

providers: [{provide: APP_BASE_HREF, useValue : '/your-value/'}]

WARNING - note that this is now hard coding your production base-href. This overrides whatever you have set in index.html (so using the ng build command line option will be pointless, as that is what creates that setting in the index.html inside the DIST folder).

2 - In your component add 2 imports and inject APP_BASE_REF in the constructor:

import { APP_BASE_HREF } from '@angular/common';
import { Inject } from '@angular/core';

constructor(@Inject(APP_BASE_HREF) private baseHref:string) { 
  console.log(this.baseHref);
}

IMPORTANT NOTE

If in step 1 above if you set your value to:

useValue : '/'

and then deploy to github:pages...after you browse to your app, it will stop using the folder name (it simply disappears from the address bar after the app loads...although the app will continue to function).

AND FINALLY

As of Dec 30 2016 it is not possible to have images inside the component and reference them using local relative paths. See this and this.

like image 137
rmcsharry Avatar answered Oct 19 '22 23:10

rmcsharry