wip(ssr): render real components
This commit is contained in:
parent
da25517377
commit
cee36ad028
@ -7,6 +7,7 @@ module.exports = {
|
|||||||
__BROWSER__: false,
|
__BROWSER__: false,
|
||||||
__BUNDLER__: true,
|
__BUNDLER__: true,
|
||||||
__RUNTIME_COMPILE__: true,
|
__RUNTIME_COMPILE__: true,
|
||||||
|
__SSR__: false,
|
||||||
__FEATURE_OPTIONS__: true,
|
__FEATURE_OPTIONS__: true,
|
||||||
__FEATURE_SUSPENSE__: true
|
__FEATURE_SUSPENSE__: true
|
||||||
},
|
},
|
||||||
|
1
packages/global.d.ts
vendored
1
packages/global.d.ts
vendored
@ -4,6 +4,7 @@ declare var __TEST__: boolean
|
|||||||
declare var __BROWSER__: boolean
|
declare var __BROWSER__: boolean
|
||||||
declare var __BUNDLER__: boolean
|
declare var __BUNDLER__: boolean
|
||||||
declare var __RUNTIME_COMPILE__: boolean
|
declare var __RUNTIME_COMPILE__: boolean
|
||||||
|
declare var __SSR__: boolean
|
||||||
declare var __COMMIT__: string
|
declare var __COMMIT__: string
|
||||||
declare var __VERSION__: string
|
declare var __VERSION__: string
|
||||||
|
|
||||||
|
@ -5,8 +5,8 @@ import {
|
|||||||
ComponentPublicInstance,
|
ComponentPublicInstance,
|
||||||
runtimeCompiledRenderProxyHandlers
|
runtimeCompiledRenderProxyHandlers
|
||||||
} from './componentProxy'
|
} from './componentProxy'
|
||||||
import { ComponentPropsOptions } from './componentProps'
|
import { ComponentPropsOptions, resolveProps } from './componentProps'
|
||||||
import { Slots } from './componentSlots'
|
import { Slots, resolveSlots } from './componentSlots'
|
||||||
import { warn } from './warning'
|
import { warn } from './warning'
|
||||||
import {
|
import {
|
||||||
ErrorCodes,
|
ErrorCodes,
|
||||||
@ -34,6 +34,7 @@ import {
|
|||||||
currentRenderingInstance,
|
currentRenderingInstance,
|
||||||
markAttrsAccessed
|
markAttrsAccessed
|
||||||
} from './componentRenderUtils'
|
} from './componentRenderUtils'
|
||||||
|
import { ShapeFlags } from '.'
|
||||||
|
|
||||||
export type Data = { [key: string]: unknown }
|
export type Data = { [key: string]: unknown }
|
||||||
|
|
||||||
@ -268,10 +269,26 @@ export function validateComponentName(name: string, config: AppConfig) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setupStatefulComponent(
|
export function setupComponent(
|
||||||
instance: ComponentInternalInstance,
|
instance: ComponentInternalInstance,
|
||||||
parentSuspense: SuspenseBoundary | null
|
parentSuspense: SuspenseBoundary | null
|
||||||
) {
|
) {
|
||||||
|
const propsOptions = instance.type.props
|
||||||
|
const { props, children, shapeFlag } = instance.vnode
|
||||||
|
resolveProps(instance, props, propsOptions)
|
||||||
|
resolveSlots(instance, children)
|
||||||
|
|
||||||
|
// setup stateful logic
|
||||||
|
if (shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
|
||||||
|
return setupStatefulComponent(instance, parentSuspense)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupStatefulComponent(
|
||||||
|
instance: ComponentInternalInstance,
|
||||||
|
parentSuspense: SuspenseBoundary | null
|
||||||
|
) {
|
||||||
|
let setupResult
|
||||||
const Component = instance.type as ComponentOptions
|
const Component = instance.type as ComponentOptions
|
||||||
|
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
@ -307,7 +324,7 @@ export function setupStatefulComponent(
|
|||||||
|
|
||||||
currentInstance = instance
|
currentInstance = instance
|
||||||
currentSuspense = parentSuspense
|
currentSuspense = parentSuspense
|
||||||
const setupResult = callWithErrorHandling(
|
setupResult = callWithErrorHandling(
|
||||||
setup,
|
setup,
|
||||||
instance,
|
instance,
|
||||||
ErrorCodes.SETUP_FUNCTION,
|
ErrorCodes.SETUP_FUNCTION,
|
||||||
@ -333,6 +350,8 @@ export function setupStatefulComponent(
|
|||||||
} else {
|
} else {
|
||||||
finishComponentSetup(instance, parentSuspense)
|
finishComponentSetup(instance, parentSuspense)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return setupResult
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleSetupResult(
|
export function handleSetupResult(
|
||||||
@ -398,7 +417,7 @@ function finishComponentSetup(
|
|||||||
`does not support runtime template compilation. Either use the ` +
|
`does not support runtime template compilation. Either use the ` +
|
||||||
`full build or pre-compile the template using Vue CLI.`
|
`full build or pre-compile the template using Vue CLI.`
|
||||||
)
|
)
|
||||||
} else {
|
} else if (!__SSR__ || !Component.ssrRender) {
|
||||||
warn(
|
warn(
|
||||||
`Component is missing${
|
`Component is missing${
|
||||||
__RUNTIME_COMPILE__ ? ` template or` : ``
|
__RUNTIME_COMPILE__ ? ` template or` : ``
|
||||||
|
@ -97,6 +97,9 @@ export const camelize = _camelize as (s: string) => string
|
|||||||
// For integration with runtime compiler
|
// For integration with runtime compiler
|
||||||
export { registerRuntimeCompiler } from './component'
|
export { registerRuntimeCompiler } from './component'
|
||||||
|
|
||||||
|
// For server-renderer
|
||||||
|
export { createComponentInstance, setupComponent } from './component'
|
||||||
|
|
||||||
// Types -----------------------------------------------------------------------
|
// Types -----------------------------------------------------------------------
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -13,9 +13,9 @@ import {
|
|||||||
import {
|
import {
|
||||||
ComponentInternalInstance,
|
ComponentInternalInstance,
|
||||||
createComponentInstance,
|
createComponentInstance,
|
||||||
setupStatefulComponent,
|
|
||||||
Component,
|
Component,
|
||||||
Data
|
Data,
|
||||||
|
setupComponent
|
||||||
} from './component'
|
} from './component'
|
||||||
import {
|
import {
|
||||||
renderComponentRoot,
|
renderComponentRoot,
|
||||||
@ -940,8 +940,6 @@ export function createRenderer<
|
|||||||
pushWarningContext(initialVNode)
|
pushWarningContext(initialVNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
const Comp = initialVNode.type as Component
|
|
||||||
|
|
||||||
// inject renderer internals for keepAlive
|
// inject renderer internals for keepAlive
|
||||||
if (isKeepAlive(initialVNode)) {
|
if (isKeepAlive(initialVNode)) {
|
||||||
const sink = instance.sink as KeepAliveSink
|
const sink = instance.sink as KeepAliveSink
|
||||||
@ -950,14 +948,7 @@ export function createRenderer<
|
|||||||
}
|
}
|
||||||
|
|
||||||
// resolve props and slots for setup context
|
// resolve props and slots for setup context
|
||||||
const propsOptions = Comp.props
|
setupComponent(instance, parentSuspense)
|
||||||
resolveProps(instance, initialVNode.props, propsOptions)
|
|
||||||
resolveSlots(instance, initialVNode.children)
|
|
||||||
|
|
||||||
// setup stateful logic
|
|
||||||
if (initialVNode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
|
|
||||||
setupStatefulComponent(instance, parentSuspense)
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup() is async. This component relies on async logic to be resolved
|
// setup() is async. This component relies on async logic to be resolved
|
||||||
// before proceeding
|
// before proceeding
|
||||||
|
@ -27,6 +27,6 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/vuejs/vue/tree/dev/packages/server-renderer#readme",
|
"homepage": "https://github.com/vuejs/vue/tree/dev/packages/server-renderer#readme",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@vue/runtime-dom": "3.0.0-alpha.3"
|
"vue": "3.0.0-alpha.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,11 @@ import {
|
|||||||
App,
|
App,
|
||||||
Component,
|
Component,
|
||||||
ComponentInternalInstance,
|
ComponentInternalInstance,
|
||||||
SuspenseBoundary
|
createComponentInstance,
|
||||||
} from '@vue/runtime-dom'
|
setupComponent,
|
||||||
|
VNode,
|
||||||
|
createVNode
|
||||||
|
} from 'vue'
|
||||||
import { isString } from '@vue/shared'
|
import { isString } from '@vue/shared'
|
||||||
|
|
||||||
type SSRBuffer = SSRBufferItem[]
|
type SSRBuffer = SSRBufferItem[]
|
||||||
@ -30,9 +33,7 @@ function createSSRBuffer() {
|
|||||||
export async function renderToString(app: App): Promise<string> {
|
export async function renderToString(app: App): Promise<string> {
|
||||||
const resolvedBuffer = (await renderComponent(
|
const resolvedBuffer = (await renderComponent(
|
||||||
app._component,
|
app._component,
|
||||||
app._props,
|
app._props
|
||||||
null,
|
|
||||||
null
|
|
||||||
)) as ResolvedSSRBuffer
|
)) as ResolvedSSRBuffer
|
||||||
return unrollBuffer(resolvedBuffer)
|
return unrollBuffer(resolvedBuffer)
|
||||||
}
|
}
|
||||||
@ -52,19 +53,17 @@ function unrollBuffer(buffer: ResolvedSSRBuffer): string {
|
|||||||
|
|
||||||
export async function renderComponent(
|
export async function renderComponent(
|
||||||
comp: Component,
|
comp: Component,
|
||||||
props: Record<string, any> | null,
|
props: Record<string, any> | null = null,
|
||||||
parentComponent: ComponentInternalInstance | null,
|
children: VNode['children'] = null,
|
||||||
parentSuspense: SuspenseBoundary | null
|
parentComponent: ComponentInternalInstance | null = null
|
||||||
): Promise<SSRBuffer> {
|
): Promise<SSRBuffer> {
|
||||||
// 1. create component buffer
|
// 1. create component buffer
|
||||||
const { buffer, push } = createSSRBuffer()
|
const { buffer, push } = createSSRBuffer()
|
||||||
|
|
||||||
// 2. TODO create actual instance
|
// 2. create actual instance
|
||||||
const instance = {
|
const vnode = createVNode(comp, props, children)
|
||||||
proxy: {
|
const instance = createComponentInstance(vnode, parentComponent)
|
||||||
msg: 'hello'
|
await setupComponent(instance, null)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof comp === 'function') {
|
if (typeof comp === 'function') {
|
||||||
// TODO FunctionalComponent
|
// TODO FunctionalComponent
|
||||||
|
@ -79,6 +79,7 @@ function createConfig(format, output, plugins = []) {
|
|||||||
process.env.__DEV__ === 'false' || /\.prod\.js$/.test(output.file)
|
process.env.__DEV__ === 'false' || /\.prod\.js$/.test(output.file)
|
||||||
const isGlobalBuild = format === 'global'
|
const isGlobalBuild = format === 'global'
|
||||||
const isRawESMBuild = format === 'esm'
|
const isRawESMBuild = format === 'esm'
|
||||||
|
const isNodeBuild = format === 'cjs'
|
||||||
const isBundlerESMBuild = /esm-bundler/.test(format)
|
const isBundlerESMBuild = /esm-bundler/.test(format)
|
||||||
const isRuntimeCompileBuild = /vue\./.test(output.file)
|
const isRuntimeCompileBuild = /vue\./.test(output.file)
|
||||||
|
|
||||||
@ -111,14 +112,16 @@ function createConfig(format, output, plugins = []) {
|
|||||||
const entryFile =
|
const entryFile =
|
||||||
format === 'esm-bundler-runtime' ? `src/runtime.ts` : `src/index.ts`
|
format === 'esm-bundler-runtime' ? `src/runtime.ts` : `src/index.ts`
|
||||||
|
|
||||||
|
const external =
|
||||||
|
isGlobalBuild || isRawESMBuild
|
||||||
|
? []
|
||||||
|
: knownExternals.concat(Object.keys(pkg.dependencies || []))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
input: resolve(entryFile),
|
input: resolve(entryFile),
|
||||||
// Global and Browser ESM builds inlines everything so that they can be
|
// Global and Browser ESM builds inlines everything so that they can be
|
||||||
// used alone.
|
// used alone.
|
||||||
external:
|
external,
|
||||||
isGlobalBuild || isRawESMBuild
|
|
||||||
? []
|
|
||||||
: knownExternals.concat(Object.keys(pkg.dependencies || [])),
|
|
||||||
plugins: [
|
plugins: [
|
||||||
json({
|
json({
|
||||||
namedExports: false
|
namedExports: false
|
||||||
@ -127,9 +130,11 @@ function createConfig(format, output, plugins = []) {
|
|||||||
createReplacePlugin(
|
createReplacePlugin(
|
||||||
isProductionBuild,
|
isProductionBuild,
|
||||||
isBundlerESMBuild,
|
isBundlerESMBuild,
|
||||||
|
// isBrowserBuild?
|
||||||
(isGlobalBuild || isRawESMBuild || isBundlerESMBuild) &&
|
(isGlobalBuild || isRawESMBuild || isBundlerESMBuild) &&
|
||||||
!packageOptions.enableNonBrowserBranches,
|
!packageOptions.enableNonBrowserBranches,
|
||||||
isRuntimeCompileBuild
|
isRuntimeCompileBuild,
|
||||||
|
isNodeBuild
|
||||||
),
|
),
|
||||||
...plugins
|
...plugins
|
||||||
],
|
],
|
||||||
@ -146,7 +151,8 @@ function createReplacePlugin(
|
|||||||
isProduction,
|
isProduction,
|
||||||
isBundlerESMBuild,
|
isBundlerESMBuild,
|
||||||
isBrowserBuild,
|
isBrowserBuild,
|
||||||
isRuntimeCompileBuild
|
isRuntimeCompileBuild,
|
||||||
|
isNodeBuild
|
||||||
) {
|
) {
|
||||||
const replacements = {
|
const replacements = {
|
||||||
__COMMIT__: `"${process.env.COMMIT}"`,
|
__COMMIT__: `"${process.env.COMMIT}"`,
|
||||||
@ -164,6 +170,8 @@ function createReplacePlugin(
|
|||||||
__BUNDLER__: isBundlerESMBuild,
|
__BUNDLER__: isBundlerESMBuild,
|
||||||
// support compile in browser?
|
// support compile in browser?
|
||||||
__RUNTIME_COMPILE__: isRuntimeCompileBuild,
|
__RUNTIME_COMPILE__: isRuntimeCompileBuild,
|
||||||
|
// is targeting Node (SSR)?
|
||||||
|
__SSR__: isNodeBuild,
|
||||||
// support options?
|
// support options?
|
||||||
// the lean build drops options related code with buildOptions.lean: true
|
// the lean build drops options related code with buildOptions.lean: true
|
||||||
__FEATURE_OPTIONS__: !packageOptions.lean && !process.env.LEAN,
|
__FEATURE_OPTIONS__: !packageOptions.lean && !process.env.LEAN,
|
||||||
|
Loading…
Reference in New Issue
Block a user