-
Notifications
You must be signed in to change notification settings - Fork 201
feat: show SSR output #343
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -223,7 +223,8 @@ async function updatePreview() { | |
console.info( | ||
`[@vue/repl] successfully compiled ${ssrModules.length} modules for SSR.`, | ||
) | ||
await proxy.eval([ | ||
store.value.ssrOutput.html = store.value.ssrOutput.context = '' | ||
const response = await proxy.eval([ | ||
`const __modules__ = {};`, | ||
...ssrModules, | ||
`import { renderToString as _renderToString } from 'vue/server-renderer' | ||
|
@@ -235,15 +236,41 @@ async function updatePreview() { | |
app.config.unwrapInjectedRef = true | ||
} | ||
app.config.warnHandler = () => {} | ||
window.__ssr_promise__ = _renderToString(app).then(html => { | ||
const rawContext = {} | ||
window.__ssr_promise__ = _renderToString(app, rawContext).then(html => { | ||
document.body.innerHTML = '<div id="app">' + html + '</div>' + \`${ | ||
previewOptions.value?.bodyHTML || '' | ||
}\` | ||
const safeContext = {} | ||
const isSafe = (v) => | ||
v === null || | ||
typeof v === 'boolean' || | ||
typeof v === 'string' || | ||
Number.isFinite(v) | ||
const toSafe = (v) => (isSafe(v) ? v : '[' + typeof v + ']') | ||
for (const prop in rawContext) { | ||
const value = rawContext[prop] | ||
safeContext[prop] = isSafe(value) | ||
? value | ||
: Array.isArray(value) | ||
? value.map(toSafe) | ||
: typeof value === 'object' | ||
? Object.fromEntries( | ||
Object.entries(value).map(([k, v]) => [k, toSafe(v)]), | ||
) | ||
: toSafe(value) | ||
} | ||
return { ssrHtml: html, ssrContext: safeContext } | ||
Comment on lines
+244
to
+263
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While this looks like a lot, it's just trying to make the SSR context object safe to pass to |
||
}).catch(err => { | ||
console.error("SSR Error", err) | ||
}) | ||
`, | ||
]) | ||
|
||
if (response) { | ||
store.value.ssrOutput.html = String((response as any).ssrHtml ?? '') | ||
store.value.ssrOutput.context = (response as any).ssrContext || '' | ||
} | ||
} | ||
|
||
// compile code to simulated module system | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<script setup lang="ts"> | ||
defineProps<{ | ||
html: string | ||
context: unknown | ||
}>() | ||
</script> | ||
|
||
<template> | ||
<div class="ssr-output"> | ||
<strong>HTML</strong> | ||
<pre class="ssr-output-pre">{{ html }}</pre> | ||
<strong>Context</strong> | ||
<pre class="ssr-output-pre">{{ context }}</pre> | ||
</div> | ||
</template> | ||
|
||
<style scoped> | ||
.ssr-output { | ||
background: var(--bg); | ||
box-sizing: border-box; | ||
color: var(--text-light); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In light mode the text is a bit lighter than I would like, but there didn't seem to be any other variables available I could use and I was reluctant to introduce a new one. |
||
height: 100%; | ||
overflow: auto; | ||
padding: 10px; | ||
width: 100%; | ||
} | ||
|
||
.ssr-output-pre { | ||
font-family: var(--font-code); | ||
white-space: pre-wrap; | ||
} | ||
</style> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,7 +35,8 @@ | |
const send_message = (payload) => | ||
parent.postMessage({ ...payload }, ev.origin) | ||
const send_reply = (payload) => send_message({ ...payload, cmd_id }) | ||
const send_ok = () => send_reply({ action: 'cmd_ok' }) | ||
const send_ok = (response) => | ||
send_reply({ action: 'cmd_ok', args: response }) | ||
const send_error = (message, stack) => | ||
send_reply({ action: 'cmd_error', message, stack }) | ||
|
||
|
@@ -65,7 +66,11 @@ | |
scriptEls.push(scriptEl) | ||
await done | ||
} | ||
send_ok() | ||
if (window.__ssr_promise__) { | ||
send_ok(await window.__ssr_promise__) | ||
} else { | ||
send_ok() | ||
} | ||
Comment on lines
+69
to
+73
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a bit of a hack, reusing |
||
} catch (e) { | ||
send_error(e.message, e.stack) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I switched to using
watchEffect
because I wanted the value in the store to be updated if the current tab isn't valid. This can happen if SSR mode is turned off when theSSR OUTPUT
tab is active. Turning SSR mode back on should stay on the newly active tab, rather than jumping back toSSR OUTPUT
.