Background / Goal
- I have an app with multiple environments, each stored in a subfolder of a CDN.
- e.g.
cdn.com/dev
,cdn.com/test
- e.g.
- My goal is to load the dev site (
cdn.com/dev/index.html
) and have it load the corresponding resources from the/dev/
path.
⚠️ℹ️ We are doing a build-once, deploy-many strategy, so I do not have the ability to pass the baseHref as part of a build process or similar.
The Problem
So far no matter what I've tried, cdn.com/dev/index.html
attempts to load scripts from the root (cdn.com/script.js
) instead of the subfolder (cdn.com/dev/script.js
)
What I've Tried
❌ Attempt 1: Set APP_BASE_HREF
and use it as a provider
I set a window variable in index.html
:
<script>
window['base-href'] = window.location.pathname;
console.log(window['base-href']);
</script>
Then I attempt to use that value to pass to APP_BASE_HREF
as part of the provider, in app.module.ts
:
import { APP_BASE_HREF } from '@angular/common';
let baseHref = (window as { [key: string]: any })["base-href"] as string;
if (!baseHref.endsWith("/")) {
baseHref = "/";
}
// I only updated the providers array below
@NgModule({
declarations: [
AppComponent,
ComingSoonListComponent
],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule
],
providers: [
{
provide: APP_BASE_HREF,
useValue: baseHref
}
],
bootstrap: [AppComponent]
})
This did not appear to work.
❌ Attempt 2: A slightly less naive attempt
I remove the base
tag from the index.html page on the off-chance it's overriding things.
In index.html, I call the script to capture the pathname:
<script>
window['base-href'] = window.location.pathname;
console.log(window['base-href']);
</script>
</
In app.module.ts
, I create a factory method that captures the window value, and then use it:
const baseHrefFactory = () => {
let baseHref = (window as { [key: string]: any })["base-href"] as string;
if (!baseHref.endsWith("/")) {
baseHref = "/";
}
console.log('TS: using baseHref of:', baseHref);
return baseHref;
}
// Note I just use the factory method below
@NgModule({
declarations: [
AppComponent,
ComingSoonListComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
],
providers: [{ provide: APP_BASE_HREF, useFactory: baseHrefFactory }],
bootstrap: [AppComponent],
})
export class AppModule { }
- I can see the window value being set (per console logging)
- It appears other files try to load before we can programmatically trigger the
APP_BASE_HREF
factory, and are attempted to load from the root path rather than the path I'd set. When running locally, it appears to work fine, but likely only because the path is/
naturally.
❌ Attempt 3: Set the base
href directly in HTML
In index.html
in the <head>
tag, after the base
tag has been created:
<script>
var baseHref = window.location.pathname;
if (!baseHref.endsWith("/")) {
baseHref = "/";
}
console.log("setting a baseHref of:", baseHref);
document.getElementsByTagName("base")[0].href = baseHref;
</script>
- ✅ The index.html script I added is running (I see the console log)
- ✅ The appropriate base path is being picked up (
/dev/
– I see it in the console log) - ✅ The base tag is being set correctly (I can see this by inspecting via the browser dev tools)
- ❌ The URL being requested in the browser does not contain
/dev/
- Actual URL:
cdn.com/script.js
- Expected URL:
cdn.com/dev/script.js
- Actual URL:
❓(Not Yet attempted) Do I have to modify this at deploy time?
Do I need my deployment script to physically modify index.html
to use the correct href
in the <base>
tag? That would be surprising, but I suppose it's possible. Seems like this would definitely be an answer; just hoping it's not the answer.
Question
How do I, at runtime, modify the base path so that Angular will download resources from the correct URL, including the sub-path from the CDN endpoint? Am I able to do this at runtime, or do I need to set this programmatically in the HTML at deployment time?
CodePudding user response:
Can you set the base href to something relative?
ng build --base-href ./
This will load the files relative to where your index file is.
CodePudding user response:
As far as I have been able to determine, the only ways to modify the base href is:
- ❌ With the
angular.json file
-- but this would be applied at build time, and so wouldn't work for a build-once, deploy-many scenario - ❌ With the command line, e.g.
ng build --base-href="./dev"
-- but again, this is applied at build time, and wouldn't apply to all the deployed environments after that one build. - ❌ With the contents of the
<base>
tag withinindex.html
itself. But again, when deployed to multiple places, this won't meet my needs.
So, as far as I am able to tell, the solution in this case for me will be to have the deployment script modify index.html
to ensure the base
tag within it aligns with the environment it's being deployed to.