如何在初始化之前以编程方式设置 Angular 基本路径?
How can I set the Angular base path programmatically prior to initialization?
背景/目标
- 我有一个具有多个环境的应用程序,每个环境都存储在 CDN 的子文件夹中。
- 例如
cdn.com/dev
、cdn.com/test
- 我的目标是加载开发站点 (
cdn.com/dev/index.html
) 并让它从 /dev/
路径加载相应的资源。
⚠️ℹ️ 我们正在执行构建一次,部署多次的策略,因此我无法将 baseHref 作为构建过程或类似过程的一部分进行传递。
问题
到目前为止,无论我尝试过什么,cdn.com/dev/index.html
都会尝试从根目录 (cdn.com/script.js
) 而不是子文件夹 (cdn.com/dev/script.js
)
加载脚本
我尝试过的
❌ 尝试 1:设置 APP_BASE_HREF
并将其用作提供者
我在index.html
中设置了一个window变量:
<script>
window['base-href'] = window.location.pathname;
console.log(window['base-href']);
</script>
然后我尝试使用该值作为提供程序的一部分传递给 APP_BASE_HREF
,在 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]
})
这似乎没有用。
❌ 尝试二:稍微不那么幼稚的尝试
我从 index.html 页面上删除了 base
标签,以防它覆盖了某些内容。
在index.html中,我调用脚本捕获路径名:
<script>
window['base-href'] = window.location.pathname;
console.log(window['base-href']);
</script>
</
在app.module.ts
中,我创建了一个捕获window值的工厂方法,然后使用它:
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 { }
- 我可以看到正在设置 window 值(根据控制台日志记录)
- 在我们以编程方式触发
APP_BASE_HREF
工厂之前,似乎有其他文件尝试加载,并且尝试从根路径而不是我设置的路径加载。当 运行 在本地时,它似乎工作正常,但可能只是因为路径自然是 /
。
❌ 尝试3:直接在HTML
中设置base
href
在 <head>
标签的 index.html
中,创建 base
标签后:
<script>
var baseHref = window.location.pathname;
if (!baseHref.endsWith("/")) {
baseHref += "/";
}
console.log("setting a baseHref of:", baseHref);
document.getElementsByTagName("base")[0].href = baseHref;
</script>
- ✅ 我添加的index.html脚本是运行(我看控制台日志)
- ✅ 正在选择适当的基本路径(
/dev/
– 我在控制台日志中看到它)
- ✅ 基本标签设置正确(我可以通过浏览器开发工具检查看到这一点)
- ❌浏览器中请求的URL不包含
/dev/
- 实际 URL:
cdn.com/script.js
- 预期 URL:
cdn.com/dev/script.js
❓(尚未尝试)我必须在部署时修改它吗?
我是否需要我的部署脚本来物理修改 index.html
以在 <base>
标记中使用正确的 href
?这将是令人惊讶的,但我认为这是可能的。看来这肯定是一个的答案;只是希望这不是 答案。
问题
如何在运行时修改基本路径,以便 Angular 从正确的 URL 下载资源,包括来自 CDN 端点的子路径?我可以在运行时执行此操作,还是需要在部署时以编程方式在 HTML 中进行设置?
你能把 base href 设置成相对的东西吗?
ng build --base-href ./
这将加载相对于索引文件所在位置的文件。
据我所知,修改基本 href 的唯一方法是:
- ❌ 使用
angular.json file
-- 但这将在构建时应用,因此不适用于 build-once、deploy-many 场景
- ❌ 使用命令行,例如
ng build --base-href="./dev"
-- 但同样,这是在构建时应用的,不会应用于构建之后的所有部署环境。
- ❌
<base>
标签的内容在 index.html
本身。但是同样,当部署到多个地方时,这将不能满足我的需求。
因此,据我所知,在这种情况下,我的解决方案是让部署脚本修改 index.html
以确保其中的 base
标记与部署到的环境。
我写了一个可以在部署过程中使用的小型 PowerShell 脚本,以防其他人方便使用:
<#
.SYNOPSIS
Modifies an HTML file to set the base href with the appropriate CDN endpoint.
.EXAMPLE
# Can use relative path to file
.\TransformBaseHref.ps1 -PathToHtmlFile ..\code\webapp\dist\webapp\index.html -CDNPath "EnvironmentName"
.EXAMPLE
# Can use full path to file
.\TransformBaseHref.ps1 -PathToHtmlFile C:\path\to\index.html -CDNPath "EnvironmentName"
.EXAMPLE
# When index.html is in Current directory
.\TransformBaseHref.ps1 -PathToHtmlFile index.html -CDNPath "EnvironmentName"
#>
Param (
[Parameter(Mandatory = $true, HelpMessage = "The path to the html file to be updated.")]
[string] $PathToHtmlFile,
[Parameter(Mandatory = $true, HelpMessage = "The name of the CDN subfolder, e.g. 'develop' for the development environment")]
[string] $CDNPath
)
((Get-Content $PathToHtmlFile).Replace("<base href=""/"">", "<base href=""/$CDNPath/"">")) | Set-Content $PathToHtmlFile
背景/目标
- 我有一个具有多个环境的应用程序,每个环境都存储在 CDN 的子文件夹中。
- 例如
cdn.com/dev
、cdn.com/test
- 例如
- 我的目标是加载开发站点 (
cdn.com/dev/index.html
) 并让它从/dev/
路径加载相应的资源。
⚠️ℹ️ 我们正在执行构建一次,部署多次的策略,因此我无法将 baseHref 作为构建过程或类似过程的一部分进行传递。
问题
到目前为止,无论我尝试过什么,cdn.com/dev/index.html
都会尝试从根目录 (cdn.com/script.js
) 而不是子文件夹 (cdn.com/dev/script.js
)
我尝试过的
❌ 尝试 1:设置 APP_BASE_HREF
并将其用作提供者
我在index.html
中设置了一个window变量:
<script>
window['base-href'] = window.location.pathname;
console.log(window['base-href']);
</script>
然后我尝试使用该值作为提供程序的一部分传递给 APP_BASE_HREF
,在 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]
})
这似乎没有用。
❌ 尝试二:稍微不那么幼稚的尝试
我从 index.html 页面上删除了 base
标签,以防它覆盖了某些内容。
在index.html中,我调用脚本捕获路径名:
<script>
window['base-href'] = window.location.pathname;
console.log(window['base-href']);
</script>
</
在app.module.ts
中,我创建了一个捕获window值的工厂方法,然后使用它:
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 { }
- 我可以看到正在设置 window 值(根据控制台日志记录)
- 在我们以编程方式触发
APP_BASE_HREF
工厂之前,似乎有其他文件尝试加载,并且尝试从根路径而不是我设置的路径加载。当 运行 在本地时,它似乎工作正常,但可能只是因为路径自然是/
。
❌ 尝试3:直接在HTML
中设置base
href
在 <head>
标签的 index.html
中,创建 base
标签后:
<script>
var baseHref = window.location.pathname;
if (!baseHref.endsWith("/")) {
baseHref += "/";
}
console.log("setting a baseHref of:", baseHref);
document.getElementsByTagName("base")[0].href = baseHref;
</script>
- ✅ 我添加的index.html脚本是运行(我看控制台日志)
- ✅ 正在选择适当的基本路径(
/dev/
– 我在控制台日志中看到它) - ✅ 基本标签设置正确(我可以通过浏览器开发工具检查看到这一点)
- ❌浏览器中请求的URL不包含
/dev/
- 实际 URL:
cdn.com/script.js
- 预期 URL:
cdn.com/dev/script.js
- 实际 URL:
❓(尚未尝试)我必须在部署时修改它吗?
我是否需要我的部署脚本来物理修改 index.html
以在 <base>
标记中使用正确的 href
?这将是令人惊讶的,但我认为这是可能的。看来这肯定是一个的答案;只是希望这不是 答案。
问题
如何在运行时修改基本路径,以便 Angular 从正确的 URL 下载资源,包括来自 CDN 端点的子路径?我可以在运行时执行此操作,还是需要在部署时以编程方式在 HTML 中进行设置?
你能把 base href 设置成相对的东西吗?
ng build --base-href ./
这将加载相对于索引文件所在位置的文件。
据我所知,修改基本 href 的唯一方法是:
- ❌ 使用
angular.json file
-- 但这将在构建时应用,因此不适用于 build-once、deploy-many 场景 - ❌ 使用命令行,例如
ng build --base-href="./dev"
-- 但同样,这是在构建时应用的,不会应用于构建之后的所有部署环境。 - ❌
<base>
标签的内容在index.html
本身。但是同样,当部署到多个地方时,这将不能满足我的需求。
因此,据我所知,在这种情况下,我的解决方案是让部署脚本修改 index.html
以确保其中的 base
标记与部署到的环境。
我写了一个可以在部署过程中使用的小型 PowerShell 脚本,以防其他人方便使用:
<#
.SYNOPSIS
Modifies an HTML file to set the base href with the appropriate CDN endpoint.
.EXAMPLE
# Can use relative path to file
.\TransformBaseHref.ps1 -PathToHtmlFile ..\code\webapp\dist\webapp\index.html -CDNPath "EnvironmentName"
.EXAMPLE
# Can use full path to file
.\TransformBaseHref.ps1 -PathToHtmlFile C:\path\to\index.html -CDNPath "EnvironmentName"
.EXAMPLE
# When index.html is in Current directory
.\TransformBaseHref.ps1 -PathToHtmlFile index.html -CDNPath "EnvironmentName"
#>
Param (
[Parameter(Mandatory = $true, HelpMessage = "The path to the html file to be updated.")]
[string] $PathToHtmlFile,
[Parameter(Mandatory = $true, HelpMessage = "The name of the CDN subfolder, e.g. 'develop' for the development environment")]
[string] $CDNPath
)
((Get-Content $PathToHtmlFile).Replace("<base href=""/"">", "<base href=""/$CDNPath/"">")) | Set-Content $PathToHtmlFile