Skip to content

Commit bcb028f

Browse files
Fix alternative index.html path (#37)
* Fix alternative index.html path * chore: revert minor formatting changes Co-authored-by: Ryan Christian <33403762+rschristian@users.noreply.github.com> --------- Co-authored-by: Ryan Christian <33403762+rschristian@users.noreply.github.com>
1 parent 3b18dfb commit bcb028f

5 files changed

Lines changed: 77 additions & 14 deletions

File tree

src/plugins/prerender-plugin.js

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ export function prerenderPlugin({ prerenderScript, renderTarget, additionalPrere
7575
let viteConfig = {};
7676
let userEnabledSourceMaps;
7777
let ssrBuild = false;
78+
let prerenderEntryHtml;
7879

7980
/** @type {import('./types.d.ts').PrerenderedRoute[]} */
8081
let routes = [];
@@ -90,12 +91,9 @@ export function prerenderPlugin({ prerenderScript, renderTarget, additionalPrere
9091
const tmpDirId = 'headless-prerender';
9192

9293
/**
93-
* From the non-external scripts in entry HTML document, find the one (if any)
94-
* that provides a `prerender` export
95-
*
9694
* @param {import('vite').Rollup.InputOption} input
9795
*/
98-
const getPrerenderScriptFromHTML = async (input) => {
96+
const getPrerenderEntryHtml = (input) => {
9997
// prettier-ignore
10098
const entryHtml =
10199
typeof input === "string"
@@ -106,7 +104,17 @@ export function prerenderPlugin({ prerenderScript, renderTarget, additionalPrere
106104

107105
if (!entryHtml) throw new Error('Unable to detect entry HTML');
108106

109-
const htmlDoc = htmlParse(await fs.readFile(entryHtml, 'utf-8'));
107+
return path.resolve(viteConfig.root, entryHtml);
108+
};
109+
110+
/**
111+
* From the non-external scripts in the entry HTML document, find the one (if any)
112+
* that provides a `prerender` export
113+
*/
114+
const getPrerenderScriptFromHtml = async () => {
115+
if (!prerenderEntryHtml) throw new Error('Unable to detect entry HTML');
116+
117+
const htmlDoc = htmlParse(await fs.readFile(prerenderEntryHtml, 'utf-8'));
110118

111119
const entryScriptTag = htmlDoc
112120
.getElementsByTagName('script')
@@ -118,7 +126,9 @@ export function prerenderPlugin({ prerenderScript, renderTarget, additionalPrere
118126
if (!entrySrc || /^https:/.test(entrySrc))
119127
throw new Error('Prerender entry script must have a `src` attribute and be local');
120128

121-
return path.join(viteConfig.root, entrySrc);
129+
return entrySrc.startsWith('/')
130+
? path.join(viteConfig.root, entrySrc)
131+
: path.resolve(path.dirname(prerenderEntryHtml), entrySrc);
122132
};
123133

124134
return {
@@ -134,7 +144,7 @@ export function prerenderPlugin({ prerenderScript, renderTarget, additionalPrere
134144
// Only required for Vite 5 and older. In 6+, this is handled by the
135145
// Environment API (`applyToEnvironment`)
136146
if (config.build?.ssr) {
137-
ssrBuild = true
147+
ssrBuild = true;
138148
return;
139149
}
140150

@@ -194,8 +204,9 @@ export function prerenderPlugin({ prerenderScript, renderTarget, additionalPrere
194204
},
195205
async options(opts) {
196206
if (ssrBuild || !opts.input) return;
207+
prerenderEntryHtml = getPrerenderEntryHtml(opts.input);
197208
if (!prerenderScript) {
198-
prerenderScript = await getPrerenderScriptFromHTML(opts.input);
209+
prerenderScript = await getPrerenderScriptFromHtml();
199210
}
200211

201212
// prettier-ignore
@@ -288,9 +299,25 @@ export function prerenderPlugin({ prerenderScript, renderTarget, additionalPrere
288299
};
289300

290301
// Grab the generated HTML file, we'll use it as a template for all pages:
291-
const tpl = /** @type {string} */ (
292-
/** @type {OutputAsset} */ (bundle['index.html']).source
293-
);
302+
const entryHtmlAsset =
303+
(prerenderEntryHtml &&
304+
Object.values(bundle).find(
305+
(output) =>
306+
output.type === 'asset' &&
307+
output.fileName.endsWith('.html') &&
308+
(output.originalFileName === prerenderEntryHtml ||
309+
output.originalFileNames?.includes(prerenderEntryHtml)),
310+
)) ||
311+
/** @type {OutputAsset | undefined} */ (bundle['index.html']) ||
312+
Object.values(bundle).find(
313+
(output) => output.type === 'asset' && output.fileName.endsWith('.html'),
314+
);
315+
316+
if (!entryHtmlAsset) {
317+
this.error('Unable to detect generated entry HTML asset');
318+
}
319+
320+
const tpl = /** @type {string} */ (entryHtmlAsset.source);
294321

295322
// Create a tmp dir to allow importing & consuming the built modules,
296323
// before Rollup writes them to the disk
@@ -506,8 +533,7 @@ export function prerenderPlugin({ prerenderScript, renderTarget, additionalPrere
506533

507534
// Add generated HTML to compilation:
508535
route.url == '/'
509-
? (/** @type {OutputAsset} */ (bundle['index.html']).source =
510-
htmlDoc.toString())
536+
? (entryHtmlAsset.source = htmlDoc.toString())
511537
: this.emitFile({
512538
type: 'asset',
513539
fileName: assetName,
@@ -535,6 +561,6 @@ export function prerenderPlugin({ prerenderScript, renderTarget, additionalPrere
535561
}
536562
}
537563
}
538-
}
564+
},
539565
};
540566
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
</head>
6+
<body>
7+
<script prerender type="module" src="./main.js"></script>
8+
</body>
9+
</html>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export async function prerender() {
2+
return `<h1>Nested Entry Test Result</h1>`;
3+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { defineConfig } from 'vite';
2+
import path from 'node:path';
3+
import url from 'node:url';
4+
import { vitePrerenderPlugin } from 'vite-prerender-plugin';
5+
6+
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
7+
8+
export default defineConfig({
9+
build: {
10+
rollupOptions: {
11+
input: {
12+
dashboard: path.resolve(__dirname, 'src/dashboard/index.html'),
13+
},
14+
},
15+
},
16+
plugins: [vitePrerenderPlugin()],
17+
});

tests/index.test.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ test('Should merge preload and entry chunks', async () => {
3737
assert.equal((await fs.readdir(outDirAssets)).length, 1);
3838
});
3939

40+
test('Should support nested HTML entrypoints', async () => {
41+
await loadFixture('nested-entry', env);
42+
await viteBuild(env.tmp.path);
43+
44+
const prerenderedHtml = await getOutputFile(env.tmp.path, 'src/dashboard/index.html');
45+
assert.match(prerenderedHtml, '<h1>Nested Entry Test Result</h1>');
46+
});
47+
4048
test('Should bail on merging preload & entry chunks if user configures `manualChunks`', async () => {
4149
await loadFixture('simple', env);
4250
await writeConfig(env.tmp.path, `

0 commit comments

Comments
 (0)