Skip to content

Commit 524c6f8

Browse files
committed
perf: stop minifying HTML
The HTML generators minified every page with SWC's HTML minifier, compiled to WASM. Its memory grows to about twelve times the biggest page it is given, and is never returned: each thread rendering pages kept it until it ended, and on Node.js 24, the worker that minified the Node.js docs' 33MB `all.html` collected garbage on nearly every allocation from then on, as V8 found that memory too large for its heap limit. Minifying also took a fifth of the build's CPU. For that, the Node.js docs' pages were 5.9% smaller, but only 3.2% once gzipped and 2.1% with brotli, which is how hosts serve them: Cloudflare, Vercel, Netlify and GitHub Pages compress HTML by default. The pages are now written as rendered, and `@swc/html-wasm` is gone, along with `@doc-kit/core/utils/html-minifier.mjs`. `minify` still minifies scripts, styles and JSON, and the publishing docs now explain how to serve the pages compressed. On Node core's build with 4 threads on Node.js 26, the build takes 7.7s instead of 10.5s and peaks at ~1.68GB instead of ~2.12GB; with one thread, 15.2s instead of 22.5s. On Node.js 24, 7.9s instead of 51.7s. Assisted-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent bff2da5 commit 524c6f8

15 files changed

Lines changed: 62 additions & 83 deletions

File tree

‎.github/dependabot.yml‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ updates:
7373
- 'recma-*'
7474
compiling:
7575
patterns:
76-
- '@swc/html-wasm'
7776
- '@rollup/*'
7877
- 'rolldown'
7978
- 'lightningcss-wasm'

‎docs/configuration.md‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,10 @@ Everything under the `global` key applies to every generator:
109109
logos, and templated text. Defaults to the `name` in your `package.json`.
110110
- `version` {string|SemVer} Documentation version. **Default:**
111111
`process.version`.
112-
- `minify` {boolean} Whether to minify output. **Default:** `true`.
112+
- `minify` {boolean} Whether to minify JSON, scripts, and styles. HTML is
113+
written as is: serve it compressed instead (see
114+
[Compress the pages](./publishing.md#compress-the-pages)). **Default:**
115+
`true`.
113116
- `repository` {string} GitHub repository in `owner/repo` format; without
114117
one, repository UI is omitted.
115118
- `ref` {string} Git reference (branch, tag, or commit SHA). **Default:**

‎docs/publishing.md‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,24 @@ costs a request per asset each time a new tab opens the site. On Vercel:
5656
Within a visit, moving between pages loads no assets at all: the site
5757
navigates client-side, swapping in the next page's content.
5858

59+
## Compress the pages
60+
61+
doc-kit writes HTML as rendered, without minifying it. Served compressed (gzip
62+
or brotli), as hosts do, pages shrink to a fraction of their size, which
63+
minifying them would barely improve on.
64+
65+
Cloudflare, Vercel, Netlify, and GitHub Pages compress HTML on their own, with
66+
nothing to configure, and so does `npx serve out`. If you serve the output
67+
yourself, turn compression on:
68+
69+
- **nginx:** `gzip on;` compresses HTML; add the other types with
70+
`gzip_types text/css application/javascript application/json;`.
71+
- **Caddy:** `encode zstd gzip`.
72+
- **Apache:** with `mod_deflate`,
73+
`AddOutputFilterByType DEFLATE text/html text/css application/javascript application/json`.
74+
- **Amazon S3:** serve the bucket through CloudFront, with **Compress objects
75+
automatically** on.
76+
5977
## Tell doc-kit its public URL
6078

6179
Set `baseURL` to where the site will live. Generators that emit absolute

‎packages/core/package.json‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@
5353
],
5454
"dependencies": {
5555
"@node-core/rehype-shiki": "^1.5.1",
56-
"@swc/html-wasm": "^1.16.2",
5756
"@swc/wasm": "^1.15.46",
5857
"acorn": "^8.17.0",
5958
"cosmiconfig": "^9.0.2",

‎packages/core/src/utils/html-minifier.mjs‎

Lines changed: 0 additions & 12 deletions
This file was deleted.

‎packages/node-legacy/src/legacy-html-all/README.md‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,5 @@ The `legacy-html-all` generator creates a single `all.html` file containing all
77
- `output` {string} The directory where `all.html` will be written.
88
- `templatePath` {string} Path to the HTML template file. Inherited from
99
`legacy-html`. **Default:** `'template.html'`.
10-
- `minify` {boolean} Whether to minify the output HTML. Inherited from
11-
`global`. **Default:** `true`.
1210
- `version` {Object} Version object containing version information. Inherited
1311
from `global`. **Default:** `process.version`.

‎packages/node-legacy/src/legacy-html-all/generate.mjs‎

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { readFile, writeFile } from 'node:fs/promises';
44
import { join } from 'node:path';
55

66
import getConfig from '@doc-kit/core/utils/configuration/index.mjs';
7-
import { minifyHTML } from '@doc-kit/core/utils/html-minifier.mjs';
87
import { getProcessor } from '@doc-kit/core/utils/markdown/processor.mjs';
98

109
import { replaceTemplateValues } from '../legacy-html/utils/replaceTemplateValues.mjs';
@@ -56,15 +55,11 @@ export async function generate(input) {
5655
content: aggregatedContent,
5756
};
5857

59-
let result = replaceTemplateValues(apiTemplate, templateValues, config, {
58+
const result = replaceTemplateValues(apiTemplate, templateValues, config, {
6059
skipGitHub: true,
6160
skipGtocPicker: true,
6261
});
6362

64-
if (config.minify) {
65-
result = await minifyHTML(result);
66-
}
67-
6863
if (config.output) {
6964
await writeFile(join(config.output, 'all.html'), result);
7065
}

‎packages/node-legacy/src/legacy-html/README.md‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,3 @@ The `legacy-html` generator creates legacy HTML documentation pages for Node.js
1717
**Default:** `'${GITHUB_EDIT_URL}/doc/api{path}.md'`.
1818
- `index` {Array} Array of `{ api, section }` objects defining the
1919
documentation structure.
20-
- `minify` {boolean} Whether to minify the output HTML. Inherited from
21-
`global`. **Default:** `true`.

‎packages/node-legacy/src/legacy-html/generate.mjs‎

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { basename, join } from 'node:path';
66
import getConfig from '@doc-kit/core/utils/configuration/index.mjs';
77
import { writeFile } from '@doc-kit/core/utils/file.mjs';
88
import { groupNodesByModule } from '@doc-kit/core/utils/generators.mjs';
9-
import { minifyHTML } from '@doc-kit/core/utils/html-minifier.mjs';
109
import { getProcessor } from '@doc-kit/core/utils/markdown/processor.mjs';
1110

1211
import buildContent from './utils/buildContent.mjs';
@@ -124,11 +123,7 @@ export async function* generate(input, worker) {
124123
// Write files for this chunk in the generate method (main thread)
125124
if (config.output) {
126125
for (const template of chunkResult) {
127-
let result = replaceTemplateValues(apiTemplate, template, config);
128-
129-
if (config.minify) {
130-
result = await minifyHTML(result);
131-
}
126+
const result = replaceTemplateValues(apiTemplate, template, config);
132127

133128
await writeFile(join(config.output, `${template.api}.html`), result);
134129
}

‎packages/react/src/html/README.md‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ output-only and does not return an in-memory copy of its HTML or CSS.
99
The site is built in pieces that are each as small as they can be. The bundler
1010
builds the component library once and the client assets once. Each page's
1111
program is then compiled — JSX to a plain module — and the worker pool imports,
12-
renders, templates, minifies and writes the pages one at a time, so memory
12+
renders, templates and writes the pages one at a time, so memory
1313
scales with the largest page rather than with the site. `all.html` is assembled
1414
from the module pages' compiled content rather than built again from scratch.
1515

@@ -509,9 +509,8 @@ Since the template supports arbitrary JS expressions, you can use conditionals a
509509
<title>${title}</title> ${assets}
510510
```
511511
512-
The populated page is the final HTML: it is minified when `minify` is set and
513-
written as is. Put `${assets}` in the `<head>`, or the page loads no script and
514-
no stylesheet.
512+
The populated page is the final HTML, written as is. Put `${assets}` in the
513+
`<head>`, or the page loads no script and no stylesheet.
515514
516515
## Client-side navigation
517516

0 commit comments

Comments
 (0)