Angular Universal: исключить из объединения зависимости только для узлов

У меня есть приложение, созданное с помощью углового универсального "@nguniversal/express-engine": "^9.1.1". Я пытаюсь добавить холст узла на стороне сервера ("canvas": "^2.6.1") для рендеринга определенных изображений на сервере. Мне не нужно, чтобы эта библиотека была доступна на стороне клиента, и поэтому я хочу исключить ее из пакета.

Однако при попытке запустить приложение с npm run dev:ssr я получаю ошибки, связанные с этой библиотекой:

ERROR in ./node_modules/canvas/build/Release/canvas.node 1:0
Module parse failed: Unexpected character '�' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are 
configured to process this file. See https://webpack.js.org/concepts#loaders
(Source code omitted for this binary file)
this.debug is not a function

После некоторых исследований я обнаружил, что опция externalDependencies была добавлена ​​к angular.json опциям сборки сервера. Я попытался добавить путь к библиотеке canvas в массив externalDependencies, но это не дало никакого результата. Ошибка все еще есть. И сборка терпит неудачу.

В настоящее время я использую динамическую import() для загрузки библиотеки холста в один из сервисов angular, если платформа server. По какой-то причине я предположил, что по умолчанию он не будет пытаться связывать динамически импортированные скрипты. Может быть, есть какие-то другие обходные пути.

Итак, резюмируя, в идеале я хотел бы иметь некий сервис, доступный только на стороне сервера, и внутри него использовалась бы библиотека canvas. И не сломает угловатую сборку.


person Daniil Andreyevich Baunov    schedule 31.05.2020    source источник


Ответы (1)


Включить только в комплект сервера

В настоящее время я использую динамический импорт() для загрузки библиотеки холста в один из угловых сервисов, если платформа является сервером.

Это включает эту зависимость в любой пакет, который использует ваш сервис (чанг с холстом может быть все еще загружен лениво, но веб-пакет все равно должен его обработать).

Идиоматический способ сделать это в Angular — через внедрение зависимостей:

// no side effect here - safe to import in browser or server files
// canvas-polyfill.token.ts
export type PolyfillLoader = () => Promise<any>;
export const CANVAS_POLYFILL_LOADER = new InjectionToken<PolyfillLoader>();

// app.server.module.ts
const canvasLoader = () => import('canvas');

@NgModule({
   ...
   providers: [{provide: CANVAS_POLYFILL_LOADER, useValue: canvasLoader}]
})
export class AppServerModule {}

// your service
@Injectable()
class MyService {
  constructor(@Optional() @Inject(CANVAS_POLYFILL_LOADER) private polyfillLoader: PolyfillLoader) {}

  doYourStuff() {
    const whenReady = this.polyfillLoader ? this.polyfillLoader() : Promise.resolve();

    return whenReady.then(() => {
      // do something useful
    })
  }
}

Проблема с веб-пакетом

Сказав все вышесказанное, по-прежнему нет гарантии, что угловой веб-пакет сможет обработать эту зависимость при создании серверного пакета. Если вы хотите не включать его в свой пакет и оставить внешним, вы можете установить параметр bundleDependencies: false для вашего сборщика серверов в angular.json. Однако у него есть побочный эффект, заключающийся в том, что код отладки не удаляется из библиотек angular, поэтому вам нужно будет выполнить дополнительные шаги, чтобы подготовить приложение к работе (см. https://angular.io/guide/ivy-compatibility#payload-size-debugging для некоторых подсказок)

person amakhrov    schedule 04.06.2020