【问题标题】:Angular CLI build using base-href and deploy-url to access assets on CDNAngular CLI 使用 base-href 和 deploy-url 构建以访问 CDN 上的资产
【发布时间】:2018-06-01 19:10:08
【问题描述】:

背景

我正在使用 Angular CLI 构建一个项目(包含多个应用程序)。我想在我的域上的单独子路径上发布应用程序,例如 example.com/apps/app1/

如果我将--base-href 参数设置为/apps/app1/,它可以解决有关路由器的任何问题,并且它会很好地加载资产(JS、CSS 和图像等)。

如果我使用Location 服务,我可以使用

this.location.prepareExternalUrl('/assets/data/data.json')

解析动态加载的资产(它们将解析为/apps/app1/assets/data/data.json)。

到目前为止一切顺利。但我现在想通过 CDN 提供应用程序资产,例如cdn.example.com,同时将应用程序本身托管在原始 URL example.com/apps/app1/`上。所以现在我使用以下方法构建应用程序:

 ng build -prod --app app1 --base-href "/apps/app1/" --deploy-url "http://cdn.example.com/app-assets/apps/app1/"

这一次,我同时应用了--base-href--deploy-url 参数。它很好用,因为它使用 base-href 来帮助路由器解析 URL,并从 CDN 加载 js 和 CSS 文件。它还使用 CDN URL 解析 CSS 文件中的图像 URL 引用。


问题

从资产文件夹动态(在服务或模板中)加载图像或数据时,我找不到使用它解析 URL 的好方法deploy-url 配置。

如果我使用Location 服务,它仍然使用base-href 来解析网址,所以

this.location.prepareExternalUrl('/assets/data/data.json')

仍将解析为 /apps/app1/assets/data/data.json 而不是 http://cdn.example.com/app-assets/apps/app1/assets/data/data.json

如果定义了 deploy-url 值,我希望它会使用它,特别是因为这将是一个通用解决方案,在将文件托管在同一域上以及在外部域上托管文件时都可以使用。


问题

考虑到base-hrefdeploy-url 参数,有没有办法解析资产URL?

理想情况下,像Location.prepareExternalUrl 这样的官方Angular 函数,但如果我能以某种方式从Angular 获取base-href 和deploy-url 参数,我可以为它构建自己的服务。

我不想在环境配置中定义 URL,因为:

  1. 每个应用都需要特定的环境配置
  2. 它会与构建应用程序时提供的值产生潜在冲突。

【问题讨论】:

  • 我将尝试或完全删除基本标记或将 替换为 document.write('');脚本>
  • @Eliseo 路由器需要 base-href 才能在子文件夹中工作,而且它看起来不像在这里干扰。麻烦的是,显然无法访问 deploy-url 值。在查看了Location.prepareExternalUrl 函数的source 之后,很明显它查看了base-href。删除基本标签对我没有帮助,恐怕......
  • 并用脚本替换?我认为您必须使用标签策略
  • @Eliseo 散列策略也无济于事,因为除了在模板或服务中加载外部源时获得外部源的可靠路径外,一切正常。 index.html 文件中的 js 和 css 文件被正确引用(我目前正在使用一个丑陋的黑客从这些脚本标签中读取 url)。
  • @JamAndJammies 据我所知,它目前不受支持。作为临时解决方法,我正在文档中寻找 main.bundle.js 脚本标记并从那里提取路径。一旦我们找到合理的方法来处理这个问题,我会立即替换该代码。

标签: angular angular-cli


【解决方案1】:

要在应用程序运行时访问 --deploy-url 值,请使用以下命令创建 deploy-url.ts

export const DEPLOY_URL = new InjectionToken<string>('deployUrl');

并在你的 main.ts 文件中使用这个 sn-p:

const deployUrl = (function() {
  const scripts = document.getElementsByTagName('script');
  const index = scripts.length - 1;
  const mainScript = scripts[index];
  return mainScript.src.replace(/main.*?\.js$/, '');
})();

const DEPLOY_URL_PROVIDER = {
  provide: DEPLOY_URL,
  useValue: deployUrl,
};

platformBrowserDynamic([DEPLOY_URL_PROVIDER])
  .bootstrapModule(AppModule)
  .catch(err => console.error(err));

这个想法是获取当前执行的 Javascript 文件的 url,它是 main.js(或 main.hash.js,如果启用了outputHashing)并从中删除文件名。然后在您的服务中注入 --deploy-url 值,并将 @Inject(DEPLOY_URL) deployUrl: string 作为构造函数参数。

【讨论】:

【解决方案2】:

这是我解决这个“BS”问题的方法。当您的应用程序用于例如托管在 www.domain.de/hehe.

  1. angular.json 添加"deployUrl": "./",
  2. src/index.html 里面&lt;head&gt; 添加/更新&lt;base href="./"&gt;
  3. 在整个应用程序中,您将使用资产的相对路径以及诸如此类的东西:&lt;img src="./assets/img/pictureOfMyCrazyWife.png"&gt;
  4. 方便地运行ng buildng build --prod

通过这些简单的步骤,您就有了一个通用的设置。所以无论是www.domain.de/hehewww.domain.de/hehe2www.domain.de/ 还是www.domain.de/lol,它都会起作用

【讨论】:

  • 这个解决方案似乎很合理。 1)有什么警告吗? 2)为什么不是angular社区默认的方式?
  • 这对我不起作用。我正在尝试在www.domain.com/directory 中部署应用程序,当我将base-href 设置为directory 时,它可以工作,但是图像不会加载。不知道发生了什么。
【解决方案3】:

我遇到了完全相同的情况,正如您在 背景 中所述,使用 base-hrefdeploy-url 集进行构建确实有效,因为我们能够提供我们的服务在另一台服务器上托管应用程序时,来自 CDN 的 css 和 js 文件。

作为在我们的模板中动态加载资产的解决方案,我们编写了一个 API,为此目的提供环境变量,从而提供每次部署所需的适当 URL。

【讨论】:

    【解决方案4】:

    这是我为几个项目所做的。

    使用服务器设置的动态值设置 APP_BASE_HREF,例如 Cookie 和 SPA 在初始化时读取它。 getBaseUrl 函数只需读取一个 cookie 值。

    { provide: APP_BASE_HREF, useFactory: () => getBaseUrl() }
    

    将 deployUrl 设置为 CI 流程的一部分。您需要动态设置 BUILD 和 VERSION。这可以通过使用一个简单的 shell 脚本来完成。

    https://my-cloud.cloudfront.net/my-app/{BUILD}/{VERSION}/
    

    【讨论】:

      猜你喜欢
      • 2018-12-13
      • 2020-08-09
      • 2022-08-03
      • 2020-05-31
      • 2020-12-06
      • 2017-07-06
      • 2019-01-21
      • 2021-11-19
      • 1970-01-01
      相关资源
      最近更新 更多