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.
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.
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.
{
"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
}
}
}
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With