types: improve type exports

This commit is contained in:
Evan You 2019-09-06 12:58:31 -04:00
parent d87bed0138
commit 360f3b4f37
25 changed files with 253 additions and 204 deletions

View File

@ -4,6 +4,8 @@
This package is inlined into Global & Browser ESM builds of user-facing renderers (e.g. `@vue/runtime-dom`), but also published as a package that can be used standalone. The standalone build should not be used alongside a pre-bundled build of a user-facing renderer, as they will have different internal storage for reactivity connections. A user-facing renderer should re-export all APIs from this package. This package is inlined into Global & Browser ESM builds of user-facing renderers (e.g. `@vue/runtime-dom`), but also published as a package that can be used standalone. The standalone build should not be used alongside a pre-bundled build of a user-facing renderer, as they will have different internal storage for reactivity connections. A user-facing renderer should re-export all APIs from this package.
For full exposed APIs, see `src/index.ts`. You can also run `yarn build reactivity --types` from repo root, which will generate an API report at `temp/reactivity.api.md`.
## Credits ## Credits
The implementation of this module is inspired by the following prior art in the JavaScript ecosystem: The implementation of this module is inspired by the following prior art in the JavaScript ecosystem:

View File

@ -9,23 +9,21 @@ export interface ReactiveEffect {
raw: Function raw: Function
deps: Array<Dep> deps: Array<Dep>
computed?: boolean computed?: boolean
scheduler?: Scheduler scheduler?: (run: Function) => void
onTrack?: Debugger onTrack?: (event: DebuggerEvent) => void
onTrigger?: Debugger onTrigger?: (event: DebuggerEvent) => void
onStop?: () => void onStop?: () => void
} }
export interface ReactiveEffectOptions { export interface ReactiveEffectOptions {
lazy?: boolean lazy?: boolean
computed?: boolean computed?: boolean
scheduler?: Scheduler scheduler?: (run: Function) => void
onTrack?: Debugger onTrack?: (event: DebuggerEvent) => void
onTrigger?: Debugger onTrigger?: (event: DebuggerEvent) => void
onStop?: () => void onStop?: () => void
} }
export type Scheduler = (run: () => any) => void
export interface DebuggerEvent { export interface DebuggerEvent {
effect: ReactiveEffect effect: ReactiveEffect
target: any target: any
@ -33,8 +31,6 @@ export interface DebuggerEvent {
key: string | symbol | undefined key: string | symbol | undefined
} }
export type Debugger = (event: DebuggerEvent) => void
export const activeReactiveEffectStack: ReactiveEffect[] = [] export const activeReactiveEffectStack: ReactiveEffect[] = []
export const ITERATE_KEY = Symbol('iterate') export const ITERATE_KEY = Symbol('iterate')

View File

@ -8,7 +8,12 @@ export {
markReadonly, markReadonly,
markNonReactive markNonReactive
} from './reactive' } from './reactive'
export { computed, ComputedRef, WritableComputedOptions } from './computed' export {
computed,
ComputedRef,
WritableComputedRef,
WritableComputedOptions
} from './computed'
export { export {
effect, effect,
stop, stop,

View File

@ -2,14 +2,25 @@
> This package is published only for typing and building custom renderers. It is NOT meant to be used in applications. > This package is published only for typing and building custom renderers. It is NOT meant to be used in applications.
``` ts For full exposed APIs, see `src/index.ts`. You can also run `yarn build runtime-core --types` from repo root, which will generate an API report at `temp/runtime-core.api.md`.
import { createRenderer, h } from '@vue/runtime-core'
const { render } = createRenderer({ ## Building a Custom Renderer
nodeOps,
patchData, ``` ts
teardownVNode import { createRenderer, createAppAPI } from '@vue/runtime-core'
// low-level render method
export const render = createRenderer({
pathcProp,
insert,
remove,
createElement,
// ...
}) })
render(h('div'), container) export const createApp = createAppAPI(render)
export * from '@vue/runtime-core'
``` ```
See `@vue/runtime-dom` for how a DOM-targeting renderer is implemented.

View File

@ -6,11 +6,10 @@ import {
nodeOps, nodeOps,
DirectiveHook, DirectiveHook,
VNode, VNode,
ComponentInstance,
DirectiveBinding, DirectiveBinding,
nextTick nextTick
} from '@vue/runtime-test' } from '@vue/runtime-test'
import { currentInstance } from '../src/component' import { currentInstance, ComponentInternalInstance } from '../src/component'
describe('directives', () => { describe('directives', () => {
it('should work', async () => { it('should work', async () => {
@ -99,7 +98,7 @@ describe('directives', () => {
expect(prevVNode).toBe(null) expect(prevVNode).toBe(null)
}) as DirectiveHook) }) as DirectiveHook)
let _instance: ComponentInstance | null = null let _instance: ComponentInternalInstance | null = null
let _vnode: VNode | null = null let _vnode: VNode | null = null
let _prevVnode: VNode | null = null let _prevVnode: VNode | null = null
const Comp = { const Comp = {

View File

@ -1,6 +1,6 @@
import { Component, Data, ComponentInstance } from './component' import { Component, Data, ComponentInternalInstance } from './component'
import { ComponentOptions } from './componentOptions' import { ComponentOptions } from './componentOptions'
import { ComponentRenderProxy } from './componentProxy' import { ComponentPublicInstance } from './componentPublicInstanceProxy'
import { Directive } from './directives' import { Directive } from './directives'
import { HostNode, RootRenderFunction } from './createRenderer' import { HostNode, RootRenderFunction } from './createRenderer'
import { InjectionKey } from './apiInject' import { InjectionKey } from './apiInject'
@ -20,7 +20,7 @@ export interface App {
rootComponent: Component, rootComponent: Component,
rootContainer: string | HostNode, rootContainer: string | HostNode,
rootProps?: Data rootProps?: Data
): ComponentRenderProxy ): ComponentPublicInstance
provide<T>(key: InjectionKey<T> | string, value: T): void provide<T>(key: InjectionKey<T> | string, value: T): void
} }
@ -29,12 +29,12 @@ export interface AppConfig {
performance: boolean performance: boolean
errorHandler?: ( errorHandler?: (
err: Error, err: Error,
instance: ComponentRenderProxy | null, instance: ComponentPublicInstance | null,
info: string info: string
) => void ) => void
warnHandler?: ( warnHandler?: (
msg: string, msg: string,
instance: ComponentRenderProxy | null, instance: ComponentPublicInstance | null,
trace: string trace: string
) => void ) => void
} }
@ -136,7 +136,7 @@ export function createAppAPI(render: RootRenderFunction): () => App {
vnode.appContext = context vnode.appContext = context
render(vnode, rootContainer) render(vnode, rootContainer)
isMounted = true isMounted = true
return (vnode.component as ComponentInstance).renderProxy return (vnode.component as ComponentInternalInstance).renderProxy
} else if (__DEV__) { } else if (__DEV__) {
warn( warn(
`App has already been mounted. Create a new app instance instead.` `App has already been mounted. Create a new app instance instead.`

View File

@ -7,7 +7,7 @@ import {
} from './componentOptions' } from './componentOptions'
import { SetupContext } from './component' import { SetupContext } from './component'
import { VNodeChild } from './vnode' import { VNodeChild } from './vnode'
import { ComponentRenderProxy } from './componentProxy' import { ComponentPublicInstance } from './componentPublicInstanceProxy'
import { ExtractPropTypes } from './componentProps' import { ExtractPropTypes } from './componentProps'
import { isFunction } from '@vue/shared' import { isFunction } from '@vue/shared'
@ -29,7 +29,7 @@ export function createComponent<
>( >(
options: ComponentOptionsWithoutProps<Props, RawBindings, D, C, M> options: ComponentOptionsWithoutProps<Props, RawBindings, D, C, M>
): { ): {
new (): ComponentRenderProxy<Props, RawBindings, D, C, M> new (): ComponentPublicInstance<Props, RawBindings, D, C, M>
} }
// overload 3: object format with array props declaration // overload 3: object format with array props declaration
@ -44,7 +44,7 @@ export function createComponent<
>( >(
options: ComponentOptionsWithArrayProps<PropNames, RawBindings, D, C, M> options: ComponentOptionsWithArrayProps<PropNames, RawBindings, D, C, M>
): { ): {
new (): ComponentRenderProxy< new (): ComponentPublicInstance<
{ [key in PropNames]?: unknown }, { [key in PropNames]?: unknown },
RawBindings, RawBindings,
D, D,
@ -65,7 +65,7 @@ export function createComponent<
options: ComponentOptionsWithProps<PropsOptions, RawBindings, D, C, M> options: ComponentOptionsWithProps<PropsOptions, RawBindings, D, C, M>
): { ): {
// for Vetur and TSX support // for Vetur and TSX support
new (): ComponentRenderProxy< new (): ComponentPublicInstance<
ExtractPropTypes<PropsOptions>, ExtractPropTypes<PropsOptions>,
RawBindings, RawBindings,
D, D,

View File

@ -1,10 +1,10 @@
import { import {
ComponentInstance, ComponentInternalInstance,
LifecycleHooks, LifecycleHooks,
currentInstance, currentInstance,
setCurrentInstance setCurrentInstance
} from './component' } from './component'
import { ComponentRenderProxy } from './componentProxy' import { ComponentPublicInstance } from './componentPublicInstanceProxy'
import { callWithAsyncErrorHandling, ErrorTypeStrings } from './errorHandling' import { callWithAsyncErrorHandling, ErrorTypeStrings } from './errorHandling'
import { warn } from './warning' import { warn } from './warning'
import { capitalize } from '@vue/shared' import { capitalize } from '@vue/shared'
@ -13,7 +13,7 @@ import { pauseTracking, resumeTracking } from '@vue/reactivity'
function injectHook( function injectHook(
type: LifecycleHooks, type: LifecycleHooks,
hook: Function, hook: Function,
target: ComponentInstance | null target: ComponentInternalInstance | null
) { ) {
if (target) { if (target) {
;(target[type] || (target[type] = [])).push((...args: any[]) => { ;(target[type] || (target[type] = [])).push((...args: any[]) => {
@ -43,56 +43,56 @@ function injectHook(
export function onBeforeMount( export function onBeforeMount(
hook: Function, hook: Function,
target: ComponentInstance | null = currentInstance target: ComponentInternalInstance | null = currentInstance
) { ) {
injectHook(LifecycleHooks.BEFORE_MOUNT, hook, target) injectHook(LifecycleHooks.BEFORE_MOUNT, hook, target)
} }
export function onMounted( export function onMounted(
hook: Function, hook: Function,
target: ComponentInstance | null = currentInstance target: ComponentInternalInstance | null = currentInstance
) { ) {
injectHook(LifecycleHooks.MOUNTED, hook, target) injectHook(LifecycleHooks.MOUNTED, hook, target)
} }
export function onBeforeUpdate( export function onBeforeUpdate(
hook: Function, hook: Function,
target: ComponentInstance | null = currentInstance target: ComponentInternalInstance | null = currentInstance
) { ) {
injectHook(LifecycleHooks.BEFORE_UPDATE, hook, target) injectHook(LifecycleHooks.BEFORE_UPDATE, hook, target)
} }
export function onUpdated( export function onUpdated(
hook: Function, hook: Function,
target: ComponentInstance | null = currentInstance target: ComponentInternalInstance | null = currentInstance
) { ) {
injectHook(LifecycleHooks.UPDATED, hook, target) injectHook(LifecycleHooks.UPDATED, hook, target)
} }
export function onBeforeUnmount( export function onBeforeUnmount(
hook: Function, hook: Function,
target: ComponentInstance | null = currentInstance target: ComponentInternalInstance | null = currentInstance
) { ) {
injectHook(LifecycleHooks.BEFORE_UNMOUNT, hook, target) injectHook(LifecycleHooks.BEFORE_UNMOUNT, hook, target)
} }
export function onUnmounted( export function onUnmounted(
hook: Function, hook: Function,
target: ComponentInstance | null = currentInstance target: ComponentInternalInstance | null = currentInstance
) { ) {
injectHook(LifecycleHooks.UNMOUNTED, hook, target) injectHook(LifecycleHooks.UNMOUNTED, hook, target)
} }
export function onRenderTriggered( export function onRenderTriggered(
hook: Function, hook: Function,
target: ComponentInstance | null = currentInstance target: ComponentInternalInstance | null = currentInstance
) { ) {
injectHook(LifecycleHooks.RENDER_TRIGGERED, hook, target) injectHook(LifecycleHooks.RENDER_TRIGGERED, hook, target)
} }
export function onRenderTracked( export function onRenderTracked(
hook: Function, hook: Function,
target: ComponentInstance | null = currentInstance target: ComponentInternalInstance | null = currentInstance
) { ) {
injectHook(LifecycleHooks.RENDER_TRACKED, hook, target) injectHook(LifecycleHooks.RENDER_TRACKED, hook, target)
} }
@ -100,10 +100,10 @@ export function onRenderTracked(
export function onErrorCaptured( export function onErrorCaptured(
hook: ( hook: (
err: Error, err: Error,
instance: ComponentRenderProxy | null, instance: ComponentPublicInstance | null,
info: string info: string
) => boolean | void, ) => boolean | void,
target: ComponentInstance | null = currentInstance target: ComponentInternalInstance | null = currentInstance
) { ) {
injectHook(LifecycleHooks.ERROR_CAPTURED, hook, target) injectHook(LifecycleHooks.ERROR_CAPTURED, hook, target)
} }

View File

@ -8,9 +8,9 @@ import {
import { queueJob, queuePostFlushCb } from './scheduler' import { queueJob, queuePostFlushCb } from './scheduler'
import { EMPTY_OBJ, isObject, isArray, isFunction, isString } from '@vue/shared' import { EMPTY_OBJ, isObject, isArray, isFunction, isString } from '@vue/shared'
import { recordEffect } from './apiReactivity' import { recordEffect } from './apiReactivity'
import { currentInstance, ComponentInstance } from './component' import { currentInstance, ComponentInternalInstance } from './component'
import { import {
ErrorTypes, ErrorCodes,
callWithErrorHandling, callWithErrorHandling,
callWithAsyncErrorHandling callWithAsyncErrorHandling
} from './errorHandling' } from './errorHandling'
@ -93,14 +93,14 @@ function doWatch(
s => s =>
isRef(s) isRef(s)
? s.value ? s.value
: callWithErrorHandling(s, instance, ErrorTypes.WATCH_GETTER) : callWithErrorHandling(s, instance, ErrorCodes.WATCH_GETTER)
) )
} else if (isRef(source)) { } else if (isRef(source)) {
getter = () => source.value getter = () => source.value
} else if (cb) { } else if (cb) {
// getter with cb // getter with cb
getter = () => getter = () =>
callWithErrorHandling(source, instance, ErrorTypes.WATCH_GETTER) callWithErrorHandling(source, instance, ErrorCodes.WATCH_GETTER)
} else { } else {
// no cb -> simple effect // no cb -> simple effect
getter = () => { getter = () => {
@ -110,7 +110,7 @@ function doWatch(
return callWithErrorHandling( return callWithErrorHandling(
source, source,
instance, instance,
ErrorTypes.WATCH_CALLBACK, ErrorCodes.WATCH_CALLBACK,
[registerCleanup] [registerCleanup]
) )
} }
@ -125,7 +125,7 @@ function doWatch(
const registerCleanup: CleanupRegistrator = (fn: () => void) => { const registerCleanup: CleanupRegistrator = (fn: () => void) => {
// TODO wrap the cleanup fn for error handling // TODO wrap the cleanup fn for error handling
cleanup = runner.onStop = () => { cleanup = runner.onStop = () => {
callWithErrorHandling(fn, instance, ErrorTypes.WATCH_CLEANUP) callWithErrorHandling(fn, instance, ErrorCodes.WATCH_CLEANUP)
} }
} }
@ -138,7 +138,7 @@ function doWatch(
if (cleanup) { if (cleanup) {
cleanup() cleanup()
} }
callWithAsyncErrorHandling(cb, instance, ErrorTypes.WATCH_CALLBACK, [ callWithAsyncErrorHandling(cb, instance, ErrorCodes.WATCH_CALLBACK, [
newValue, newValue,
oldValue, oldValue,
registerCleanup registerCleanup
@ -190,7 +190,7 @@ function doWatch(
// this.$watch // this.$watch
export function instanceWatch( export function instanceWatch(
this: ComponentInstance, this: ComponentInternalInstance,
source: string | Function, source: string | Function,
cb: Function, cb: Function,
options?: WatchOptions options?: WatchOptions

View File

@ -1,11 +1,14 @@
import { VNode, VNodeChild } from './vnode' import { VNode, VNodeChild } from './vnode'
import { ReactiveEffect, reactive, readonly } from '@vue/reactivity' import { ReactiveEffect, reactive, readonly } from '@vue/reactivity'
import { RenderProxyHandlers, ComponentRenderProxy } from './componentProxy' import {
PublicInstanceProxyHandlers,
ComponentPublicInstance
} from './componentPublicInstanceProxy'
import { ComponentPropsOptions } from './componentProps' import { ComponentPropsOptions } from './componentProps'
import { Slots } from './componentSlots' import { Slots } from './componentSlots'
import { warn } from './warning' import { warn } from './warning'
import { import {
ErrorTypes, ErrorCodes,
callWithErrorHandling, callWithErrorHandling,
callWithAsyncErrorHandling callWithAsyncErrorHandling
} from './errorHandling' } from './errorHandling'
@ -59,11 +62,11 @@ export interface SetupContext {
type RenderFunction = () => VNodeChild type RenderFunction = () => VNodeChild
export interface ComponentInstance { export interface ComponentInternalInstance {
type: FunctionalComponent | ComponentOptions type: FunctionalComponent | ComponentOptions
parent: ComponentInstance | null parent: ComponentInternalInstance | null
appContext: AppContext appContext: AppContext
root: ComponentInstance root: ComponentInternalInstance
vnode: VNode vnode: VNode
next: VNode | null next: VNode | null
subTree: VNode subTree: VNode
@ -81,7 +84,7 @@ export interface ComponentInstance {
props: Data props: Data
attrs: Data attrs: Data
slots: Slots slots: Slots
renderProxy: ComponentRenderProxy | null renderProxy: ComponentPublicInstance | null
propsProxy: Data | null propsProxy: Data | null
setupContext: SetupContext | null setupContext: SetupContext | null
refs: Data refs: Data
@ -110,8 +113,8 @@ const emptyAppContext = createAppContext()
export function createComponentInstance( export function createComponentInstance(
vnode: VNode, vnode: VNode,
parent: ComponentInstance | null parent: ComponentInternalInstance | null
): ComponentInstance { ): ComponentInternalInstance {
// inherit parent app context - or - if root, adopt from root vnode // inherit parent app context - or - if root, adopt from root vnode
const appContext = const appContext =
(parent ? parent.appContext : vnode.appContext) || emptyAppContext (parent ? parent.appContext : vnode.appContext) || emptyAppContext
@ -171,7 +174,7 @@ export function createComponentInstance(
callWithAsyncErrorHandling( callWithAsyncErrorHandling(
handler[i], handler[i],
instance, instance,
ErrorTypes.COMPONENT_EVENT_HANDLER, ErrorCodes.COMPONENT_EVENT_HANDLER,
args args
) )
} }
@ -179,7 +182,7 @@ export function createComponentInstance(
callWithAsyncErrorHandling( callWithAsyncErrorHandling(
handler, handler,
instance, instance,
ErrorTypes.COMPONENT_EVENT_HANDLER, ErrorCodes.COMPONENT_EVENT_HANDLER,
args args
) )
} }
@ -191,20 +194,22 @@ export function createComponentInstance(
return instance return instance
} }
export let currentInstance: ComponentInstance | null = null export let currentInstance: ComponentInternalInstance | null = null
export const getCurrentInstance: () => ComponentInstance | null = () => export const getCurrentInstance: () => ComponentInternalInstance | null = () =>
currentInstance currentInstance
export const setCurrentInstance = (instance: ComponentInstance | null) => { export const setCurrentInstance = (
instance: ComponentInternalInstance | null
) => {
currentInstance = instance currentInstance = instance
} }
export function setupStatefulComponent(instance: ComponentInstance) { export function setupStatefulComponent(instance: ComponentInternalInstance) {
currentInstance = instance currentInstance = instance
const Component = instance.type as ComponentOptions const Component = instance.type as ComponentOptions
// 1. create render proxy // 1. create render proxy
instance.renderProxy = new Proxy(instance, RenderProxyHandlers) as any instance.renderProxy = new Proxy(instance, PublicInstanceProxyHandlers) as any
// 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
@ -217,7 +222,7 @@ export function setupStatefulComponent(instance: ComponentInstance) {
const setupResult = callWithErrorHandling( const setupResult = callWithErrorHandling(
setup, setup,
instance, instance,
ErrorTypes.SETUP_FUNCTION, ErrorCodes.SETUP_FUNCTION,
[propsProxy, setupContext] [propsProxy, setupContext]
) )
@ -290,7 +295,7 @@ const SetupProxyHandlers: { [key: string]: ProxyHandler<any> } = {}
} }
}) })
function createSetupContext(instance: ComponentInstance): SetupContext { function createSetupContext(instance: ComponentInternalInstance): SetupContext {
const context = { const context = {
// attrs, slots & refs are non-reactive, but they need to always expose // attrs, slots & refs are non-reactive, but they need to always expose
// the latest values (instance.xxx may get replaced during updates) so we // the latest values (instance.xxx may get replaced during updates) so we

View File

@ -1,5 +1,5 @@
import { import {
ComponentInstance, ComponentInternalInstance,
Data, Data,
currentInstance, currentInstance,
Component, Component,
@ -33,7 +33,7 @@ import { warn } from './warning'
import { ComponentPropsOptions, ExtractPropTypes } from './componentProps' import { ComponentPropsOptions, ExtractPropTypes } from './componentProps'
import { Directive } from './directives' import { Directive } from './directives'
import { VNodeChild } from './vnode' import { VNodeChild } from './vnode'
import { ComponentRenderProxy } from './componentProxy' import { ComponentPublicInstance } from './componentPublicInstanceProxy'
import { currentRenderingInstance } from './componentRenderUtils' import { currentRenderingInstance } from './componentRenderUtils'
interface ComponentOptionsBase< interface ComponentOptionsBase<
@ -68,7 +68,7 @@ export type ComponentOptionsWithoutProps<
M extends MethodOptions = {} M extends MethodOptions = {}
> = ComponentOptionsBase<Props, RawBindings, D, C, M> & { > = ComponentOptionsBase<Props, RawBindings, D, C, M> & {
props?: undefined props?: undefined
} & ThisType<ComponentRenderProxy<Props, RawBindings, D, C, M>> } & ThisType<ComponentPublicInstance<Props, RawBindings, D, C, M>>
export type ComponentOptionsWithArrayProps< export type ComponentOptionsWithArrayProps<
PropNames extends string = string, PropNames extends string = string,
@ -79,7 +79,7 @@ export type ComponentOptionsWithArrayProps<
Props = { [key in PropNames]?: unknown } Props = { [key in PropNames]?: unknown }
> = ComponentOptionsBase<Props, RawBindings, D, C, M> & { > = ComponentOptionsBase<Props, RawBindings, D, C, M> & {
props: PropNames[] props: PropNames[]
} & ThisType<ComponentRenderProxy<Props, RawBindings, D, C, M>> } & ThisType<ComponentPublicInstance<Props, RawBindings, D, C, M>>
export type ComponentOptionsWithProps< export type ComponentOptionsWithProps<
PropsOptions = ComponentPropsOptions, PropsOptions = ComponentPropsOptions,
@ -90,7 +90,7 @@ export type ComponentOptionsWithProps<
Props = ExtractPropTypes<PropsOptions> Props = ExtractPropTypes<PropsOptions>
> = ComponentOptionsBase<Props, RawBindings, D, C, M> & { > = ComponentOptionsBase<Props, RawBindings, D, C, M> & {
props: PropsOptions props: PropsOptions
} & ThisType<ComponentRenderProxy<Props, RawBindings, D, C, M>> } & ThisType<ComponentPublicInstance<Props, RawBindings, D, C, M>>
export type ComponentOptions = export type ComponentOptions =
| ComponentOptionsWithoutProps | ComponentOptionsWithoutProps
@ -151,7 +151,7 @@ export interface LegacyOptions<
// Limitation: we cannot expose RawBindings on the `this` context for data // Limitation: we cannot expose RawBindings on the `this` context for data
// since that leads to some sort of circular inference and breaks ThisType // since that leads to some sort of circular inference and breaks ThisType
// for the entire component. // for the entire component.
data?: D | ((this: ComponentRenderProxy<Props>) => D) data?: D | ((this: ComponentPublicInstance<Props>) => D)
computed?: C computed?: C
methods?: M methods?: M
// TODO watch array // TODO watch array
@ -180,7 +180,7 @@ export interface LegacyOptions<
} }
export function applyOptions( export function applyOptions(
instance: ComponentInstance, instance: ComponentInternalInstance,
options: ComponentOptions, options: ComponentOptions,
asMixin: boolean = false asMixin: boolean = false
) { ) {
@ -379,7 +379,10 @@ function callHookFromMixins(
} }
} }
function applyMixins(instance: ComponentInstance, mixins: ComponentOptions[]) { function applyMixins(
instance: ComponentInternalInstance,
mixins: ComponentOptions[]
) {
for (let i = 0; i < mixins.length; i++) { for (let i = 0; i < mixins.length; i++) {
applyOptions(instance, mixins[i], true) applyOptions(instance, mixins[i], true)
} }

View File

@ -12,14 +12,14 @@ import {
hasOwn hasOwn
} from '@vue/shared' } from '@vue/shared'
import { warn } from './warning' import { warn } from './warning'
import { Data, ComponentInstance } from './component' import { Data, ComponentInternalInstance } from './component'
import { PatchFlags } from './patchFlags' import { PatchFlags } from './patchFlags'
export type ComponentPropsOptions<P = Data> = { export type ComponentPropsOptions<P = Data> = {
[K in keyof P]: Prop<P[K]> | null [K in keyof P]: Prop<P[K]> | null
} }
type Prop<T> = PropOptions<T> | PropType<T> export type Prop<T> = PropOptions<T> | PropType<T>
interface PropOptions<T = any> { interface PropOptions<T = any> {
type?: PropType<T> | true | null type?: PropType<T> | true | null
@ -90,7 +90,7 @@ type NormalizedPropsOptions = Record<string, NormalizedProp>
// - else: everything goes in `props`. // - else: everything goes in `props`.
export function resolveProps( export function resolveProps(
instance: ComponentInstance, instance: ComponentInternalInstance,
rawProps: any, rawProps: any,
_options: ComponentPropsOptions | void _options: ComponentPropsOptions | void
) { ) {

View File

@ -1,4 +1,4 @@
import { ComponentInstance, Data } from './component' import { ComponentInternalInstance, Data } from './component'
import { nextTick } from './scheduler' import { nextTick } from './scheduler'
import { instanceWatch } from './apiWatch' import { instanceWatch } from './apiWatch'
import { EMPTY_OBJ, hasOwn } from '@vue/shared' import { EMPTY_OBJ, hasOwn } from '@vue/shared'
@ -7,7 +7,7 @@ import { UnwrapRef } from '@vue/reactivity'
// public properties exposed on the proxy, which is used as the render context // public properties exposed on the proxy, which is used as the render context
// in templates (as `this` in the render option) // in templates (as `this` in the render option)
export type ComponentRenderProxy< export type ComponentPublicInstance<
P = {}, P = {},
B = {}, B = {},
D = {}, D = {},
@ -20,8 +20,8 @@ export type ComponentRenderProxy<
$attrs: Data $attrs: Data
$refs: Data $refs: Data
$slots: Data $slots: Data
$root: ComponentInstance | null $root: ComponentInternalInstance | null
$parent: ComponentInstance | null $parent: ComponentInternalInstance | null
$emit: (event: string, ...args: unknown[]) => void $emit: (event: string, ...args: unknown[]) => void
} & P & } & P &
UnwrapRef<B> & UnwrapRef<B> &
@ -29,8 +29,8 @@ export type ComponentRenderProxy<
ExtracComputedReturns<C> & ExtracComputedReturns<C> &
M M
export const RenderProxyHandlers = { export const PublicInstanceProxyHandlers = {
get(target: ComponentInstance, key: string) { get(target: ComponentInternalInstance, key: string) {
const { renderContext, data, props, propsProxy } = target const { renderContext, data, props, propsProxy } = target
if (data !== EMPTY_OBJ && hasOwn(data, key)) { if (data !== EMPTY_OBJ && hasOwn(data, key)) {
return data[key] return data[key]
@ -77,7 +77,7 @@ export const RenderProxyHandlers = {
} }
} }
}, },
set(target: ComponentInstance, key: string, value: any): boolean { set(target: ComponentInternalInstance, key: string, value: any): boolean {
const { data, renderContext } = target const { data, renderContext } = target
if (data !== EMPTY_OBJ && hasOwn(data, key)) { if (data !== EMPTY_OBJ && hasOwn(data, key)) {
data[key] = value data[key] = value

View File

@ -1,14 +1,20 @@
import { ComponentInstance, FunctionalComponent, Data } from './component' import {
ComponentInternalInstance,
FunctionalComponent,
Data
} from './component'
import { VNode, normalizeVNode, createVNode, Empty } from './vnode' import { VNode, normalizeVNode, createVNode, Empty } from './vnode'
import { ShapeFlags } from './shapeFlags' import { ShapeFlags } from './shapeFlags'
import { handleError, ErrorTypes } from './errorHandling' import { handleError, ErrorCodes } from './errorHandling'
import { PatchFlags } from './patchFlags' import { PatchFlags } from './patchFlags'
// mark the current rendering instance for asset resolution (e.g. // mark the current rendering instance for asset resolution (e.g.
// resolveComponent, resolveDirective) during render // resolveComponent, resolveDirective) during render
export let currentRenderingInstance: ComponentInstance | null = null export let currentRenderingInstance: ComponentInternalInstance | null = null
export function renderComponentRoot(instance: ComponentInstance): VNode { export function renderComponentRoot(
instance: ComponentInternalInstance
): VNode {
const { const {
type: Component, type: Component,
vnode, vnode,
@ -38,7 +44,7 @@ export function renderComponentRoot(instance: ComponentInstance): VNode {
) )
} }
} catch (err) { } catch (err) {
handleError(err, instance, ErrorTypes.RENDER_FUNCTION) handleError(err, instance, ErrorCodes.RENDER_FUNCTION)
result = createVNode(Empty) result = createVNode(Empty)
} }
currentRenderingInstance = null currentRenderingInstance = null

View File

@ -1,4 +1,4 @@
import { ComponentInstance, currentInstance } from './component' import { ComponentInternalInstance, currentInstance } from './component'
import { VNode, NormalizedChildren, normalizeVNode, VNodeChild } from './vnode' import { VNode, NormalizedChildren, normalizeVNode, VNodeChild } from './vnode'
import { isArray, isFunction } from '@vue/shared' import { isArray, isFunction } from '@vue/shared'
import { ShapeFlags } from './shapeFlags' import { ShapeFlags } from './shapeFlags'
@ -31,7 +31,7 @@ const normalizeSlot = (key: string, rawSlot: Function): Slot => (
} }
export function resolveSlots( export function resolveSlots(
instance: ComponentInstance, instance: ComponentInternalInstance,
children: NormalizedChildren children: NormalizedChildren
) { ) {
let slots: Slots | void let slots: Slots | void

View File

@ -8,7 +8,7 @@ import {
VNodeChildren VNodeChildren
} from './vnode' } from './vnode'
import { import {
ComponentInstance, ComponentInternalInstance,
createComponentInstance, createComponentInstance,
setupStatefulComponent setupStatefulComponent
} from './component' } from './component'
@ -44,7 +44,7 @@ const prodEffectOptions = {
} }
function createDevEffectOptions( function createDevEffectOptions(
instance: ComponentInstance instance: ComponentInternalInstance
): ReactiveEffectOptions { ): ReactiveEffectOptions {
return { return {
scheduler: queueJob, scheduler: queueJob,
@ -77,10 +77,10 @@ export interface RendererOptions {
oldValue: any, oldValue: any,
isSVG: boolean, isSVG: boolean,
prevChildren?: VNode[], prevChildren?: VNode[],
parentComponent?: ComponentInstance | null, parentComponent?: ComponentInternalInstance | null,
unmountChildren?: ( unmountChildren?: (
children: VNode[], children: VNode[],
parentComponent: ComponentInstance | null parentComponent: ComponentInternalInstance | null
) => void ) => void
): void ): void
insert(el: HostNode, parent: HostNode, anchor?: HostNode): void insert(el: HostNode, parent: HostNode, anchor?: HostNode): void
@ -120,7 +120,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
n2: VNode, n2: VNode,
container: HostNode, container: HostNode,
anchor: HostNode = null, anchor: HostNode = null,
parentComponent: ComponentInstance | null = null, parentComponent: ComponentInternalInstance | null = null,
isSVG: boolean = false, isSVG: boolean = false,
optimized: boolean = false optimized: boolean = false
) { ) {
@ -226,7 +226,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
n2: VNode, n2: VNode,
container: HostNode, container: HostNode,
anchor: HostNode, anchor: HostNode,
parentComponent: ComponentInstance | null, parentComponent: ComponentInternalInstance | null,
isSVG: boolean, isSVG: boolean,
optimized: boolean optimized: boolean
) { ) {
@ -244,7 +244,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
vnode: VNode, vnode: VNode,
container: HostNode, container: HostNode,
anchor: HostNode, anchor: HostNode,
parentComponent: ComponentInstance | null, parentComponent: ComponentInternalInstance | null,
isSVG: boolean isSVG: boolean
) { ) {
const tag = vnode.type as string const tag = vnode.type as string
@ -283,7 +283,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
children: VNodeChildren, children: VNodeChildren,
container: HostNode, container: HostNode,
anchor: HostNode, anchor: HostNode,
parentComponent: ComponentInstance | null, parentComponent: ComponentInternalInstance | null,
isSVG: boolean, isSVG: boolean,
start: number = 0 start: number = 0
) { ) {
@ -296,7 +296,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
function patchElement( function patchElement(
n1: VNode, n1: VNode,
n2: VNode, n2: VNode,
parentComponent: ComponentInstance | null, parentComponent: ComponentInternalInstance | null,
isSVG: boolean, isSVG: boolean,
optimized: boolean optimized: boolean
) { ) {
@ -407,7 +407,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
vnode: VNode, vnode: VNode,
oldProps: any, oldProps: any,
newProps: any, newProps: any,
parentComponent: ComponentInstance | null, parentComponent: ComponentInternalInstance | null,
isSVG: boolean isSVG: boolean
) { ) {
if (oldProps !== newProps) { if (oldProps !== newProps) {
@ -453,7 +453,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
n2: VNode, n2: VNode,
container: HostNode, container: HostNode,
anchor: HostNode, anchor: HostNode,
parentComponent: ComponentInstance | null, parentComponent: ComponentInternalInstance | null,
isSVG: boolean, isSVG: boolean,
optimized: boolean optimized: boolean
) { ) {
@ -490,7 +490,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
n2: VNode, n2: VNode,
container: HostNode, container: HostNode,
anchor: HostNode, anchor: HostNode,
parentComponent: ComponentInstance | null, parentComponent: ComponentInternalInstance | null,
isSVG: boolean, isSVG: boolean,
optimized: boolean optimized: boolean
) { ) {
@ -552,14 +552,15 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
n2: VNode, n2: VNode,
container: HostNode, container: HostNode,
anchor: HostNode, anchor: HostNode,
parentComponent: ComponentInstance | null, parentComponent: ComponentInternalInstance | null,
isSVG: boolean, isSVG: boolean,
optimized: boolean optimized: boolean
) { ) {
if (n1 == null) { if (n1 == null) {
mountComponent(n2, container, anchor, parentComponent, isSVG) mountComponent(n2, container, anchor, parentComponent, isSVG)
} else { } else {
const instance = (n2.component = n1.component) as ComponentInstance const instance = (n2.component =
n1.component) as ComponentInternalInstance
if (shouldUpdateComponent(n1, n2, optimized)) { if (shouldUpdateComponent(n1, n2, optimized)) {
instance.next = n2 instance.next = n2
instance.update() instance.update()
@ -573,7 +574,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
n2.ref, n2.ref,
n1 && n1.ref, n1 && n1.ref,
parentComponent, parentComponent,
(n2.component as ComponentInstance).renderProxy (n2.component as ComponentInternalInstance).renderProxy
) )
} }
} }
@ -582,10 +583,10 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
initialVNode: VNode, initialVNode: VNode,
container: HostNode, container: HostNode,
anchor: HostNode, anchor: HostNode,
parentComponent: ComponentInstance | null, parentComponent: ComponentInternalInstance | null,
isSVG: boolean isSVG: boolean
) { ) {
const instance: ComponentInstance = (initialVNode.component = createComponentInstance( const instance: ComponentInternalInstance = (initialVNode.component = createComponentInstance(
initialVNode, initialVNode,
parentComponent parentComponent
)) ))
@ -692,7 +693,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
n2: VNode, n2: VNode,
container: HostNode, container: HostNode,
anchor: HostNode, anchor: HostNode,
parentComponent: ComponentInstance | null, parentComponent: ComponentInternalInstance | null,
isSVG: boolean, isSVG: boolean,
optimized: boolean = false optimized: boolean = false
) { ) {
@ -776,7 +777,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
c2: VNodeChildren, c2: VNodeChildren,
container: HostNode, container: HostNode,
anchor: HostNode, anchor: HostNode,
parentComponent: ComponentInstance | null, parentComponent: ComponentInternalInstance | null,
isSVG: boolean, isSVG: boolean,
optimized: boolean optimized: boolean
) { ) {
@ -813,7 +814,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
c2: VNodeChildren, c2: VNodeChildren,
container: HostNode, container: HostNode,
parentAnchor: HostNode, parentAnchor: HostNode,
parentComponent: ComponentInstance | null, parentComponent: ComponentInternalInstance | null,
isSVG: boolean, isSVG: boolean,
optimized: boolean optimized: boolean
) { ) {
@ -1035,7 +1036,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
function unmount( function unmount(
vnode: VNode, vnode: VNode,
parentComponent: ComponentInstance | null, parentComponent: ComponentInternalInstance | null,
doRemove?: boolean doRemove?: boolean
) { ) {
const { const {
@ -1086,7 +1087,10 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
} }
} }
function unmountComponent(instance: ComponentInstance, doRemove?: boolean) { function unmountComponent(
instance: ComponentInternalInstance,
doRemove?: boolean
) {
const { bum, effects, update, subTree, um } = instance const { bum, effects, update, subTree, um } = instance
// beforeUnmount hook // beforeUnmount hook
if (bum !== null) { if (bum !== null) {
@ -1107,7 +1111,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
function unmountChildren( function unmountChildren(
children: VNode[], children: VNode[],
parentComponent: ComponentInstance | null, parentComponent: ComponentInternalInstance | null,
doRemove?: boolean, doRemove?: boolean,
start: number = 0 start: number = 0
) { ) {
@ -1125,8 +1129,8 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
function setRef( function setRef(
ref: string | Function | Ref<any>, ref: string | Function | Ref<any>,
oldRef: string | Function | Ref<any> | null, oldRef: string | Function | Ref<any> | null,
parent: ComponentInstance, parent: ComponentInternalInstance,
value: HostNode | ComponentInstance | null value: HostNode | ComponentInternalInstance | null
) { ) {
const refs = parent.refs === EMPTY_OBJ ? (parent.refs = {}) : parent.refs const refs = parent.refs === EMPTY_OBJ ? (parent.refs = {}) : parent.refs
const renderContext = toRaw(parent.renderContext) const renderContext = toRaw(parent.renderContext)

View File

@ -14,14 +14,14 @@ return applyDirectives(h(comp), [
import { VNode, cloneVNode } from './vnode' import { VNode, cloneVNode } from './vnode'
import { extend, isArray, isFunction } from '@vue/shared' import { extend, isArray, isFunction } from '@vue/shared'
import { warn } from './warning' import { warn } from './warning'
import { ComponentInstance } from './component' import { ComponentInternalInstance } from './component'
import { currentRenderingInstance } from './componentRenderUtils' import { currentRenderingInstance } from './componentRenderUtils'
import { callWithAsyncErrorHandling, ErrorTypes } from './errorHandling' import { callWithAsyncErrorHandling, ErrorCodes } from './errorHandling'
import { HostNode } from './createRenderer' import { HostNode } from './createRenderer'
import { ComponentRenderProxy } from './componentProxy' import { ComponentPublicInstance } from './componentPublicInstanceProxy'
export interface DirectiveBinding { export interface DirectiveBinding {
instance: ComponentRenderProxy | null instance: ComponentPublicInstance | null
value?: any value?: any
oldValue?: any oldValue?: any
arg?: string arg?: string
@ -50,7 +50,7 @@ const valueCache = new WeakMap<Directive, WeakMap<any, any>>()
function applyDirective( function applyDirective(
props: Record<any, any>, props: Record<any, any>,
instance: ComponentInstance, instance: ComponentInternalInstance,
directive: Directive, directive: Directive,
value?: any, value?: any,
arg?: string, arg?: string,
@ -92,7 +92,7 @@ function applyDirective(
} }
// Directive, value, argument, modifiers // Directive, value, argument, modifiers
type DirectiveArguments = Array< export type DirectiveArguments = Array<
| [Directive] | [Directive]
| [Directive, any] | [Directive, any]
| [Directive, any, string] | [Directive, any, string]
@ -115,7 +115,7 @@ export function applyDirectives(vnode: VNode, directives: DirectiveArguments) {
export function invokeDirectiveHook( export function invokeDirectiveHook(
hook: Function | Function[], hook: Function | Function[],
instance: ComponentInstance | null, instance: ComponentInternalInstance | null,
vnode: VNode, vnode: VNode,
prevVNode: VNode | null = null prevVNode: VNode | null = null
) { ) {
@ -125,11 +125,11 @@ export function invokeDirectiveHook(
callWithAsyncErrorHandling( callWithAsyncErrorHandling(
hook[i], hook[i],
instance, instance,
ErrorTypes.DIRECTIVE_HOOK, ErrorCodes.DIRECTIVE_HOOK,
args args
) )
} }
} else if (isFunction(hook)) { } else if (isFunction(hook)) {
callWithAsyncErrorHandling(hook, instance, ErrorTypes.DIRECTIVE_HOOK, args) callWithAsyncErrorHandling(hook, instance, ErrorCodes.DIRECTIVE_HOOK, args)
} }
} }

View File

@ -1,10 +1,10 @@
import { VNode } from './vnode' import { VNode } from './vnode'
import { ComponentInstance, LifecycleHooks } from './component' import { ComponentInternalInstance, LifecycleHooks } from './component'
import { warn, pushWarningContext, popWarningContext } from './warning' import { warn, pushWarningContext, popWarningContext } from './warning'
// contexts where user provided function may be executed, in addition to // contexts where user provided function may be executed, in addition to
// lifecycle hooks. // lifecycle hooks.
export const enum ErrorTypes { export const enum ErrorCodes {
SETUP_FUNCTION = 1, SETUP_FUNCTION = 1,
RENDER_FUNCTION, RENDER_FUNCTION,
WATCH_GETTER, WATCH_GETTER,
@ -32,27 +32,27 @@ export const ErrorTypeStrings: Record<number | string, string> = {
[LifecycleHooks.ERROR_CAPTURED]: 'errorCaptured hook', [LifecycleHooks.ERROR_CAPTURED]: 'errorCaptured hook',
[LifecycleHooks.RENDER_TRACKED]: 'renderTracked hook', [LifecycleHooks.RENDER_TRACKED]: 'renderTracked hook',
[LifecycleHooks.RENDER_TRIGGERED]: 'renderTriggered hook', [LifecycleHooks.RENDER_TRIGGERED]: 'renderTriggered hook',
[ErrorTypes.SETUP_FUNCTION]: 'setup function', [ErrorCodes.SETUP_FUNCTION]: 'setup function',
[ErrorTypes.RENDER_FUNCTION]: 'render function', [ErrorCodes.RENDER_FUNCTION]: 'render function',
[ErrorTypes.WATCH_GETTER]: 'watcher getter', [ErrorCodes.WATCH_GETTER]: 'watcher getter',
[ErrorTypes.WATCH_CALLBACK]: 'watcher callback', [ErrorCodes.WATCH_CALLBACK]: 'watcher callback',
[ErrorTypes.WATCH_CLEANUP]: 'watcher cleanup function', [ErrorCodes.WATCH_CLEANUP]: 'watcher cleanup function',
[ErrorTypes.NATIVE_EVENT_HANDLER]: 'native event handler', [ErrorCodes.NATIVE_EVENT_HANDLER]: 'native event handler',
[ErrorTypes.COMPONENT_EVENT_HANDLER]: 'component event handler', [ErrorCodes.COMPONENT_EVENT_HANDLER]: 'component event handler',
[ErrorTypes.DIRECTIVE_HOOK]: 'directive hook', [ErrorCodes.DIRECTIVE_HOOK]: 'directive hook',
[ErrorTypes.APP_ERROR_HANDLER]: 'app errorHandler', [ErrorCodes.APP_ERROR_HANDLER]: 'app errorHandler',
[ErrorTypes.APP_WARN_HANDLER]: 'app warnHandler', [ErrorCodes.APP_WARN_HANDLER]: 'app warnHandler',
[ErrorTypes.SCHEDULER]: [ErrorCodes.SCHEDULER]:
'scheduler flush. This may be a Vue internals bug. ' + 'scheduler flush. This may be a Vue internals bug. ' +
'Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/vue' 'Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/vue'
} }
type AllErrorTypes = LifecycleHooks | ErrorTypes export type ErrorTypes = LifecycleHooks | ErrorCodes
export function callWithErrorHandling( export function callWithErrorHandling(
fn: Function, fn: Function,
instance: ComponentInstance | null, instance: ComponentInternalInstance | null,
type: AllErrorTypes, type: ErrorTypes,
args?: any[] args?: any[]
) { ) {
let res: any let res: any
@ -66,8 +66,8 @@ export function callWithErrorHandling(
export function callWithAsyncErrorHandling( export function callWithAsyncErrorHandling(
fn: Function, fn: Function,
instance: ComponentInstance | null, instance: ComponentInternalInstance | null,
type: AllErrorTypes, type: ErrorTypes,
args?: any[] args?: any[]
) { ) {
const res = callWithErrorHandling(fn, instance, type, args) const res = callWithErrorHandling(fn, instance, type, args)
@ -81,12 +81,12 @@ export function callWithAsyncErrorHandling(
export function handleError( export function handleError(
err: Error, err: Error,
instance: ComponentInstance | null, instance: ComponentInternalInstance | null,
type: AllErrorTypes type: ErrorTypes
) { ) {
const contextVNode = instance ? instance.vnode : null const contextVNode = instance ? instance.vnode : null
if (instance) { if (instance) {
let cur: ComponentInstance | null = instance.parent let cur: ComponentInternalInstance | null = instance.parent
// the exposed instance is the render proxy to keep it consistent with 2.x // the exposed instance is the render proxy to keep it consistent with 2.x
const exposedInstance = instance.renderProxy const exposedInstance = instance.renderProxy
// in production the hook receives only the error code // in production the hook receives only the error code
@ -108,7 +108,7 @@ export function handleError(
callWithErrorHandling( callWithErrorHandling(
appErrorHandler, appErrorHandler,
null, null,
ErrorTypes.APP_ERROR_HANDLER, ErrorCodes.APP_ERROR_HANDLER,
[err, exposedInstance, errorInfo] [err, exposedInstance, errorInfo]
) )
return return
@ -117,7 +117,7 @@ export function handleError(
logError(err, type, contextVNode) logError(err, type, contextVNode)
} }
function logError(err: Error, type: AllErrorTypes, contextVNode: VNode | null) { function logError(err: Error, type: ErrorTypes, contextVNode: VNode | null) {
// default behavior is crash in prod & test, recover in dev. // default behavior is crash in prod & test, recover in dev.
// TODO we should probably make this configurable via `createApp` // TODO we should probably make this configurable via `createApp`
if ( if (

View File

@ -47,7 +47,7 @@ h('div', {}, 'foo') // text
h('div', null, {}) h('div', null, {})
**/ **/
interface Props { export interface RawProps {
[key: string]: any [key: string]: any
key?: string | number key?: string | number
ref?: string | Ref<any> | Function ref?: string | Ref<any> | Function
@ -57,7 +57,14 @@ interface Props {
[Symbol.iterator]?: never [Symbol.iterator]?: never
} }
type Children = string | number | boolean | VNodeChildren | (() => any) export type RawChildren =
| string
| number
| boolean
| VNodeChildren
| (() => any)
export { RawSlots }
// fake constructor type returned from `createComponent` // fake constructor type returned from `createComponent`
interface Constructor<P = any> { interface Constructor<P = any> {
@ -68,63 +75,63 @@ interface Constructor<P = any> {
// manually written render functions. // manually written render functions.
// element // element
export function h(type: string, children?: Children): VNode export function h(type: string, children?: RawChildren): VNode
export function h( export function h(
type: string, type: string,
props?: Props | null, props?: RawProps | null,
children?: Children children?: RawChildren
): VNode ): VNode
// keyed fragment // keyed fragment
export function h(type: typeof Fragment, children?: Children): VNode export function h(type: typeof Fragment, children?: RawChildren): VNode
export function h( export function h(
type: typeof Fragment, type: typeof Fragment,
props?: (Props & { key?: string | number }) | null, props?: (RawProps & { key?: string | number }) | null,
children?: Children children?: RawChildren
): VNode ): VNode
// portal // portal
export function h(type: typeof Portal, children?: Children): VNode export function h(type: typeof Portal, children?: RawChildren): VNode
export function h( export function h(
type: typeof Portal, type: typeof Portal,
props?: (Props & { target: any }) | null, props?: (RawProps & { target: any }) | null,
children?: Children children?: RawChildren
): VNode ): VNode
// functional component // functional component
export function h(type: FunctionalComponent, children?: Children): VNode export function h(type: FunctionalComponent, children?: RawChildren): VNode
export function h<P>( export function h<P>(
type: FunctionalComponent<P>, type: FunctionalComponent<P>,
props?: (Props & P) | null, props?: (RawProps & P) | null,
children?: Children | RawSlots children?: RawChildren | RawSlots
): VNode ): VNode
// stateful component // stateful component
export function h(type: ComponentOptions, children?: Children): VNode export function h(type: ComponentOptions, children?: RawChildren): VNode
export function h<P>( export function h<P>(
type: ComponentOptionsWithoutProps<P>, type: ComponentOptionsWithoutProps<P>,
props?: (Props & P) | null, props?: (RawProps & P) | null,
children?: Children | RawSlots children?: RawChildren | RawSlots
): VNode ): VNode
export function h<P extends string>( export function h<P extends string>(
type: ComponentOptionsWithArrayProps<P>, type: ComponentOptionsWithArrayProps<P>,
// TODO for now this doesn't really do anything, but it would become useful // TODO for now this doesn't really do anything, but it would become useful
// if we make props required by default // if we make props required by default
props?: (Props & { [key in P]?: any }) | null, props?: (RawProps & { [key in P]?: any }) | null,
children?: Children | RawSlots children?: RawChildren | RawSlots
): VNode ): VNode
export function h<P>( export function h<P>(
type: ComponentOptionsWithProps<P>, type: ComponentOptionsWithProps<P>,
props?: (Props & ExtractPropTypes<P>) | null, props?: (RawProps & ExtractPropTypes<P>) | null,
children?: Children | RawSlots children?: RawChildren | RawSlots
): VNode ): VNode
// fake constructor type returned by `createComponent` // fake constructor type returned by `createComponent`
export function h(type: Constructor, children?: Children): VNode export function h(type: Constructor, children?: RawChildren): VNode
export function h<P>( export function h<P>(
type: Constructor<P>, type: Constructor<P>,
props?: (Props & P) | null, props?: (RawProps & P) | null,
children?: Children | RawSlots children?: RawChildren | RawSlots
): VNode ): VNode
// Actual implementation // Actual implementation

View File

@ -43,9 +43,26 @@ export { resolveComponent, resolveDirective } from './componentOptions'
// Types ----------------------------------------------------------------------- // Types -----------------------------------------------------------------------
export { App, AppConfig, AppContext, Plugin } from './apiApp' export { App, AppConfig, AppContext, Plugin } from './apiApp'
export { RawProps, RawChildren, RawSlots } from './h'
export { VNode, VNodeTypes } from './vnode' export { VNode, VNodeTypes } from './vnode'
export { FunctionalComponent, ComponentInstance } from './component' export {
Component,
FunctionalComponent,
ComponentInternalInstance
} from './component'
export {
ComponentOptions,
ComponentOptionsWithoutProps,
ComponentOptionsWithProps,
ComponentOptionsWithArrayProps
} from './componentOptions'
export { ComponentPublicInstance } from './componentPublicInstanceProxy'
export { RendererOptions } from './createRenderer' export { RendererOptions } from './createRenderer'
export { Slot, Slots } from './componentSlots' export { Slot, Slots } from './componentSlots'
export { PropType, ComponentPropsOptions } from './componentProps' export { Prop, PropType, ComponentPropsOptions } from './componentProps'
export { Directive, DirectiveBinding, DirectiveHook } from './directives' export {
Directive,
DirectiveBinding,
DirectiveHook,
DirectiveArguments
} from './directives'

View File

@ -1,4 +1,4 @@
import { handleError, ErrorTypes } from './errorHandling' import { handleError, ErrorCodes } from './errorHandling'
const queue: Function[] = [] const queue: Function[] = []
const postFlushCbs: Function[] = [] const postFlushCbs: Function[] = []
@ -72,7 +72,7 @@ function flushJobs(seenJobs?: JobCountMap) {
try { try {
job() job()
} catch (err) { } catch (err) {
handleError(err, null, ErrorTypes.SCHEDULER) handleError(err, null, ErrorCodes.SCHEDULER)
} }
} }
flushPostFlushCbs() flushPostFlushCbs()

View File

@ -6,7 +6,7 @@ import {
EMPTY_ARR, EMPTY_ARR,
extend extend
} from '@vue/shared' } from '@vue/shared'
import { ComponentInstance, Data, SetupProxySymbol } from './component' import { ComponentInternalInstance, Data, SetupProxySymbol } from './component'
import { HostNode } from './createRenderer' import { HostNode } from './createRenderer'
import { RawSlots } from './componentSlots' import { RawSlots } from './componentSlots'
import { PatchFlags } from './patchFlags' import { PatchFlags } from './patchFlags'
@ -40,7 +40,7 @@ export interface VNode {
key: string | number | null key: string | number | null
ref: string | Function | null ref: string | Function | null
children: NormalizedChildren children: NormalizedChildren
component: ComponentInstance | null component: ComponentInternalInstance | null
// DOM // DOM
el: HostNode | null el: HostNode | null

View File

@ -1,5 +1,5 @@
import { VNode } from './vnode' import { VNode } from './vnode'
import { Data, ComponentInstance } from './component' import { Data, ComponentInternalInstance } from './component'
import { isString } from '@vue/shared' import { isString } from '@vue/shared'
import { toRaw } from '@vue/reactivity' import { toRaw } from '@vue/reactivity'
@ -77,7 +77,7 @@ function getComponentTrace(): ComponentTraceStack {
recurseCount: 0 recurseCount: 0
}) })
} }
const parentInstance: ComponentInstance | null = (currentVNode.component as ComponentInstance) const parentInstance: ComponentInternalInstance | null = (currentVNode.component as ComponentInternalInstance)
.parent .parent
currentVNode = parentInstance && parentInstance.vnode currentVNode = parentInstance && parentInstance.vnode
} }
@ -108,7 +108,9 @@ function formatTraceEntry(
const open = padding + `<${formatComponentName(vnode)}` const open = padding + `<${formatComponentName(vnode)}`
const close = `>` + postfix const close = `>` + postfix
const rootLabel = const rootLabel =
(vnode.component as ComponentInstance).parent == null ? `(Root)` : `` (vnode.component as ComponentInternalInstance).parent == null
? `(Root)`
: ``
return vnode.props return vnode.props
? [open, ...formatProps(vnode.props), close, rootLabel] ? [open, ...formatProps(vnode.props), close, rootLabel]
: [open + close, rootLabel] : [open + close, rootLabel]

View File

@ -1,21 +1,13 @@
# @vue/runtime-dom # @vue/runtime-dom
``` js ``` js
import { h, render, Component } from '@vue/runtime-dom' import { h, createApp } from '@vue/runtime-dom'
class App extends Component { const RootComponent = {
data () { render() {
return { return h('div', 'hello world')
msg: 'Hello World!'
}
}
render () {
return h('div', this.msg)
} }
} }
render( createApp().mount(RootComponent, '#app')
h(App),
document.getElementById('app')
)
``` ```

View File

@ -1,9 +1,9 @@
import { isArray } from '@vue/shared' import { isArray } from '@vue/shared'
import { import {
ComponentInstance, ComponentInternalInstance,
callWithAsyncErrorHandling callWithAsyncErrorHandling
} from '@vue/runtime-core' } from '@vue/runtime-core'
import { ErrorTypes } from 'packages/runtime-core/src/errorHandling' import { ErrorCodes } from 'packages/runtime-core/src/errorHandling'
interface Invoker extends Function { interface Invoker extends Function {
value: EventValue value: EventValue
@ -45,7 +45,7 @@ export function patchEvent(
name: string, name: string,
prevValue: EventValue | null, prevValue: EventValue | null,
nextValue: EventValue | null, nextValue: EventValue | null,
instance: ComponentInstance | null instance: ComponentInternalInstance | null
) { ) {
const invoker = prevValue && prevValue.invoker const invoker = prevValue && prevValue.invoker
if (nextValue) { if (nextValue) {
@ -62,7 +62,7 @@ export function patchEvent(
} }
} }
function createInvoker(value: any, instance: ComponentInstance | null) { function createInvoker(value: any, instance: ComponentInternalInstance | null) {
const invoker = ((e: Event) => { const invoker = ((e: Event) => {
// async edge case #6566: inner click event triggers patch, event handler // async edge case #6566: inner click event triggers patch, event handler
// attached to outer element during patch, and triggered again. This // attached to outer element during patch, and triggered again. This
@ -77,7 +77,7 @@ function createInvoker(value: any, instance: ComponentInstance | null) {
callWithAsyncErrorHandling( callWithAsyncErrorHandling(
value[i], value[i],
instance, instance,
ErrorTypes.NATIVE_EVENT_HANDLER, ErrorCodes.NATIVE_EVENT_HANDLER,
args args
) )
} }
@ -85,7 +85,7 @@ function createInvoker(value: any, instance: ComponentInstance | null) {
callWithAsyncErrorHandling( callWithAsyncErrorHandling(
value, value,
instance, instance,
ErrorTypes.NATIVE_EVENT_HANDLER, ErrorCodes.NATIVE_EVENT_HANDLER,
args args
) )
} }