Skip to content

Commit cee36ad

Browse files
committed
wip(ssr): render real components
1 parent da25517 commit cee36ad

File tree

8 files changed

+60
-38
lines changed

8 files changed

+60
-38
lines changed

jest.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module.exports = {
77
__BROWSER__: false,
88
__BUNDLER__: true,
99
__RUNTIME_COMPILE__: true,
10+
__SSR__: false,
1011
__FEATURE_OPTIONS__: true,
1112
__FEATURE_SUSPENSE__: true
1213
},

packages/global.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ declare var __TEST__: boolean
44
declare var __BROWSER__: boolean
55
declare var __BUNDLER__: boolean
66
declare var __RUNTIME_COMPILE__: boolean
7+
declare var __SSR__: boolean
78
declare var __COMMIT__: string
89
declare var __VERSION__: string
910

packages/runtime-core/src/component.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import {
55
ComponentPublicInstance,
66
runtimeCompiledRenderProxyHandlers
77
} from './componentProxy'
8-
import { ComponentPropsOptions } from './componentProps'
9-
import { Slots } from './componentSlots'
8+
import { ComponentPropsOptions, resolveProps } from './componentProps'
9+
import { Slots, resolveSlots } from './componentSlots'
1010
import { warn } from './warning'
1111
import {
1212
ErrorCodes,
@@ -34,6 +34,7 @@ import {
3434
currentRenderingInstance,
3535
markAttrsAccessed
3636
} from './componentRenderUtils'
37+
import { ShapeFlags } from '.'
3738

3839
export type Data = { [key: string]: unknown }
3940

@@ -268,10 +269,26 @@ export function validateComponentName(name: string, config: AppConfig) {
268269
}
269270
}
270271

271-
export function setupStatefulComponent(
272+
export function setupComponent(
272273
instance: ComponentInternalInstance,
273274
parentSuspense: SuspenseBoundary | null
274275
) {
276+
const propsOptions = instance.type.props
277+
const { props, children, shapeFlag } = instance.vnode
278+
resolveProps(instance, props, propsOptions)
279+
resolveSlots(instance, children)
280+
281+
// setup stateful logic
282+
if (shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
283+
return setupStatefulComponent(instance, parentSuspense)
284+
}
285+
}
286+
287+
function setupStatefulComponent(
288+
instance: ComponentInternalInstance,
289+
parentSuspense: SuspenseBoundary | null
290+
) {
291+
let setupResult
275292
const Component = instance.type as ComponentOptions
276293

277294
if (__DEV__) {
@@ -307,7 +324,7 @@ export function setupStatefulComponent(
307324

308325
currentInstance = instance
309326
currentSuspense = parentSuspense
310-
const setupResult = callWithErrorHandling(
327+
setupResult = callWithErrorHandling(
311328
setup,
312329
instance,
313330
ErrorCodes.SETUP_FUNCTION,
@@ -333,6 +350,8 @@ export function setupStatefulComponent(
333350
} else {
334351
finishComponentSetup(instance, parentSuspense)
335352
}
353+
354+
return setupResult
336355
}
337356

338357
export function handleSetupResult(
@@ -398,7 +417,7 @@ function finishComponentSetup(
398417
`does not support runtime template compilation. Either use the ` +
399418
`full build or pre-compile the template using Vue CLI.`
400419
)
401-
} else {
420+
} else if (!__SSR__ || !Component.ssrRender) {
402421
warn(
403422
`Component is missing${
404423
__RUNTIME_COMPILE__ ? ` template or` : ``

packages/runtime-core/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ export const camelize = _camelize as (s: string) => string
9797
// For integration with runtime compiler
9898
export { registerRuntimeCompiler } from './component'
9999

100+
// For server-renderer
101+
export { createComponentInstance, setupComponent } from './component'
102+
100103
// Types -----------------------------------------------------------------------
101104

102105
export {

packages/runtime-core/src/renderer.ts

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ import {
1313
import {
1414
ComponentInternalInstance,
1515
createComponentInstance,
16-
setupStatefulComponent,
1716
Component,
18-
Data
17+
Data,
18+
setupComponent
1919
} from './component'
2020
import {
2121
renderComponentRoot,
@@ -940,8 +940,6 @@ export function createRenderer<
940940
pushWarningContext(initialVNode)
941941
}
942942

943-
const Comp = initialVNode.type as Component
944-
945943
// inject renderer internals for keepAlive
946944
if (isKeepAlive(initialVNode)) {
947945
const sink = instance.sink as KeepAliveSink
@@ -950,14 +948,7 @@ export function createRenderer<
950948
}
951949

952950
// resolve props and slots for setup context
953-
const propsOptions = Comp.props
954-
resolveProps(instance, initialVNode.props, propsOptions)
955-
resolveSlots(instance, initialVNode.children)
956-
957-
// setup stateful logic
958-
if (initialVNode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
959-
setupStatefulComponent(instance, parentSuspense)
960-
}
951+
setupComponent(instance, parentSuspense)
961952

962953
// setup() is async. This component relies on async logic to be resolved
963954
// before proceeding

packages/server-renderer/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@
2727
},
2828
"homepage": "https://github.com/vuejs/vue/tree/dev/packages/server-renderer#readme",
2929
"peerDependencies": {
30-
"@vue/runtime-dom": "3.0.0-alpha.3"
30+
"vue": "3.0.0-alpha.3"
3131
}
3232
}

packages/server-renderer/src/index.ts

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ import {
22
App,
33
Component,
44
ComponentInternalInstance,
5-
SuspenseBoundary
6-
} from '@vue/runtime-dom'
5+
createComponentInstance,
6+
setupComponent,
7+
VNode,
8+
createVNode
9+
} from 'vue'
710
import { isString } from '@vue/shared'
811

912
type SSRBuffer = SSRBufferItem[]
@@ -30,9 +33,7 @@ function createSSRBuffer() {
3033
export async function renderToString(app: App): Promise<string> {
3134
const resolvedBuffer = (await renderComponent(
3235
app._component,
33-
app._props,
34-
null,
35-
null
36+
app._props
3637
)) as ResolvedSSRBuffer
3738
return unrollBuffer(resolvedBuffer)
3839
}
@@ -52,19 +53,17 @@ function unrollBuffer(buffer: ResolvedSSRBuffer): string {
5253

5354
export async function renderComponent(
5455
comp: Component,
55-
props: Record<string, any> | null,
56-
parentComponent: ComponentInternalInstance | null,
57-
parentSuspense: SuspenseBoundary | null
56+
props: Record<string, any> | null = null,
57+
children: VNode['children'] = null,
58+
parentComponent: ComponentInternalInstance | null = null
5859
): Promise<SSRBuffer> {
5960
// 1. create component buffer
6061
const { buffer, push } = createSSRBuffer()
6162

62-
// 2. TODO create actual instance
63-
const instance = {
64-
proxy: {
65-
msg: 'hello'
66-
}
67-
}
63+
// 2. create actual instance
64+
const vnode = createVNode(comp, props, children)
65+
const instance = createComponentInstance(vnode, parentComponent)
66+
await setupComponent(instance, null)
6867

6968
if (typeof comp === 'function') {
7069
// TODO FunctionalComponent

rollup.config.js

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ function createConfig(format, output, plugins = []) {
7979
process.env.__DEV__ === 'false' || /\.prod\.js$/.test(output.file)
8080
const isGlobalBuild = format === 'global'
8181
const isRawESMBuild = format === 'esm'
82+
const isNodeBuild = format === 'cjs'
8283
const isBundlerESMBuild = /esm-bundler/.test(format)
8384
const isRuntimeCompileBuild = /vue\./.test(output.file)
8485

@@ -111,14 +112,16 @@ function createConfig(format, output, plugins = []) {
111112
const entryFile =
112113
format === 'esm-bundler-runtime' ? `src/runtime.ts` : `src/index.ts`
113114

115+
const external =
116+
isGlobalBuild || isRawESMBuild
117+
? []
118+
: knownExternals.concat(Object.keys(pkg.dependencies || []))
119+
114120
return {
115121
input: resolve(entryFile),
116122
// Global and Browser ESM builds inlines everything so that they can be
117123
// used alone.
118-
external:
119-
isGlobalBuild || isRawESMBuild
120-
? []
121-
: knownExternals.concat(Object.keys(pkg.dependencies || [])),
124+
external,
122125
plugins: [
123126
json({
124127
namedExports: false
@@ -127,9 +130,11 @@ function createConfig(format, output, plugins = []) {
127130
createReplacePlugin(
128131
isProductionBuild,
129132
isBundlerESMBuild,
133+
// isBrowserBuild?
130134
(isGlobalBuild || isRawESMBuild || isBundlerESMBuild) &&
131135
!packageOptions.enableNonBrowserBranches,
132-
isRuntimeCompileBuild
136+
isRuntimeCompileBuild,
137+
isNodeBuild
133138
),
134139
...plugins
135140
],
@@ -146,7 +151,8 @@ function createReplacePlugin(
146151
isProduction,
147152
isBundlerESMBuild,
148153
isBrowserBuild,
149-
isRuntimeCompileBuild
154+
isRuntimeCompileBuild,
155+
isNodeBuild
150156
) {
151157
const replacements = {
152158
__COMMIT__: `"${process.env.COMMIT}"`,
@@ -164,6 +170,8 @@ function createReplacePlugin(
164170
__BUNDLER__: isBundlerESMBuild,
165171
// support compile in browser?
166172
__RUNTIME_COMPILE__: isRuntimeCompileBuild,
173+
// is targeting Node (SSR)?
174+
__SSR__: isNodeBuild,
167175
// support options?
168176
// the lean build drops options related code with buildOptions.lean: true
169177
__FEATURE_OPTIONS__: !packageOptions.lean && !process.env.LEAN,

0 commit comments

Comments
 (0)