wip(ssr): reduce reactivity overhead during ssr
This commit is contained in:
parent
cee36ad028
commit
25a0d4a65f
@ -56,6 +56,10 @@ export function computed<T>(
|
|||||||
// expose effect so computed can be stopped
|
// expose effect so computed can be stopped
|
||||||
effect: runner,
|
effect: runner,
|
||||||
get value() {
|
get value() {
|
||||||
|
if (__SSR__) {
|
||||||
|
return getter()
|
||||||
|
}
|
||||||
|
|
||||||
if (dirty) {
|
if (dirty) {
|
||||||
value = runner()
|
value = runner()
|
||||||
dirty = false
|
dirty = false
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { isObject, toRawType } from '@vue/shared'
|
import { isObject, toRawType, EMPTY_OBJ } from '@vue/shared'
|
||||||
import {
|
import {
|
||||||
mutableHandlers,
|
mutableHandlers,
|
||||||
readonlyHandlers,
|
readonlyHandlers,
|
||||||
@ -117,9 +117,15 @@ function createReactiveObject(
|
|||||||
if (!canObserve(target)) {
|
if (!canObserve(target)) {
|
||||||
return target
|
return target
|
||||||
}
|
}
|
||||||
const handlers = collectionTypes.has(target.constructor)
|
const handlers = __SSR__
|
||||||
? collectionHandlers
|
? // disable reactivity in SSR.
|
||||||
: baseHandlers
|
// NOTE: a potential caveat here is isReactive check may return different
|
||||||
|
// values on nested values on client/server. This should be very rare but
|
||||||
|
// we should keep an eye on this.
|
||||||
|
EMPTY_OBJ
|
||||||
|
: collectionTypes.has(target.constructor)
|
||||||
|
? collectionHandlers
|
||||||
|
: baseHandlers
|
||||||
observed = new Proxy(target, handlers)
|
observed = new Proxy(target, handlers)
|
||||||
toProxy.set(target, observed)
|
toProxy.set(target, observed)
|
||||||
toRaw.set(observed, target)
|
toRaw.set(observed, target)
|
||||||
|
@ -36,6 +36,14 @@ export function ref(raw?: unknown) {
|
|||||||
return raw
|
return raw
|
||||||
}
|
}
|
||||||
raw = convert(raw)
|
raw = convert(raw)
|
||||||
|
|
||||||
|
if (__SSR__) {
|
||||||
|
return {
|
||||||
|
_isRef: true,
|
||||||
|
value: raw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const r = {
|
const r = {
|
||||||
_isRef: true,
|
_isRef: true,
|
||||||
get value() {
|
get value() {
|
||||||
@ -58,7 +66,7 @@ export function ref(raw?: unknown) {
|
|||||||
export function toRefs<T extends object>(
|
export function toRefs<T extends object>(
|
||||||
object: T
|
object: T
|
||||||
): { [K in keyof T]: Ref<T[K]> } {
|
): { [K in keyof T]: Ref<T[K]> } {
|
||||||
if (__DEV__ && !isReactive(object)) {
|
if (__DEV__ && !__SSR__ && !isReactive(object)) {
|
||||||
console.warn(`toRefs() expects a reactive object but received a plain one.`)
|
console.warn(`toRefs() expects a reactive object but received a plain one.`)
|
||||||
}
|
}
|
||||||
const ret: any = {}
|
const ret: any = {}
|
||||||
|
@ -65,7 +65,8 @@ export function injectHook(
|
|||||||
export const createHook = <T extends Function = () => any>(
|
export const createHook = <T extends Function = () => any>(
|
||||||
lifecycle: LifecycleHooks
|
lifecycle: LifecycleHooks
|
||||||
) => (hook: T, target: ComponentInternalInstance | null = currentInstance) =>
|
) => (hook: T, target: ComponentInternalInstance | null = currentInstance) =>
|
||||||
injectHook(lifecycle, hook, target)
|
// post-create lifecycle registrations are noops during SSR
|
||||||
|
!__SSR__ && injectHook(lifecycle, hook, target)
|
||||||
|
|
||||||
export const onBeforeMount = createHook(LifecycleHooks.BEFORE_MOUNT)
|
export const onBeforeMount = createHook(LifecycleHooks.BEFORE_MOUNT)
|
||||||
export const onMounted = createHook(LifecycleHooks.MOUNTED)
|
export const onMounted = createHook(LifecycleHooks.MOUNTED)
|
||||||
@ -87,6 +88,10 @@ export type ErrorCapturedHook = (
|
|||||||
instance: ComponentPublicInstance | null,
|
instance: ComponentPublicInstance | null,
|
||||||
info: string
|
info: string
|
||||||
) => boolean | void
|
) => boolean | void
|
||||||
export const onErrorCaptured = createHook<ErrorCapturedHook>(
|
|
||||||
LifecycleHooks.ERROR_CAPTURED
|
export const onErrorCaptured = (
|
||||||
)
|
hook: ErrorCapturedHook,
|
||||||
|
target: ComponentInternalInstance | null = currentInstance
|
||||||
|
) => {
|
||||||
|
injectHook(LifecycleHooks.ERROR_CAPTURED, hook, target)
|
||||||
|
}
|
||||||
|
@ -218,7 +218,7 @@ export function applyOptions(
|
|||||||
) {
|
) {
|
||||||
const renderContext =
|
const renderContext =
|
||||||
instance.renderContext === EMPTY_OBJ
|
instance.renderContext === EMPTY_OBJ
|
||||||
? (instance.renderContext = reactive({}))
|
? (instance.renderContext = __SSR__ ? {} : reactive({}))
|
||||||
: instance.renderContext
|
: instance.renderContext
|
||||||
const ctx = instance.proxy!
|
const ctx = instance.proxy!
|
||||||
const {
|
const {
|
||||||
@ -285,7 +285,7 @@ export function applyOptions(
|
|||||||
checkDuplicateProperties!(OptionTypes.DATA, key)
|
checkDuplicateProperties!(OptionTypes.DATA, key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
instance.data = reactive(data)
|
instance.data = __SSR__ ? data : reactive(data)
|
||||||
} else {
|
} else {
|
||||||
// existing data: this is a mixin or extends.
|
// existing data: this is a mixin or extends.
|
||||||
extend(instance.data, data)
|
extend(instance.data, data)
|
||||||
|
@ -13,7 +13,8 @@ import {
|
|||||||
isArray,
|
isArray,
|
||||||
isFunction,
|
isFunction,
|
||||||
isString,
|
isString,
|
||||||
hasChanged
|
hasChanged,
|
||||||
|
NOOP
|
||||||
} from '@vue/shared'
|
} from '@vue/shared'
|
||||||
import { recordEffect } from './apiReactivity'
|
import { recordEffect } from './apiReactivity'
|
||||||
import {
|
import {
|
||||||
@ -85,7 +86,10 @@ export function watch<T = any>(
|
|||||||
cbOrOptions?: WatchCallback<T> | WatchOptions,
|
cbOrOptions?: WatchCallback<T> | WatchOptions,
|
||||||
options?: WatchOptions
|
options?: WatchOptions
|
||||||
): StopHandle {
|
): StopHandle {
|
||||||
if (isFunction(cbOrOptions)) {
|
if (__SSR__ && !(options && options.flush === 'sync')) {
|
||||||
|
// during SSR, non-sync watchers never fire.
|
||||||
|
return NOOP
|
||||||
|
} else if (isFunction(cbOrOptions)) {
|
||||||
// effect callback as 2nd argument - this is a source watcher
|
// effect callback as 2nd argument - this is a source watcher
|
||||||
return doWatch(effectOrSource, cbOrOptions, options)
|
return doWatch(effectOrSource, cbOrOptions, options)
|
||||||
} else {
|
} else {
|
||||||
|
@ -288,7 +288,6 @@ function setupStatefulComponent(
|
|||||||
instance: ComponentInternalInstance,
|
instance: ComponentInternalInstance,
|
||||||
parentSuspense: SuspenseBoundary | null
|
parentSuspense: SuspenseBoundary | null
|
||||||
) {
|
) {
|
||||||
let setupResult
|
|
||||||
const Component = instance.type as ComponentOptions
|
const Component = instance.type as ComponentOptions
|
||||||
|
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
@ -315,7 +314,9 @@ function setupStatefulComponent(
|
|||||||
// 2. create props proxy
|
// 2. create props proxy
|
||||||
// the propsProxy is a reactive AND readonly proxy to the actual props.
|
// the propsProxy is a reactive AND readonly proxy to the actual props.
|
||||||
// it will be updated in resolveProps() on updates before render
|
// it will be updated in resolveProps() on updates before render
|
||||||
const propsProxy = (instance.propsProxy = shallowReadonly(instance.props))
|
const propsProxy = (instance.propsProxy = __SSR__
|
||||||
|
? instance.props
|
||||||
|
: shallowReadonly(instance.props))
|
||||||
// 3. call setup()
|
// 3. call setup()
|
||||||
const { setup } = Component
|
const { setup } = Component
|
||||||
if (setup) {
|
if (setup) {
|
||||||
@ -324,7 +325,7 @@ function setupStatefulComponent(
|
|||||||
|
|
||||||
currentInstance = instance
|
currentInstance = instance
|
||||||
currentSuspense = parentSuspense
|
currentSuspense = parentSuspense
|
||||||
setupResult = callWithErrorHandling(
|
const setupResult = callWithErrorHandling(
|
||||||
setup,
|
setup,
|
||||||
instance,
|
instance,
|
||||||
ErrorCodes.SETUP_FUNCTION,
|
ErrorCodes.SETUP_FUNCTION,
|
||||||
@ -334,7 +335,10 @@ function setupStatefulComponent(
|
|||||||
currentSuspense = null
|
currentSuspense = null
|
||||||
|
|
||||||
if (isPromise(setupResult)) {
|
if (isPromise(setupResult)) {
|
||||||
if (__FEATURE_SUSPENSE__) {
|
if (__SSR__) {
|
||||||
|
// return the promise so server-renderer can wait on it
|
||||||
|
return setupResult
|
||||||
|
} else if (__FEATURE_SUSPENSE__) {
|
||||||
// async setup returned Promise.
|
// async setup returned Promise.
|
||||||
// bail here and wait for re-entry.
|
// bail here and wait for re-entry.
|
||||||
instance.asyncDep = setupResult
|
instance.asyncDep = setupResult
|
||||||
@ -350,8 +354,6 @@ function setupStatefulComponent(
|
|||||||
} else {
|
} else {
|
||||||
finishComponentSetup(instance, parentSuspense)
|
finishComponentSetup(instance, parentSuspense)
|
||||||
}
|
}
|
||||||
|
|
||||||
return setupResult
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleSetupResult(
|
export function handleSetupResult(
|
||||||
@ -371,7 +373,7 @@ export function handleSetupResult(
|
|||||||
}
|
}
|
||||||
// setup returned bindings.
|
// setup returned bindings.
|
||||||
// assuming a render function compiled from template is present.
|
// assuming a render function compiled from template is present.
|
||||||
instance.renderContext = reactive(setupResult)
|
instance.renderContext = __SSR__ ? setupResult : reactive(setupResult)
|
||||||
} else if (__DEV__ && setupResult !== undefined) {
|
} else if (__DEV__ && setupResult !== undefined) {
|
||||||
warn(
|
warn(
|
||||||
`setup() should return an object. Received: ${
|
`setup() should return an object. Received: ${
|
||||||
@ -449,7 +451,7 @@ function finishComponentSetup(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (instance.renderContext === EMPTY_OBJ) {
|
if (instance.renderContext === EMPTY_OBJ) {
|
||||||
instance.renderContext = reactive({})
|
instance.renderContext = __SSR__ ? {} : reactive({})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user