Skip to content

Commit cfad1b2

Browse files
committed
remove mustache
1 parent 6c934fa commit cfad1b2

File tree

8 files changed

+82
-71
lines changed

8 files changed

+82
-71
lines changed

package-lock.json

Lines changed: 0 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@
6363
"hast-util-to-string": "^3.0.1",
6464
"hastscript": "^9.0.1",
6565
"html-minifier-terser": "^7.2.0",
66-
"mustache": "^4.2.0",
6766
"postcss": "^8.5.3",
6867
"postcss-calc": "^10.1.1",
6968
"react": "^19.1.0",

src/constants.mjs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,10 @@ export const DOC_API_BLOB_EDIT_BASE_URL =
2020

2121
// Base URL for a specific Node.js version within the Node.js API docs
2222
export const DOC_API_BASE_URL_VERSION = 'https://nodejs.org/docs/latest-v';
23+
24+
// Options for Terser
25+
export const TERSER_MINIFY_OPTIONS = {
26+
collapseWhitespace: true,
27+
minifyJS: true,
28+
minifyCSS: true,
29+
};

src/generators/legacy-html-all/index.mjs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { join, resolve } from 'node:path';
55

66
import { minify } from 'html-minifier-terser';
77

8+
import { TERSER_MINIFY_OPTIONS } from '../../constants.mjs';
89
import { getRemarkRehype } from '../../utils/remark.mjs';
910
import dropdowns from '../legacy-html/utils/buildDropdowns.mjs';
1011
import tableOfContents from '../legacy-html/utils/tableOfContents.mjs';
@@ -95,11 +96,7 @@ export default {
9596
.replace('__EDIT_ON_GITHUB__', '');
9697

9798
// We minify the html result to reduce the file size and keep it "clean"
98-
const minified = await minify(generatedAllTemplate, {
99-
collapseWhitespace: true,
100-
minifyJS: true,
101-
minifyCSS: true,
102-
});
99+
const minified = await minify(generatedAllTemplate, TERSER_MINIFY_OPTIONS);
103100

104101
if (output) {
105102
await writeFile(join(output, 'all.html'), minified);

src/generators/legacy-html/index.mjs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { minify } from 'html-minifier-terser';
88
import buildContent from './utils/buildContent.mjs';
99
import dropdowns from './utils/buildDropdowns.mjs';
1010
import tableOfContents from './utils/tableOfContents.mjs';
11+
import { TERSER_MINIFY_OPTIONS } from '../../constants.mjs';
1112
import { groupNodesByModule } from '../../utils/generators.mjs';
1213
import { getRemarkRehype } from '../../utils/remark.mjs';
1314

@@ -155,11 +156,7 @@ export default {
155156

156157
if (output) {
157158
// We minify the html result to reduce the file size and keep it "clean"
158-
const minified = await minify(result, {
159-
collapseWhitespace: true,
160-
minifyJS: true,
161-
minifyCSS: true,
162-
});
159+
const minified = await minify(result, TERSER_MINIFY_OPTIONS);
163160

164161
await writeFile(join(output, `${node.api}.html`), minified);
165162
}

src/generators/web/constants.mjs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ export const ESBUILD_RESOLVE_DIR = fileURLToPath(
44
new URL('./client', import.meta.url)
55
);
66

7+
export const TEMPLATE_PLACEHOLDERS = {
8+
TITLE: '__TITLE__',
9+
DEHYDRATED: '__DEHYDRATED__',
10+
JAVASCRIPT: '__JAVASCRIPT__',
11+
};
12+
713
// Imports are relative to ESBUILD_RESOLVE_DIR
814
export const JSX_IMPORTS = {
915
NavBar: {

src/generators/web/index.mjs

Lines changed: 62 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,24 @@ import { createRequire } from 'node:module';
33
import { join } from 'node:path';
44

55
import { estreeToBabel } from 'estree-to-babel';
6-
import Mustache from 'mustache';
6+
import { minify } from 'html-minifier-terser';
77

8-
import { ESBUILD_RESOLVE_DIR } from './constants.mjs';
8+
import { ESBUILD_RESOLVE_DIR, TEMPLATE_PLACEHOLDERS } from './constants.mjs';
9+
import { TERSER_MINIFY_OPTIONS } from '../../constants.mjs';
910
import createASTBuilder from './utils/astBuilder.mjs';
1011
import bundleCode from './utils/bundle.mjs';
1112

1213
/**
1314
* Executes server-side code in a safe, isolated context
1415
* @param {string} serverCode - The server code to execute
15-
* @param {Function} require - Node.js require function for dependencies
16+
* @param {ReturnType<createRequire>} require - Node.js require function for dependencies
1617
* @returns {Promise<string>} The rendered HTML output
1718
*/
1819
async function executeServerCode(serverCode, require) {
19-
// Bundle the server code for execution
2020
const { js: bundledServer } = await bundleCode(serverCode, {
2121
platform: 'node',
2222
});
2323

24-
// Create a safe execution context that returns the rendered content
2524
const executedFunction = new Function(
2625
'require',
2726
`
@@ -34,6 +33,53 @@ async function executeServerCode(serverCode, require) {
3433
return executedFunction(require);
3534
}
3635

36+
/**
37+
* Processes a single entry and writes the HTML file immediately
38+
* @param {import('../jsx-ast/utils/buildContent.mjs').JSXContent} entry - JSX AST entry
39+
* @param {string} template - HTML template
40+
* @param {ReturnType<createASTBuilder>} astBuilders - AST builder functions
41+
* @param {ReturnType<createRequire>} require - Node.js require function
42+
* @param {string} output - Output directory path
43+
* @returns {Promise<{html: string, css?: string}>}
44+
*/
45+
async function processEntry(
46+
entry,
47+
template,
48+
{ buildServerProgram, buildClientProgram },
49+
require,
50+
output
51+
) {
52+
// Convert JSX AST to Babel AST
53+
const { program } = estreeToBabel(entry);
54+
55+
// Generate and execute server-side code for SSR
56+
const serverCode = buildServerProgram(program);
57+
const serverRenderedHTML = await executeServerCode(serverCode, require);
58+
59+
// Generate and bundle client-side code
60+
const clientCode = buildClientProgram(program);
61+
const clientBundle = await bundleCode(clientCode);
62+
63+
// Render the final HTML using the template
64+
const finalHTML = await minify(
65+
template
66+
.replace(TEMPLATE_PLACEHOLDERS.TITLE, entry.data.heading.data.name)
67+
.replace(TEMPLATE_PLACEHOLDERS.DEHYDRATED, serverRenderedHTML)
68+
.replace(TEMPLATE_PLACEHOLDERS.JAVASCRIPT, clientBundle.js),
69+
TERSER_MINIFY_OPTIONS
70+
);
71+
72+
// Write HTML file immediately if output directory is specified
73+
if (output) {
74+
await writeFile(join(output, `${entry.data.api}.html`), finalHTML, 'utf-8');
75+
}
76+
77+
return {
78+
html: finalHTML,
79+
css: clientBundle.css,
80+
};
81+
}
82+
3783
/**
3884
* This generator generates a JavaScript / HTML / CSS bundle from the input JSX AST
3985
*
@@ -54,57 +100,26 @@ export default {
54100
* @param {Partial<GeneratorOptions>} options
55101
*/
56102
async generate(entries, { output }) {
57-
// Load the HTML template
103+
// Load template and set up dependencies
58104
const template = await readFile(
59105
new URL('template.html', import.meta.url),
60106
'utf-8'
61107
);
62-
63-
// Set up AST builders for server and client code
64-
const { buildServerProgram, buildClientProgram } = createASTBuilder();
108+
const astBuilders = createASTBuilder();
65109
const require = createRequire(ESBUILD_RESOLVE_DIR);
66110

67-
let css; // Will store CSS from the first bundle
68-
69-
// Process each entry in parallel
70-
const bundles = await Promise.all(
71-
entries.map(async entry => {
72-
// Convert JSX AST to Babel AST
73-
const { program } = estreeToBabel(entry);
74-
75-
// Generate and execute server-side code for SSR
76-
const serverCode = buildServerProgram(program);
77-
const serverRenderedHTML = await executeServerCode(serverCode, require);
78-
79-
// Generate and bundle client-side code
80-
const clientCode = buildClientProgram(program);
81-
const clientBundle = await bundleCode(clientCode);
82-
83-
// Extract CSS only from the first bundle to avoid duplicates
84-
css ??= clientBundle.css;
85-
86-
// Render the final HTML using the template
87-
const finalHTML = Mustache.render(template, {
88-
title: entry.data.heading.data.name,
89-
javascript: clientBundle.js,
90-
dehydrated: serverRenderedHTML,
91-
});
92-
93-
// Write individual HTML file if output directory is specified
94-
if (output) {
95-
const filename = `${entry.data.api}.html`;
96-
await writeFile(join(output, filename), finalHTML);
97-
}
98-
99-
return finalHTML;
100-
})
111+
// Process all entries in parallel
112+
const results = await Promise.all(
113+
entries.map(entry => processEntry(entry, template, astBuilders, require))
101114
);
102115

103-
// Write shared CSS file if we have CSS and an output directory
104-
if (output && css) {
105-
await writeFile(join(output, 'styles.css'), css);
116+
if (output) {
117+
await writeFile(
118+
join(output, 'styles.css'),
119+
results.find(result => result.css).css
120+
);
106121
}
107122

108-
return bundles;
123+
return results.map(result => result.html);
109124
},
110125
};

src/generators/web/template.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<!DOCTYPE html>
22
<html>
33
<head>
4-
<title>{{title}}</title>
4+
<title>__TITLE__</title>
55
<link rel="stylesheet" href="styles.css" />
66
</head>
77
<body>
8-
<div id="root">{{{dehydrated}}}</div>
9-
<script>{{{javascript}}}</script>
8+
<div id="root">__DEHYDRATED__</div>
9+
<script>__JAVASCRIPT__</script>
1010
</body>
1111
</html>

0 commit comments

Comments
 (0)