Angular 9 Сбой универсального SSR на отложенном загруженном маршруте с HTTP-вызовом - PullRequest
1 голос
/ 13 апреля 2020

У меня есть приложение Angular 9 (v9.0.6), работающее корректно с Universal (SSR), и я выполнял последний набор тестов перед переходом на PROD, когда заметил, что приложение зависло со 100% -ной загрузкой ЦП. Я проанализировал ошибку и оказался проблемой, когда приложение Angular загружает напрямую маршрут, который является лениво загруженным модулем, который выполняет HTTP-вызов.

Если я загружаю angular через Home (или другой маршрут без HTTP - но даже дома, другой лениво загруженный модуль имеет тот же компонент, который выполняет HTTP-вызов), все работает нормально. Я могу перемещаться по всем маршрутам без каких-либо проблем, и приложение работает как шарм. Если, однако, я go, скажем, www.mywebsite/lazy-loaded-module прямо в новой вкладке, я полагаю, что в процессе bootstrap есть что-то, что препятствует правильной регистрации всех регистраций или, по крайней мере, модуля HTTPClientModule, а затем я получить ошибку.

Для начала, я зарегистрировал HTTPClientModule только один раз в AppModule. Я получаю ошибку:

(node:17624) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.

Процессор переходит на 100%, и приложение зависает. Опять же, этого не произойдет, если я go до www.my-website.com, тогда я перейду через приложение к /my-lazy-loaded-module

Я попробовал что-то еще: включение (я знаю, что не должен) HTTPClientModule внутри моего модуль с отложенной загрузкой, и он работал так же, как и в случае проблемы с процессором, исчез, однако я получил другую ошибку:

ReferenceError: XMLHttpRequest is not defined
    at BrowserXhr.build

, которая влияет на контент, который я бы извлек с использованием SSR и рендеринга, потому что его нет. Как обходной путь, который мог бы сделать это, но я хотел бы знать, как это должно быть решено. Версия node, которую я выполняю: v10.16.2

ОБНОВЛЕНИЕ

Для большей наглядности вокруг выполняемого мной HTTP-вызова это просто стандартный вызов:

public getNext = (page: number, pageSize: number): Promise<IEventsPaged> => {
        return this.http.get<IEventsPaged>(`${environment.apiBaseUrl}/events?page=${page}&pageSize=${pageSize})
                        .toPromise()
                        .then(r => r)
                        .catch((error: Response | any) => {
                            return Promise.reject(error);
                        });
    }

ОБНОВЛЕНИЕ 2

Я обновился до Angular 9.1.1, в котором исправлено предупреждение о буфере. Приложение все еще зависает, и это происходит только на одном модуле. Другие модули также выполняют HTTP-вызов (тот же стандартный get, но с другим сервисом) без проблем.

** ОБНОВЛЕНИЕ 3 **

Я нашел причину root вопрос. В конечном итоге это не имеет ничего общего с HTTP. Происходило то, что на странице, на которую я ссылаюсь, анимация angular очень простая. Это треугольник, который становится больше или меньше, применяя бесконечную анимацию с помощью стандартной angular анимации. Чтобы достичь бесконечного эффекта, я подключился к событию animation.done, чтобы изменить состояние на большое или маленькое. Что ж, если вы жестко обновите sh страницу на том маршруте, где размещена эта анимация, вы получите бесконечное число l oop, например:

{ element:
   HTMLDivElement {
     parentNode:
      HTMLUnknownElement {
        parentNode: [HTMLDivElement],
        _previousSibling: [HTMLDivElement],
        _nextSibling: [HTMLImageElement],
        _index: undefined,
        _childNodes: null,
        _firstChild: [Circular],
        nodeType: 1,
        ownerDocument: [Object],
        localName: 'app-bottom-angle',
        namespaceURI: 'http://www.w3.org/1999/xhtml',
        prefix: null,
        _tagName: undefined,
        _attrsByQName: [Object],
        _attrsByLName: [Object],
        _attrKeys: [Array],
        __ngContext__: [LComponentView_CalendarIntroductionComponent],
        _classList: [DOMTokenList],
        _nid: 79 },
     _previousSibling: [Circular],
     _nextSibling: [Circular],
     _index: undefined,
     _childNodes: null,
     _firstChild: null,
     nodeType: 1,
     ownerDocument:
      { parentNode: null,
        _previousSibling: [Circular],
        _nextSibling: [Circular],
        _index: undefined,
        _childNodes: null,
        _firstChild: [Object],
        nodeType: 9,
        isHTML: true,
        _address: 'http://localhost:54818/en/calendar',
        readyState: 'loading',
        implementation: [Object],
        ownerDocument: null,
        _contentType: 'text/html',
        doctype: [Object],
        documentElement: [HTMLHtmlElement],
        _templateDocCache: null,
        _nodeIterators: null,
        _nid: 1,
        _nextnid: 152,
        _nodes: [Array],
        byId: [Object],
        modclock: 23,
        _scripting_enabled: true,
        defaultView: [Object],
        _lastModTime: 1 },
     localName: 'div',
     namespaceURI: 'http://www.w3.org/1999/xhtml',
     prefix: null,
     _tagName: undefined,
     _attrsByQName:
      [Object: null prototype] { '_ngcontent-sc33': [Object], class: [Object], style: [Object] },
     _attrsByLName:
      [Object: null prototype] {
        '|_ngcontent-sc33': [Object],
        '|class': [Object],
        '|style': [Object] },
     _attrKeys: [ '|_ngcontent-sc33', '|class', '|style' ],
     _classList:
      DOMTokenList {
        '0': 'position-absolute',
        '1': 'z-index-plus-1',
        '2': 'bottom-0',
        '3': 'right-0',
        '4': 'left-0',
        '5': 'mb-4',
        '6': 'ng-tns-c33-1',
        '7': 'ng-trigger',
        '8': 'ng-trigger-scale',
        '9': undefined,
        '10': undefined,
        _getString: [Function],
        _setString: [Function],
        _length: 9 },
     __ngContext__:
      LComponentView_BottomAngleComponent [
        [HTMLUnknownElement],
        [TView],
        211,
        [LComponentView_CalendarIntroductionComponent],
        null,
        null,
        [TNode$1],
        [LCleanup],
        [BottomAngleComponent],
        [Object],
        [AnimationRendererFactory],
        [AnimationRenderer],
        null,
        null,
        null,
        [LComponentView_CalendarIntroductionComponent],
        [Circular],
        null,
        0,
        [Circular],
        'big' ],
     _nid: 80,
     _style:
      { _element: [Circular],
        _parsedStyles: [Object],
        _lastParsedText: 'transform: scale(1); transform-style: preserve-3d;',
        _names: [Array] } },
  triggerName: 'scale',
  fromState: 'small',
  toState: 'big',
  phaseName: 'done',
  totalTime: 1200,
  disabled: false,
  _data: 1006 }
{ element:
   HTMLDivElement {
     parentNode:
      HTMLUnknownElement {
        parentNode: [HTMLDivElement],
        _previousSibling: [HTMLDivElement],
        _nextSibling: [HTMLImageElement],
        _index: undefined,
        _childNodes: null,
        _firstChild: [Circular],
        nodeType: 1,
        ownerDocument: [Object],
        localName: 'app-bottom-angle',
        namespaceURI: 'http://www.w3.org/1999/xhtml',
        prefix: null,
        _tagName: undefined,
        _attrsByQName: [Object],
        _attrsByLName: [Object],
        _attrKeys: [Array],
        __ngContext__: [LComponentView_CalendarIntroductionComponent],
        _classList: [DOMTokenList],
        _nid: 79 },
     _previousSibling: [Circular],
     _nextSibling: [Circular],
     _index: undefined,
     _childNodes: null,
     _firstChild: null,
     nodeType: 1,
     ownerDocument:
      { parentNode: null,
        _previousSibling: [Circular],
        _nextSibling: [Circular],
        _index: undefined,
        _childNodes: null,
        _firstChild: [Object],
        nodeType: 9,
        isHTML: true,
        _address: 'http://localhost:54818/en/calendar',
        readyState: 'loading',
        implementation: [Object],
        ownerDocument: null,
        _contentType: 'text/html',
        doctype: [Object],
        documentElement: [HTMLHtmlElement],
        _templateDocCache: null,
        _nodeIterators: null,
        _nid: 1,
        _nextnid: 152,
        _nodes: [Array],
        byId: [Object],
        modclock: 23,
        _scripting_enabled: true,
        defaultView: [Object],
        _lastModTime: 1 },
     localName: 'div',
     namespaceURI: 'http://www.w3.org/1999/xhtml',
     prefix: null,
     _tagName: undefined,
     _attrsByQName:
      [Object: null prototype] { '_ngcontent-sc33': [Object], class: [Object], style: [Object] },
     _attrsByLName:
      [Object: null prototype] {
        '|_ngcontent-sc33': [Object],
        '|class': [Object],
        '|style': [Object] },
     _attrKeys: [ '|_ngcontent-sc33', '|class', '|style' ],
     _classList:
      DOMTokenList {
        '0': 'position-absolute',
        '1': 'z-index-plus-1',
        '2': 'bottom-0',
        '3': 'right-0',
        '4': 'left-0',
        '5': 'mb-4',
        '6': 'ng-tns-c33-1',
        '7': 'ng-trigger',
        '8': 'ng-trigger-scale',
        '9': undefined,
        '10': undefined,
        _getString: [Function],
        _setString: [Function],
        _length: 9 },
     __ngContext__:
      LComponentView_BottomAngleComponent [
        [HTMLUnknownElement],
        [TView],
        211,
        [LComponentView_CalendarIntroductionComponent],
        null,
        null,
        [TNode$1],
        [LCleanup],
        [BottomAngleComponent],
        [Object],
        [AnimationRendererFactory],
        [AnimationRenderer],
        null,
        null,
        null,
        [LComponentView_CalendarIntroductionComponent],
        [Circular],
        null,
        0,
        [Circular],
        'small' ],
     _nid: 80,
     _style:
      { _element: [Circular],
        _parsedStyles: [Object],
        _lastParsedText: 'transform: scale(1.2); transform-style: preserve-3d;',
        _names: [Array] } },
  triggerName: 'scale',
  fromState: 'big',
  toState: 'small',
  phaseName: 'done',
  totalTime: 1200,
  disabled: false,
  _data: 1007 }

И ваше приложение зависает. Я не знаю, есть ли лучший способ достижения бесконечной анимации с использованием Angular анимаций и должен ли разработчик "знать", что SSR будет уязвим для них. Я думаю, если вы думаете, что они имеют дело с HTML элементами, вы можете утверждать, что они все должны использовать isPlatformBrowser внутри них.

1 Ответ

0 голосов
/ 15 апреля 2020

Да, есть лучший способ добиться анимации, если вы знаете, как сообщить angular о том, что запрос размещается сервером SSR.

Итак, пошло.

Вы можете видеть, что на server.ts

есть токен впрыска, который вводится.

providers: [
    { provide: APP_BASE_HREF, useValue: req.baseUrl },

теперь вам нужно go добавить в компонент и внедрить этот токен, как показано ниже.

constructor(
@Optional() @Inject(APP_BASE_HREF) private basehref: string,

Теперь basehref будет нулевым, если это не SSR, и некоторым строковым значением при запросе через SSR.

теперь предлагает способ выполнения анимации только тогда, когда basehref нуль.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...