Skip to content

Commit

Permalink
fix(@angular-devkit/build-angular): error during critical CSS inlinin…
Browse files Browse the repository at this point in the history
…g for external stylesheets

These changes revert the performance improvement from e88aea6 and add a test. The problem with the previous approach is that it assumes that a `link` tag processed by Critters will be preceded by a `style` tag that was inserted by Critters. This assumption might not necessarily be true if Critters is unable to resolve the content of the linked styles. Furthermore, I'm not sure if we need to optimize this code path to begin with, because it only does a shallow traversal of the `head` tag which is generally fast and is unlikely to have many direct descendants.

Fixes #25419.

(cherry picked from commit d6ae2c7)
  • Loading branch information
crisbeto authored and clydin committed Jul 26, 2023
1 parent 6ab416c commit 20816b5
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,15 @@ class CrittersExtended extends Critters {
this.conditionallyInsertCspLoadingScript(document, cspNonce);
}

link.prev?.setAttribute('nonce', cspNonce);
// Ideally we would hook in at the time Critters inserts the `style` tags, but there isn't
// a way of doing that at the moment so we fall back to doing it any time a `link` tag is
// inserted. We mitigate it by only iterating the direct children of the `<head>` which
// should be pretty shallow.
document.head.children.forEach((child) => {
if (child.tagName === 'style' && !child.hasAttribute('nonce')) {
child.setAttribute('nonce', cspNonce);
}
});
}

return returnValue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,34 @@ describe('InlineCriticalCssProcessor', () => {
html { color: white; }
</style>`);
});

it('should not modify the document for external stylesheets', async () => {
const inlineCssProcessor = new InlineCriticalCssProcessor({
readAsset,
});

const initialContent = `
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="https://google.com/styles.css" />
</head>
<body>
<app ngCspNonce="{% nonce %}"></app>
</body>
</html>
`;

const { content } = await inlineCssProcessor.process(initialContent, {
outputPath: '/dist/',
});

expect(tags.stripIndents`${content}`).toContain(tags.stripIndents`
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="https://google.com/styles.css">
</head>
`);
});
});

0 comments on commit 20816b5

Please sign in to comment.