Угловая сборка CLI с использованием base-href и deploy-url для доступа к активам на CDN

Фон

Я использую Angular CLI для создания проекта (с несколькими приложениями). Я хочу опубликовать приложения на отдельных подпутьях в моем домене, например example.com/apps/app1/.

Если я установил параметр --base-href в /apps/app1/ он решает все проблемы, связанные с маршрутизатором, и он будет загружать активы (js, css и images и т.д.) Просто отлично.

Если я использую службу 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-адрес и загружает файлы js и css из CDN. Он также решает ссылки URL-адреса изображения в файлах CSS с использованием URL-адреса CDN.


Эта проблема

При загрузке изображений или данных из папки с ресурсами динамически (в службе или шаблоне) я не могу найти хороший способ для этого разрешить URL-адреса, используя конфигурацию deploy-url.

Если я использую службу Location, она все еще использует base-href для разрешения URL-адресов, поэтому

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 если оно определено, тем более, что это будет общее решение, которое будет работать при размещении файлов в одном домене и при размещении файлов во внешнем домене.


Вопрос

Есть ли способ разрешить URL-адреса активов с учетом параметров base-href и deploy-url?

В идеале официальная функция Angular, такая как Location.prepareExternalUrl, но если я могу каким-то образом получить параметры base-href и deploy-url из Angular, я мог бы создать для себя собственный сервис.

Я бы не хотел определять URL-адреса в конфигурации среды, поскольку:

  1. Это потребует определенных конфигураций среды для каждого приложения
  2. Это создает потенциальный конфликт со значениями, которые предоставляются при создании приложения.

Ответ 1

Чтобы получить доступ к значению --deploy-url во время выполнения приложения, создайте deploy-url.ts с помощью:

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

И используйте этот фрагмент в вашем файле main.ts:

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));

Идея состоит в том, чтобы получить URL исполняемого в настоящий момент файла Javascript, который является main.js (или main.hash.js, если outputHashing включен), и удалить из него имя файла. Затем в ваших сервисах введите значение --deploy-url с @Inject(DEPLOY_URL) deployUrl: string в качестве параметра конструктора.

Ответ 2

Я столкнулся с точно такой же ситуацией, и, как вы описали в Фон, сборка с использованием набора base-href и deploy-url работает в том смысле, что мы можем обслуживать наши файлы CSS и JS. из CDN при размещении приложения на другом сервере.

В качестве решения для динамически загружаемых ресурсов в наших шаблонах мы написали API, который предоставляет переменные среды для этой цели, которые предоставляют соответствующие URL-адреса, необходимые для развертывания.

Ответ 3

Вот как я сделал для нескольких проектов.

Установите APP_BASE_HREF, используя динамическое значение, установленное сервером, например Cookie, и SPA считывает его при инициализации. Функция getBaseUrl просто читает значение cookie.

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

Установите deployUrl как часть вашего процесса CI. Вам нужно установить BUILD и VERSION динамически. Это можно сделать с помощью простого сценария оболочки.

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