taiga-family / taiga-ui

Angular UI Kit and components library for awesome people
https://taiga-ui.dev
Apache License 2.0
3.25k stars 452 forks source link

🐞 - `Svg` throws `Assertion failed: Failed to load external SVG` during SSR #4063

Open nsbarsukov opened 1 year ago

nsbarsukov commented 1 year ago

Playground Link

https://github.com/Tinkoff/maskito/actions/runs/4572709295/jobs/8072254292

Description

  1. Open logs of prerender job https://github.com/Tinkoff/maskito/actions/runs/4572709295/jobs/8072254292
  2. They contain
    Assertion failed: Failed to load external SVG assets/icons/github.svg

Reproduction

<a
    tuiLink
    tuiMode="onLight"
    href="https://github.com/tinkoff/maskito"
    title="Maskito source code on GitHub"
    rel="noreferrer"
    iconAlign="left"
    icon="assets/icons/github.svg"
    target="_blank"
    class="link"
></a>

Run nx serve-ssr

Taiga UI version

3.22.0

Which operating systems have you used?

nsbarsukov commented 1 year ago

https://github.com/Tinkoff/maskito/blob/34622646ea1d78428ff0298a9868dbcbcf11c468/projects/demo/src/app/app.component.html#L3-L13

nsbarsukov commented 1 year ago

Error is thrown here: https://github.com/Tinkoff/taiga-ui/blob/856bc574815a7749e86f405b777cc95d686fe55f/projects/core/components/svg/svg.component.ts#L189-L191

It happens because TuiStaticRequestService uses legacy XMLHttpRequest https://github.com/Tinkoff/taiga-ui/blob/856bc574815a7749e86f405b777cc95d686fe55f/projects/cdk/services/static-request.service.ts#L19

and it causes this error during SSR:

ReferenceError: XMLHttpRequest is not defined
nsbarsukov commented 1 year ago

In this PR legacy XMLHttpRequest was replaced by modern fetch:

It was just a small refactor (since Taiga 3.x.x all our required browser supports fetch).

But problem still persists - no external icons after SSR. Even with Node.js >18.0.0 (this version introduces built-in support of fetch).

waterplea commented 1 year ago

Maybe it's a sanitizing issue now?

nsbarsukov commented 1 year ago

The new error is the following:

ERROR Error: Uncaught (in promise): TypeError: Failed to parse URL from assets/images/github.svg ``` ERROR Error: Uncaught (in promise): TypeError: Failed to parse URL from assets/images/github.svg TypeError: Failed to parse URL from assets/images/github.svg at new Request (node:internal/deps/undici/undici:7043:19) at fetch2 (node:internal/deps/undici/undici:10598:25) at Object.fetch (node:internal/deps/undici/undici:11455:18) at fetch (node:internal/process/pre_execution:230:25) at /Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:207285:36 at proto. (/Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:206744:24) at Observable._subscribe (/Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:192657:9) at Observable._trySubscribe (/Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:191268:25) at Observable.subscribe (/Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:191254:22) at SwitchMapOperator.call (/Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:195137:23) at resolvePromise (/Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:206978:31) at /Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:206885:17 at Object.reject (/Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:206901:33) at fetch2 (node:internal/deps/undici/undici:10600:11) at Object.fetch (node:internal/deps/undici/undici:11455:18) at fetch (node:internal/process/pre_execution:230:25) at /Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:207285:36 at proto. (/Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:206744:24) at Observable._subscribe (/Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:192657:9) at Observable._trySubscribe (/Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:191268:25) { rejection: TypeError: Failed to parse URL from assets/images/github.svg at new Request (node:internal/deps/undici/undici:7043:19) at fetch2 (node:internal/deps/undici/undici:10598:25) ... 5 lines matching cause stack trace ... at Observable._trySubscribe (/Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:191268:25) at Observable.subscribe (/Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:191254:22) at SwitchMapOperator.call (/Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:195137:23) { [cause]: TypeError [ERR_INVALID_URL]: Invalid URL at new NodeError (node:internal/errors:399:5) at new URL (node:internal/url:560:13) at new Request (node:internal/deps/undici/undici:7041:25) at fetch2 (node:internal/deps/undici/undici:10598:25) at Object.fetch (node:internal/deps/undici/undici:11455:18) at fetch (node:internal/process/pre_execution:230:25) at /Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:207285:36 at proto. (/Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:206744:24) at Observable._subscribe (/Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:192657:9) at Observable._trySubscribe (/Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:191268:25) { input: 'assets/images/github.svg', code: 'ERR_INVALID_URL' } }, promise: ZoneAwarePromise [Promise] { __zone_symbol__state: 0, __zone_symbol__value: TypeError: Failed to parse URL from assets/images/github.svg at new Request (node:internal/deps/undici/undici:7043:19) at fetch2 (node:internal/deps/undici/undici:10598:25) ... 5 lines matching cause stack trace ... at Observable._trySubscribe (/Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:191268:25) at Observable.subscribe (/Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:191254:22) at SwitchMapOperator.call (/Users/n.barsukov/WebstormProjects/taiga-ui/dist/demo/server/main.js:195137:23) { [cause]: [TypeError] } }, zone: Zone { _parent: Zone { _parent: null, _name: '', _properties: {}, _zoneDelegate: [_ZoneDelegate] }, _name: 'angular', _properties: { isAngularZone: true }, _zoneDelegate: _ZoneDelegate { _taskCounts: [Object], zone: [Circular *1], _parentDelegate: [_ZoneDelegate], _forkZS: null, _forkDlgt: null, _forkCurrZone: null, _interceptZS: null, _interceptDlgt: null, _interceptCurrZone: null, _invokeZS: [Object], _invokeDlgt: [_ZoneDelegate], _invokeCurrZone: [Circular *1], _handleErrorZS: [Object], _handleErrorDlgt: [_ZoneDelegate], _handleErrorCurrZone: [Circular *1], _scheduleTaskZS: [Object], _scheduleTaskDlgt: [_ZoneDelegate], _scheduleTaskCurrZone: [Circular *1], _invokeTaskZS: [Object], _invokeTaskDlgt: [_ZoneDelegate], _invokeTaskCurrZone: [Circular *1], _cancelTaskZS: [Object], _cancelTaskDlgt: [_ZoneDelegate], _cancelTaskCurrZone: [Circular *1], _hasTaskZS: [Object], _hasTaskDlgt: [_ZoneDelegate], _hasTaskDlgtOwner: [Circular *2], _hasTaskCurrZone: [Circular *1] } }, task: ZoneTask { _zone: Zone { _parent: [Zone], _name: 'angular', _properties: [Object], _zoneDelegate: [_ZoneDelegate] }, runCount: 0, _zoneDelegates: null, _state: 'notScheduled', type: 'microTask', source: 'Promise.then', data: ZoneAwarePromise [Promise] { __zone_symbol__state: true, __zone_symbol__value: [NgModuleRef$1] }, scheduleFn: undefined, cancelFn: undefined, callback: [Function (anonymous)], invoke: [Function (anonymous)] } } ```

Reproduction

  1. Open Taiga UI project
  2. Execute nvm use 18
  3. Run nx serve-ssr demo
  4. Open http://localhost:4200