Skip to content

Commit 12e0994

Browse files
authored
Merge branch 'main' into edison/feat/sourcemap
2 parents 85d6056 + 52a193a commit 12e0994

File tree

8 files changed

+107
-22
lines changed

8 files changed

+107
-22
lines changed

src/Repl.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export interface Props {
2020
showCompileOutput?: boolean
2121
showOpenSourceMap?: boolean
2222
showImportMap?: boolean
23+
showSsrOutput?: boolean
2324
showTsConfig?: boolean
2425
clearConsole?: boolean
2526
layout?: 'horizontal' | 'vertical'
@@ -56,6 +57,7 @@ const props = withDefaults(defineProps<Props>(), {
5657
showCompileOutput: true,
5758
showOpenSourceMap: false,
5859
showImportMap: true,
60+
showSsrOutput: false,
5961
showTsConfig: true,
6062
clearConsole: true,
6163
layoutReverse: false,
@@ -108,6 +110,7 @@ defineExpose({ reload })
108110
:editor-component="editor"
109111
:show-compile-output="props.showCompileOutput"
110112
:show-open-source-map="props.showOpenSourceMap"
113+
:show-ssr-output="props.showSsrOutput"
111114
:ssr="!!props.ssr"
112115
/>
113116
</template>

src/output/Output.vue

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script setup lang="ts">
22
import Preview from './Preview.vue'
3-
import { computed, inject, useTemplateRef } from 'vue'
3+
import SsrOutput from './SsrOutput.vue'
4+
import { computed, inject, useTemplateRef, watchEffect } from 'vue'
45
import {
56
type EditorComponentType,
67
type OutputModes,
@@ -10,28 +11,33 @@ import {
1011
const props = defineProps<{
1112
editorComponent: EditorComponentType
1213
showCompileOutput?: boolean
13-
ssr: boolean,
1414
showOpenSourceMap?: boolean
15+
showSsrOutput?: boolean
16+
ssr: boolean
1517
}>()
1618
1719
const { store } = inject(injectKeyProps)!
1820
const previewRef = useTemplateRef('preview')
19-
const modes = computed(() =>
20-
props.showCompileOutput
21-
? (['preview', 'js', 'css', 'ssr'] as const)
22-
: (['preview'] as const),
23-
)
21+
const modes = computed(() => {
22+
const outputModes: OutputModes[] = ['preview']
23+
if (props.showCompileOutput) {
24+
outputModes.push('js', 'css', 'ssr')
25+
}
26+
if (props.ssr && props.showSsrOutput) {
27+
outputModes.push('ssr output')
28+
}
29+
return outputModes
30+
})
2431
2532
const mode = computed<OutputModes>({
26-
get: () =>
27-
(modes.value as readonly string[]).includes(store.value.outputMode)
28-
? store.value.outputMode
29-
: 'preview',
30-
set(value) {
31-
if ((modes.value as readonly string[]).includes(store.value.outputMode)) {
32-
store.value.outputMode = value
33-
}
34-
},
33+
get: () => store.value.outputMode,
34+
set: (value) => (store.value.outputMode = value),
35+
})
36+
37+
watchEffect(() => {
38+
if (!modes.value.includes(mode.value)) {
39+
mode.value = modes.value[0]
40+
}
3541
})
3642
3743
const showSourceMap = computed(() => {
@@ -64,8 +70,13 @@ defineExpose({ reload, previewRef })
6470

6571
<div class="output-container">
6672
<Preview ref="preview" :show="mode === 'preview'" :ssr="ssr" />
73+
<SsrOutput
74+
v-if="mode === 'ssr output'"
75+
:context="store.ssrOutput.context"
76+
:html="store.ssrOutput.html"
77+
/>
6778
<props.editorComponent
68-
v-if="mode !== 'preview'"
79+
v-else-if="mode !== 'preview'"
6980
readonly
7081
:filename="store.activeFile.filename"
7182
:value="store.activeFile.compiled[mode]"

src/output/Sandbox.vue

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,8 @@ async function updatePreview() {
223223
console.info(
224224
`[@vue/repl] successfully compiled ${ssrModules.length} modules for SSR.`,
225225
)
226-
await proxy.eval([
226+
store.value.ssrOutput.html = store.value.ssrOutput.context = ''
227+
const response = await proxy.eval([
227228
`const __modules__ = {};`,
228229
...ssrModules,
229230
`import { renderToString as _renderToString } from 'vue/server-renderer'
@@ -235,15 +236,41 @@ async function updatePreview() {
235236
app.config.unwrapInjectedRef = true
236237
}
237238
app.config.warnHandler = () => {}
238-
window.__ssr_promise__ = _renderToString(app).then(html => {
239+
const rawContext = {}
240+
window.__ssr_promise__ = _renderToString(app, rawContext).then(html => {
239241
document.body.innerHTML = '<div id="app">' + html + '</div>' + \`${
240242
previewOptions.value?.bodyHTML || ''
241243
}\`
244+
const safeContext = {}
245+
const isSafe = (v) =>
246+
v === null ||
247+
typeof v === 'boolean' ||
248+
typeof v === 'string' ||
249+
Number.isFinite(v)
250+
const toSafe = (v) => (isSafe(v) ? v : '[' + typeof v + ']')
251+
for (const prop in rawContext) {
252+
const value = rawContext[prop]
253+
safeContext[prop] = isSafe(value)
254+
? value
255+
: Array.isArray(value)
256+
? value.map(toSafe)
257+
: typeof value === 'object'
258+
? Object.fromEntries(
259+
Object.entries(value).map(([k, v]) => [k, toSafe(v)]),
260+
)
261+
: toSafe(value)
262+
}
263+
return { ssrHtml: html, ssrContext: safeContext }
242264
}).catch(err => {
243265
console.error("SSR Error", err)
244266
})
245267
`,
246268
])
269+
270+
if (response) {
271+
store.value.ssrOutput.html = String((response as any).ssrHtml ?? '')
272+
store.value.ssrOutput.context = (response as any).ssrContext || ''
273+
}
247274
}
248275
249276
// compile code to simulated module system

src/output/SsrOutput.vue

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<script setup lang="ts">
2+
defineProps<{
3+
html: string
4+
context: unknown
5+
}>()
6+
</script>
7+
8+
<template>
9+
<div class="ssr-output">
10+
<strong>HTML</strong>
11+
<pre class="ssr-output-pre">{{ html }}</pre>
12+
<strong>Context</strong>
13+
<pre class="ssr-output-pre">{{ context }}</pre>
14+
</div>
15+
</template>
16+
17+
<style scoped>
18+
.ssr-output {
19+
background: var(--bg);
20+
box-sizing: border-box;
21+
color: var(--text-light);
22+
height: 100%;
23+
overflow: auto;
24+
padding: 10px;
25+
width: 100%;
26+
}
27+
28+
.ssr-output-pre {
29+
font-family: var(--font-code);
30+
white-space: pre-wrap;
31+
}
32+
</style>

src/output/srcdoc.html

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535
const send_message = (payload) =>
3636
parent.postMessage({ ...payload }, ev.origin)
3737
const send_reply = (payload) => send_message({ ...payload, cmd_id })
38-
const send_ok = () => send_reply({ action: 'cmd_ok' })
38+
const send_ok = (response) =>
39+
send_reply({ action: 'cmd_ok', args: response })
3940
const send_error = (message, stack) =>
4041
send_reply({ action: 'cmd_error', message, stack })
4142

@@ -65,7 +66,11 @@
6566
scriptEls.push(scriptEl)
6667
await done
6768
}
68-
send_ok()
69+
if (window.__ssr_promise__) {
70+
send_ok(await window.__ssr_promise__)
71+
} else {
72+
send_ok()
73+
}
6974
} catch (e) {
7075
send_error(e.message, e.stack)
7176
}

src/store.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ export function useStore(
368368
showOutput,
369369
outputMode,
370370
sfcOptions,
371+
ssrOutput: { html: '', context: '' },
371372
compiler,
372373
loading,
373374
vueVersion,
@@ -429,6 +430,10 @@ export type StoreState = ToRefs<{
429430
showOutput: boolean
430431
outputMode: OutputModes
431432
sfcOptions: SFCOptions
433+
ssrOutput: {
434+
html: string
435+
context: unknown
436+
}
432437
/** `@vue/compiler-sfc` */
433438
compiler: typeof defaultCompiler
434439
/* only apply for compiler-sfc */
@@ -474,6 +479,7 @@ export type Store = Pick<
474479
| 'showOutput'
475480
| 'outputMode'
476481
| 'sfcOptions'
482+
| 'ssrOutput'
477483
| 'compiler'
478484
| 'vueVersion'
479485
| 'locale'

src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export interface EditorEmits {
1313
}
1414
export type EditorComponentType = Component<EditorProps>
1515

16-
export type OutputModes = 'preview' | EditorMode
16+
export type OutputModes = 'preview' | 'ssr output' | EditorMode
1717

1818
export const injectKeyProps: InjectionKey<
1919
ToRefs<Required<Props & { autoSave: boolean }>>

test/main.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ const App = {
6161
showOpenSourceMap: true,
6262
// layout: 'vertical',
6363
ssr: true,
64+
showSsrOutput: true,
6465
sfcOptions: {
6566
script: {
6667
// inlineTemplate: false

0 commit comments

Comments
 (0)