37

Does anyone know how to accomplish this with the angular-cli? I would like to be able to store the baseHref path in an environment variable within /src/environments/environment.x.ts and based on the selected evironment during build, be able to set the baseHref path.

Something like this:

environment.ts

export const environment = {
  production: false,
  baseHref: '/'
};

environment.prod.ts

export const environment = {
  production: true,
  baseHref: '/my-app/'
};

And then call...

ng build --prod

...and have my /dist/index.html file show <base href="/my-app/">.

I thought maybe if I named my environment variable the same as the --base-href build option used in the build command that the cli might pick it up, but no dice there either.

Is there someway to reference an environment variable from the command line? Something like ng build --base-href environment.baseHref?

Mel
  • 5,837
  • 10
  • 37
  • 42
ryanulit
  • 4,983
  • 6
  • 42
  • 66
  • 1
    Why do you want the base href in the environment file? The base href in `index.html` can be configured with `--base-href your-url` – shusson Jan 07 '17 at 02:15
  • 9
    Because I need to run this on a build server with multiple, different deployment locations, and it makes sense to leverage the built-in functionality that angular provides (if possible). – ryanulit Jan 09 '17 at 15:44

4 Answers4

24

You would have to use APP_BASE_HREF

@NgModule({
  providers: [{provide: APP_BASE_HREF, useValue: environment.baseHref }]
})
class AppModule {}

See angular doc

EDIT

Since CSS/JS does not work with APP_BASE_HREF, you can do this:

In app.component.ts, inject DOCUMENT via import {DOCUMENT} from "@angular/platform-browser";

constructor(@Inject(DOCUMENT) private document) {
}

Then on your ngOnInit()

ngOnInit(): void {
    let bases = this.document.getElementsByTagName('base');

    if (bases.length > 0) {
      bases[0].setAttribute('href', environment.baseHref);

    }
  }
isherwood
  • 58,414
  • 16
  • 114
  • 157
penleychan
  • 5,370
  • 1
  • 17
  • 28
  • I'm assuming this should work, but I've noticed it doesn't update the index.html tag value. Won't that still cause problems? – ryanulit Jan 09 '17 at 15:58
  • No it shouldn't APP_BASE_HREF on your app.module.ts should override that tag on your index.html. You can test it out by commenting out the tag on your index.html it will still work if you have the APP_BASE_HREF defined on your module. – penleychan Jan 09 '17 at 16:20
  • I spoke too soon. While this works great for routing and navigation, it does not work for css/js file references. Those still get resolved using the tag and are returning 404s. Any more ideas? – ryanulit Jan 09 '17 at 18:23
  • Are you talking about global css/js? If so where are you putting those css/js references? In index.html? Or in angular-cli.json? – penleychan Jan 09 '17 at 18:40
  • 1
    Yes, I am talking about global css/js. I am adding any 3rd party refs within the angular-cli.json under the apps[0].styles and apps[0].scripts arrays respectively. Specifically though I am talking about the inline, vendor, main, etc. bundle files that angular-cli json compiles and minifies the project code into. Those try to resolve from the tag path instead of the path I provide for APP_BASE_HREF. – ryanulit Jan 09 '17 at 18:46
  • @12seconds Could you update your answer containing the imports too. I try to use this code and in the app.module.ts file it throws an error for environment variable. Where it comes from? How it is available in app.component.ts file? – AndrasCsanyi Mar 14 '17 at 14:44
  • 1
    @SayusiAndo environment variable is from a environment.ts file generated from angular-cli. If you are not using angular-cli you can create your own environment.ts file and export const variable of environment. (See the original question on how the variable is defined) – penleychan Mar 14 '17 at 14:55
  • 2
    DOCUMENT has now moved to the package `@angular/common` – ratatosk Aug 15 '17 at 06:37
  • 5
    Before reaching any javascript code (obtained from app.ts), the server must deliver files actually containing this code (e.g. main.bundle.js). If I publish this within a Web application that is not located within the Web site's root (IIS), all initial resources are served regardless of environment's baseHref. E.g. `http://localhost/Angular5Starter` will deliver `localhost/somefile.js` instead of `localhost/Angular5Starter`. Can this be handled or I still need `--base-href`? – Alexei - check Codidact Apr 19 '18 at 09:13
  • @Alexei you will need `--base-href` if it's not on your root of IIS. Maybe there might be a way to handle it with URL rewrite module on IIS, but I haven't explored that area. – penleychan Apr 19 '18 at 13:06
9

You need editing angular.json for production environment. Replace __BASE_HREF__ and __DEPLOY_URL__ constant with your desired path and enjoy.

  "configurations": {
    "production": {
      "baseHref": "__BASE_HREF__",
      "deployUrl": "__DEPLOY_URL__",
      "fileReplacements": [
        {
          "replace": "src/environments/environment.ts",
          "with": "src/environments/environment.prod.ts"
        }
      ],

Read about baseHref and deployUrl in https://angular.io/cli/serve

izimiky
  • 99
  • 1
  • 3
1

You can edit your angular.json and set build configuration for production pointing to different tsconfing file

angular.json

"targets": {
    "build": {
      "builder": "@angular-devkit/build-angular:browser",
      "options": {
        "tsConfig": "src/tsconfig.app.dev.json"
      },
      "configurations": {
        "production": {
         ...
         "tsConfig": "src/tsconfig.app.prod.json"
        }
      }
    }
...
}

tsconfig.app.prod.json

{
    "compilerOptions" : {
        "baseUrl" : "/my-app/",
        ......
    }
}

tsconfig.app.dev.json

{
    "compilerOptions" : {
        "baseUrl" : "/",
        ......
    }
}
Nas Tika
  • 29
  • 3
0

This approach worked for me:

 <body>
    <app-root></app-root>
    <script>
       this.document.getElementsByTagName('base')[0]
        .setAttribute('href', window.location.pathname);
    </script>
 </body>

Why it works: when the browser loads the index.html, the base href attribute is set with the current relative path. This is all you need to load the following runtime and main and polyfill javascript files from the correct path. This works also for assets.

This approach works for the local development environment as also for production.

And you don't need an environment variable to set what should be obviously the current relative path of the index.html.

Additional note: Maybe the HashLocationStrategy is required for this kind of solution:

{ provide: LocationStrategy, useClass: HashLocationStrategy }
Brain
  • 447
  • 7
  • 21