mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-11 19:46:16 -08:00
fix(performance): ignore inert HTML when listing initial resources
Strip HTML comments and the bodies of inline script/style elements before scanning index.html, so a commented-out tag or a tag-like string literal is neither counted nor reported as a missing file. Document the silent pnpm invocation for the JSON output and state that the counter is Angular's "Initial total" plus index.html and app-config.js rather than an exact match of that rounded figure. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
5cb69b1ec1
commit
be58eacb20
3 files changed
+45
-9
No files matched your search
@@ -32,16 +32,19 @@ The bytes a browser fetches before Angular can bootstrap, read from the built
|
||||
- every `<link rel="stylesheet">`,
|
||||
- every `<link rel="modulepreload">` chunk.
|
||||
|
||||
Manifest, icons, external URLs and lazy chunks are not counted. A file that
|
||||
`index.html` references but the build did not emit is an error, never zero
|
||||
bytes. The value is raw (uncompressed) size, which is what the renderer parses;
|
||||
it matches the "Initial total" line of the Angular build output.
|
||||
Manifest, icons, external URLs, commented-out tags and lazy chunks are not
|
||||
counted. A file that `index.html` references but the build did not emit is an
|
||||
error, never zero bytes. The value is raw (uncompressed) size, which is what the
|
||||
renderer parses. It is Angular's "Initial total" plus `index.html` and
|
||||
`assets/app-config.js` (about 4 KB together), so it sits slightly above the
|
||||
rounded figure the build prints; never copy that figure into a baseline, use
|
||||
the script's output.
|
||||
|
||||
```bash
|
||||
pnpm nx build web # production configuration
|
||||
pnpm run perf:initial-bytes # human-readable breakdown
|
||||
pnpm run perf:initial-bytes -- --json # machine-readable breakdown
|
||||
pnpm run perf:initial-bytes -- --summary dist/performance/journey-summary.json
|
||||
pnpm nx build web # production configuration
|
||||
pnpm run perf:initial-bytes # human-readable breakdown
|
||||
pnpm --silent run perf:initial-bytes -- --json # machine-readable; --silent keeps pnpm's headers out of stdout
|
||||
node tools/performance/measure-initial-bytes.mjs --summary dist/performance/journey-summary.json
|
||||
```
|
||||
|
||||
`--summary` writes the journey summary shape (`journeys.<journey>.counters`)
|
||||
|
||||
@@ -21,6 +21,8 @@ export const INITIAL_BYTES_COUNTER = 'renderer.initialBytes';
|
||||
export const LAUNCH_JOURNEY = 'launch';
|
||||
|
||||
const TAG_PATTERN = /<(script|link)\b([^>]*)>/gi;
|
||||
const HTML_COMMENT = /<!--[\s\S]*?-->/g;
|
||||
const INLINE_ELEMENT_BODY = /(<(script|style)\b[^>]*>)[\s\S]*?(<\/\2\s*>)/gi;
|
||||
const ATTRIBUTE_PATTERN =
|
||||
/([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g;
|
||||
const EXTERNAL_URL = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
|
||||
@@ -56,6 +58,17 @@ function classify(tag, attributes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the parts of the document the browser never treats as markup: HTML
|
||||
* comments (a commented-out `<script>` is not a request) and the bodies of
|
||||
* inline `<script>`/`<style>` elements (a string literal that looks like a tag
|
||||
* is not one either). The opening tags themselves are kept so a `src` on an
|
||||
* inline script element is still seen.
|
||||
*/
|
||||
export function stripInertHtml(html) {
|
||||
return html.replace(HTML_COMMENT, '').replace(INLINE_ELEMENT_BODY, '$1$3');
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists the same-origin resources `index.html` puts on the initial path, in
|
||||
* document order. Duplicates are collapsed by request URL, not by file: the
|
||||
@@ -66,7 +79,9 @@ function classify(tag, attributes) {
|
||||
export function extractInitialResources(html) {
|
||||
const seen = new Set();
|
||||
const resources = [];
|
||||
for (const [, tag, rawAttributes] of html.matchAll(TAG_PATTERN)) {
|
||||
for (const [, tag, rawAttributes] of stripInertHtml(html).matchAll(
|
||||
TAG_PATTERN
|
||||
)) {
|
||||
const resource = classify(
|
||||
tag.toLowerCase(),
|
||||
parseAttributes(rawAttributes)
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
formatReport,
|
||||
measureInitialBytes,
|
||||
parseArgs,
|
||||
stripInertHtml,
|
||||
toJourneySummary,
|
||||
} from './measure-initial-bytes.mjs';
|
||||
|
||||
@@ -117,6 +118,23 @@ test('deduplicates by request URL, ignores fragments and normalizes relative URL
|
||||
]);
|
||||
});
|
||||
|
||||
test('ignores commented-out tags and tag-like text inside inline scripts and styles', () => {
|
||||
const html = `
|
||||
<!-- <script src="old.js"></script> -->
|
||||
<!--
|
||||
<link rel="stylesheet" href="legacy.css">
|
||||
-->
|
||||
<script>const markup = '<script src="fake.js"><\\/script><link rel="modulepreload" href="fake-chunk.js">';</script>
|
||||
<style>/* <link rel="stylesheet" href="fake.css"> */ body { color: red; }</style>
|
||||
<script src="assets/app-config.js" defer></script>
|
||||
<script src="main.js" type="module"></script>`;
|
||||
assert.deepEqual(
|
||||
extractInitialResources(html).map((resource) => resource.url),
|
||||
['assets/app-config.js', 'main.js']
|
||||
);
|
||||
assert.equal(stripInertHtml('<script>1 < 2</script>'), '<script></script>');
|
||||
});
|
||||
|
||||
test('counts a file once per distinct request URL', async () => {
|
||||
const distDir = await writeDist('cache-busted', {
|
||||
indexHtml: `<link rel="modulepreload" href="chunk-a.js"><link rel="modulepreload" href="chunk-a.js?v=2">`,
|
||||
|
||||
Reference in new issue
Block a user