Skip to content

Commit b4b4953

Browse files
committed
chore: code review changes
1 parent c0ed071 commit b4b4953

File tree

4 files changed

+34
-76
lines changed

4 files changed

+34
-76
lines changed

src/generators/web/template.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@
2121

2222
<body>
2323
<div id="root">{{dehydrated}}</div>
24-
<script type="module" src="{{mainJsSrc}}"></script>
24+
<script type="module" src="{{entrypoint}}"></script>
2525
</body>
2626
</html>

src/generators/web/utils/bundle.mjs

Lines changed: 16 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -13,31 +13,14 @@ import staticData from './data.mjs';
1313
* @param {boolean} [options.server=false] - Whether this is a server-side build.
1414
*/
1515
export default async function bundleCode(codeMap, { server = false } = {}) {
16-
// Store the import map HTML for later extraction
17-
let importMapHtml = '';
18-
19-
/** @type {import('rolldown').OutputOptions} */
20-
const serverOutputConfig = {
21-
// Inline all dynamic imports to create a single self-contained bundle
22-
inlineDynamicImports: true,
23-
};
24-
25-
/** @type {import('rolldown').InputOptions['experimental']} */
26-
const clientExperimentalConfig = {
27-
// Generate an import map for cache-busted module resolution in browsers
28-
// https://rolldown.rs/options/experimental#chunkimportmap
29-
chunkImportMap: {
30-
baseUrl: './',
31-
fileName: 'importmap.json',
32-
},
33-
};
34-
3516
const result = await build({
3617
// Entry points: array of virtual module names that the virtual plugin provides
3718
input: Array.from(codeMap.keys()),
3819

3920
// Experimental features: import maps for client, none for server
40-
experimental: server ? {} : clientExperimentalConfig,
21+
experimental: {
22+
chunkImportMap: !server,
23+
},
4124

4225
// Output configuration
4326
output: {
@@ -50,8 +33,8 @@ export default async function bundleCode(codeMap, { server = false } = {}) {
5033
// Server builds are usually not minified to preserve stack traces and debuggability.
5134
minify: !server,
5235

53-
// Environment-specific output configuration
54-
...(server ? serverOutputConfig : {}),
36+
// Within server builds we want to ensure dynamic imports get inlined whenever possible.
37+
inlineDynamicImports: server,
5538
},
5639

5740
// Platform informs Rolldown of the environment-specific code behavior:
@@ -106,28 +89,6 @@ export default async function bundleCode(codeMap, { server = false } = {}) {
10689
// Load CSS imports via the custom plugin.
10790
// This plugin will collect imported CSS files and return them as `source` chunks.
10891
cssLoader(),
109-
110-
// Extract and transform the import map generated by Rolldown
111-
{
112-
name: 'extract-import-map',
113-
/**
114-
* Extracts import map from bundle and converts to HTML script tag.
115-
*
116-
* @param {import('rolldown').NormalizedOutputOptions} _ - Output options (unused).
117-
* @param {import('rolldown').OutputBundle} bundle - Bundle object containing all output chunks.
118-
*/
119-
generateBundle(_, bundle) {
120-
const chunkImportMap = bundle['importmap.json'];
121-
122-
if (chunkImportMap?.type === 'asset') {
123-
// Convert to HTML script tag for inline inclusion
124-
importMapHtml = `<script type="importmap">${chunkImportMap.source}</script>`;
125-
126-
// Remove from bundle to prevent writing as separate file
127-
delete bundle['importmap.json'];
128-
}
129-
},
130-
},
13192
],
13293

13394
// Enable tree-shaking to remove unused code
@@ -138,16 +99,21 @@ export default async function bundleCode(codeMap, { server = false } = {}) {
13899
});
139100

140101
// Separate CSS assets from JavaScript chunks
141-
const cssFiles = result.output.filter(chunk => chunk.type === 'asset');
142-
const jsChunks = result.output.filter(chunk => chunk.type === 'chunk');
102+
const assets = result.output.filter(c => c.type === 'asset');
103+
const chunks = result.output.filter(c => c.type === 'chunk');
104+
105+
const importMap = assets.find(c => c.fileName === 'importmap.json');
143106

144107
return {
145-
importMapHtml,
146-
css: cssFiles.map(f => f.source).join(''),
147-
jsChunks: jsChunks.map(({ fileName, code, isEntry }) => ({
108+
css: assets
109+
.filter(c => c.fileName.endsWith('.css'))
110+
.map(f => f.source)
111+
.join(''),
112+
jsChunks: chunks.map(({ fileName, code, isEntry }) => ({
148113
fileName: fileName.replace('_virtual_', ''),
149-
code,
150114
isEntry,
115+
code,
151116
})),
117+
importMapHtml: `<script type="importmap">${importMap?.source}</script>`,
152118
};
153119
}

src/generators/web/utils/chunkHelper.mjs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,10 @@ export function createEnhancedRequire(jsChunks, requireFn) {
1717
* @param {string} modulePath - Module path to require.
1818
* @returns {*} Module exports.
1919
*/
20-
const enhancedRequire = modulePath => {
20+
const chunkedRequire = modulePath => {
2121
// Check virtual file system first for code-split chunks
2222
if (chunkModules[modulePath]) {
23-
const moduleExports = {};
24-
const module = { exports: moduleExports };
23+
const mod = { exports: {} };
2524

2625
// Execute chunk code in isolated context with its own module.exports
2726
const chunkFn = new Function(
@@ -31,14 +30,14 @@ export function createEnhancedRequire(jsChunks, requireFn) {
3130
chunkModules[modulePath]
3231
);
3332

34-
chunkFn(module, moduleExports, enhancedRequire);
33+
chunkFn(mod, mod.exports, chunkedRequire);
3534

36-
return module.exports;
35+
return mod.exports;
3736
}
3837

3938
// Fall back to Node.js require for external packages
4039
return requireFn(modulePath);
4140
};
4241

43-
return enhancedRequire;
42+
return chunkedRequire;
4443
}

src/generators/web/utils/processing.mjs

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,14 @@ export async function executeServerCode(serverCodeMap, requireFn) {
4242
}
4343

4444
/**
45-
* Processes multiple JSX AST entries to generate complete HTML pages with SSR content,
46-
* client-side JavaScript bundles (with code splitting), and CSS.
45+
* Processes a single JSX AST (Abstract Syntax Tree) entry to generate a complete
46+
* HTML page, including server-side rendered content, client-side JavaScript, and CSS.
4747
*
48-
* This function:
49-
* 1. Converts JSX AST to JavaScript code for both server and client
50-
* 2. Executes server code to get dehydrated (server-rendered) HTML
51-
* 3. Bundles client code with code splitting and import maps
52-
* 4. Injects everything into HTML template and minifies
53-
*
54-
* @param {import('../../jsx-ast/utils/buildContent.mjs').JSXContent[]} entries - JSX AST entries to process.
55-
* @param {string} template - HTML template string with placeholders: {{title}}, {{dehydrated}}, {{importMap}}, {{mainJsCode}}.
56-
* @param {ReturnType<import('./generate.mjs').default>} astBuilders - AST generator functions (buildServerProgram, buildClientProgram).
57-
* @param {ReturnType<import('node:module').createRequire>} requireFn - Node.js require function.
58-
* @param {Object} options - Processing options.
59-
* @param {string} options.version - Documentation version string.
48+
* @param {Array<import('../../jsx-ast/utils/buildContent.mjs').JSXContent>} entries - The JSX AST entry to process.
49+
* @param {string} template - The HTML template string that serves as the base for the output page.
50+
* @param {ReturnType<import('./generate.mjs')>} astBuilders - The AST generators
51+
* @param {version} version - The version to generator the documentation for
52+
* @param {ReturnType<import('node:module').createRequire>} requireFn - A Node.js `require` function.
6053
*/
6154
export async function processJSXEntries(
6255
entries,
@@ -89,22 +82,22 @@ export async function processJSXEntries(
8982
const clientBundle = await bundleCode(clientCodeMap);
9083

9184
// Process each entry to create final HTML
92-
const results = entries.map(entry => {
93-
const fileName = `${entry.data.api}.js`;
85+
const results = entries.map(({ data }) => {
86+
const fileName = `${data.api}.js`;
9487

95-
const title = `${entry.data.heading.data.name} | Node.js v${version} Documentation`;
88+
const title = `${data.heading.data.name} | Node.js v${version} Documentation`;
9689

9790
// Replace template placeholders with actual content
9891
const renderedHtml = template
9992
.replace('{{title}}', title)
10093
.replace('{{dehydrated}}', serverBundle.get(fileName) ?? '')
10194
.replace('{{importMap}}', clientBundle.importMapHtml)
102-
.replace('{{mainJsSrc}}', `./${fileName}?${randomUUID()}`);
95+
.replace('{{entrypoint}}', `./${fileName}?${randomUUID()}`);
10396

10497
// Minify HTML (input must be a Buffer)
10598
const finalHTMLBuffer = HTMLMinifier.minify(Buffer.from(renderedHtml), {});
10699

107-
return { html: finalHTMLBuffer, api: entry.data.api };
100+
return { html: finalHTMLBuffer, api: data.api };
108101
});
109102

110103
return {

0 commit comments

Comments
 (0)