(doc: Document)
| 774 | * Note: this function is invoked only on the client, so it's safe to use DOM APIs. |
| 775 | */ |
| 776 | export function verifySsrContentsIntegrity(doc: Document): void { |
| 777 | for (const node of doc.body.childNodes) { |
| 778 | if (isSsrContentsIntegrity(node)) { |
| 779 | return; |
| 780 | } |
| 781 | } |
| 782 | |
| 783 | // Check if the HTML parser may have moved the marker to just before the <body> tag, |
| 784 | // e.g. because the body tag was implicit and not present in the markup. An implicit body |
| 785 | // tag is unlikely to interfer with whitespace/comments inside of the app's root element. |
| 786 | |
| 787 | // Case 1: Implicit body. Example: |
| 788 | // <!doctype html><head><title>Hi</title></head><!--nghm--><app-root></app-root> |
| 789 | const beforeBody = skipTextNodes(doc.body.previousSibling); |
| 790 | if (isSsrContentsIntegrity(beforeBody)) { |
| 791 | return; |
| 792 | } |
| 793 | |
| 794 | // Case 2: Implicit body & head. Example: |
| 795 | // <!doctype html><head><title>Hi</title><!--nghm--><app-root></app-root> |
| 796 | let endOfHead = skipTextNodes(doc.head.lastChild); |
| 797 | if (isSsrContentsIntegrity(endOfHead)) { |
| 798 | return; |
| 799 | } |
| 800 | |
| 801 | throw new RuntimeError( |
| 802 | RuntimeErrorCode.MISSING_SSR_CONTENT_INTEGRITY_MARKER, |
| 803 | typeof ngDevMode !== 'undefined' && |
| 804 | ngDevMode && |
| 805 | 'Angular hydration logic detected that HTML content of this page was modified after it ' + |
| 806 | 'was produced during server side rendering. Make sure that there are no optimizations ' + |
| 807 | 'that remove comment nodes from HTML enabled on your CDN. Angular hydration ' + |
| 808 | 'relies on HTML produced by the server, including whitespaces and comment nodes.', |
| 809 | ); |
| 810 | } |
no test coverage detected
searching dependent graphs…