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
The implementation of this module is inspired by the following prior art in the JavaScript ecosystem:
raw: Function
deps: Array<Dep>
computed?: boolean
- scheduler?: Scheduler
- onTrack?: Debugger
- onTrigger?: Debugger
+ scheduler?: (run: Function) => void
+ onTrack?: (event: DebuggerEvent) => void
+ onTrigger?: (event: DebuggerEvent) => void
onStop?: () => void
}
export interface ReactiveEffectOptions {
lazy?: boolean
computed?: boolean
- scheduler?: Scheduler
- onTrack?: Debugger
- onTrigger?: Debugger
+ scheduler?: (run: Function) => void
+ onTrack?: (event: DebuggerEvent) => void
+ onTrigger?: (event: DebuggerEvent) => void
onStop?: () => void
}
-export type Scheduler = (run: () => any) => void
-
export interface DebuggerEvent {
effect: ReactiveEffect
target: any
key: string | symbol | undefined
}
-export type Debugger = (event: DebuggerEvent) => void
-
export const activeReactiveEffectStack: ReactiveEffect[] = []
export const ITERATE_KEY = Symbol('iterate')
markReadonly,
markNonReactive
} from './reactive'
-export { computed, ComputedRef, WritableComputedOptions } from './computed'
+export {
+ computed,
+ ComputedRef,
+ WritableComputedRef,
+ WritableComputedOptions
+} from './computed'
export {
effect,
stop,
> This package is published only for typing and building custom renderers. It is NOT meant to be used in applications.
+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`.
+
+## Building a Custom Renderer
+
``` ts
-import { createRenderer, h } from '@vue/runtime-core'
+import { createRenderer, createAppAPI } from '@vue/runtime-core'
-const { render } = createRenderer({
- nodeOps,
- patchData,
- teardownVNode
+// 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.
nodeOps,
DirectiveHook,
VNode,
- ComponentInstance,
DirectiveBinding,
nextTick
} from '@vue/runtime-test'
-import { currentInstance } from '../src/component'
+import { currentInstance, ComponentInternalInstance } from '../src/component'
describe('directives', () => {
it('should work', async () => {
expect(prevVNode).toBe(null)
}) as DirectiveHook)
- let _instance: ComponentInstance | null = null
+ let _instance: ComponentInternalInstance | null = null
let _vnode: VNode | null = null
let _prevVnode: VNode | null = null
const Comp = {
-import { Component, Data, ComponentInstance } from './component'
+import { Component, Data, ComponentInternalInstance } from './component'
import { ComponentOptions } from './componentOptions'
-import { ComponentRenderProxy } from './componentProxy'
+import { ComponentPublicInstance } from './componentPublicInstanceProxy'
import { Directive } from './directives'
import { HostNode, RootRenderFunction } from './createRenderer'
import { InjectionKey } from './apiInject'
rootComponent: Component,
rootContainer: string | HostNode,
rootProps?: Data
- ): ComponentRenderProxy
+ ): ComponentPublicInstance
provide<T>(key: InjectionKey<T> | string, value: T): void
}
performance: boolean
errorHandler?: (
err: Error,
- instance: ComponentRenderProxy | null,
+ instance: ComponentPublicInstance | null,
info: string
) => void
warnHandler?: (
msg: string,
- instance: ComponentRenderProxy | null,
+ instance: ComponentPublicInstance | null,
trace: string
) => void
}
vnode.appContext = context
render(vnode, rootContainer)
isMounted = true
- return (vnode.component as ComponentInstance).renderProxy
+ return (vnode.component as ComponentInternalInstance).renderProxy
} else if (__DEV__) {
warn(
`App has already been mounted. Create a new app instance instead.`
} from './componentOptions'
import { SetupContext } from './component'
import { VNodeChild } from './vnode'
-import { ComponentRenderProxy } from './componentProxy'
+import { ComponentPublicInstance } from './componentPublicInstanceProxy'
import { ExtractPropTypes } from './componentProps'
import { isFunction } from '@vue/shared'
>(
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
>(
options: ComponentOptionsWithArrayProps<PropNames, RawBindings, D, C, M>
): {
- new (): ComponentRenderProxy<
+ new (): ComponentPublicInstance<
{ [key in PropNames]?: unknown },
RawBindings,
D,
options: ComponentOptionsWithProps<PropsOptions, RawBindings, D, C, M>
): {
// for Vetur and TSX support
- new (): ComponentRenderProxy<
+ new (): ComponentPublicInstance<
ExtractPropTypes<PropsOptions>,
RawBindings,
D,
import {
- ComponentInstance,
+ ComponentInternalInstance,
LifecycleHooks,
currentInstance,
setCurrentInstance
} from './component'
-import { ComponentRenderProxy } from './componentProxy'
+import { ComponentPublicInstance } from './componentPublicInstanceProxy'
import { callWithAsyncErrorHandling, ErrorTypeStrings } from './errorHandling'
import { warn } from './warning'
import { capitalize } from '@vue/shared'
function injectHook(
type: LifecycleHooks,
hook: Function,
- target: ComponentInstance | null
+ target: ComponentInternalInstance | null
) {
if (target) {
;(target[type] || (target[type] = [])).push((...args: any[]) => {
export function onBeforeMount(
hook: Function,
- target: ComponentInstance | null = currentInstance
+ target: ComponentInternalInstance | null = currentInstance
) {
injectHook(LifecycleHooks.BEFORE_MOUNT, hook, target)
}
export function onMounted(
hook: Function,
- target: ComponentInstance | null = currentInstance
+ target: ComponentInternalInstance | null = currentInstance
) {
injectHook(LifecycleHooks.MOUNTED, hook, target)
}
export function onBeforeUpdate(
hook: Function,
- target: ComponentInstance | null = currentInstance
+ target: ComponentInternalInstance | null = currentInstance
) {
injectHook(LifecycleHooks.BEFORE_UPDATE, hook, target)
}
export function onUpdated(
hook: Function,
- target: ComponentInstance | null = currentInstance
+ target: ComponentInternalInstance | null = currentInstance
) {
injectHook(LifecycleHooks.UPDATED, hook, target)
}
export function onBeforeUnmount(
hook: Function,
- target: ComponentInstance | null = currentInstance
+ target: ComponentInternalInstance | null = currentInstance
) {
injectHook(LifecycleHooks.BEFORE_UNMOUNT, hook, target)
}
export function onUnmounted(
hook: Function,
- target: ComponentInstance | null = currentInstance
+ target: ComponentInternalInstance | null = currentInstance
) {
injectHook(LifecycleHooks.UNMOUNTED, hook, target)
}
export function onRenderTriggered(
hook: Function,
- target: ComponentInstance | null = currentInstance
+ target: ComponentInternalInstance | null = currentInstance
) {
injectHook(LifecycleHooks.RENDER_TRIGGERED, hook, target)
}
export function onRenderTracked(
hook: Function,
- target: ComponentInstance | null = currentInstance
+ target: ComponentInternalInstance | null = currentInstance
) {
injectHook(LifecycleHooks.RENDER_TRACKED, hook, target)
}
export function onErrorCaptured(
hook: (
err: Error,
- instance: ComponentRenderProxy | null,
+ instance: ComponentPublicInstance | null,
info: string
) => boolean | void,
- target: ComponentInstance | null = currentInstance
+ target: ComponentInternalInstance | null = currentInstance
) {
injectHook(LifecycleHooks.ERROR_CAPTURED, hook, target)
}
import { queueJob, queuePostFlushCb } from './scheduler'
import { EMPTY_OBJ, isObject, isArray, isFunction, isString } from '@vue/shared'
import { recordEffect } from './apiReactivity'
-import { currentInstance, ComponentInstance } from './component'
+import { currentInstance, ComponentInternalInstance } from './component'
import {
- ErrorTypes,
+ ErrorCodes,
callWithErrorHandling,
callWithAsyncErrorHandling
} from './errorHandling'
s =>
isRef(s)
? s.value
- : callWithErrorHandling(s, instance, ErrorTypes.WATCH_GETTER)
+ : callWithErrorHandling(s, instance, ErrorCodes.WATCH_GETTER)
)
} else if (isRef(source)) {
getter = () => source.value
} else if (cb) {
// getter with cb
getter = () =>
- callWithErrorHandling(source, instance, ErrorTypes.WATCH_GETTER)
+ callWithErrorHandling(source, instance, ErrorCodes.WATCH_GETTER)
} else {
// no cb -> simple effect
getter = () => {
return callWithErrorHandling(
source,
instance,
- ErrorTypes.WATCH_CALLBACK,
+ ErrorCodes.WATCH_CALLBACK,
[registerCleanup]
)
}
const registerCleanup: CleanupRegistrator = (fn: () => void) => {
// TODO wrap the cleanup fn for error handling
cleanup = runner.onStop = () => {
- callWithErrorHandling(fn, instance, ErrorTypes.WATCH_CLEANUP)
+ callWithErrorHandling(fn, instance, ErrorCodes.WATCH_CLEANUP)
}
}
if (cleanup) {
cleanup()
}
- callWithAsyncErrorHandling(cb, instance, ErrorTypes.WATCH_CALLBACK, [
+ callWithAsyncErrorHandling(cb, instance, ErrorCodes.WATCH_CALLBACK, [
newValue,
oldValue,
registerCleanup
// this.$watch
export function instanceWatch(
- this: ComponentInstance,
+ this: ComponentInternalInstance,
source: string | Function,
cb: Function,
options?: WatchOptions
import { VNode, VNodeChild } from './vnode'
import { ReactiveEffect, reactive, readonly } from '@vue/reactivity'
-import { RenderProxyHandlers, ComponentRenderProxy } from './componentProxy'
+import {
+ PublicInstanceProxyHandlers,
+ ComponentPublicInstance
+} from './componentPublicInstanceProxy'
import { ComponentPropsOptions } from './componentProps'
import { Slots } from './componentSlots'
import { warn } from './warning'
import {
- ErrorTypes,
+ ErrorCodes,
callWithErrorHandling,
callWithAsyncErrorHandling
} from './errorHandling'
type RenderFunction = () => VNodeChild
-export interface ComponentInstance {
+export interface ComponentInternalInstance {
type: FunctionalComponent | ComponentOptions
- parent: ComponentInstance | null
+ parent: ComponentInternalInstance | null
appContext: AppContext
- root: ComponentInstance
+ root: ComponentInternalInstance
vnode: VNode
next: VNode | null
subTree: VNode
props: Data
attrs: Data
slots: Slots
- renderProxy: ComponentRenderProxy | null
+ renderProxy: ComponentPublicInstance | null
propsProxy: Data | null
setupContext: SetupContext | null
refs: Data
export function createComponentInstance(
vnode: VNode,
- parent: ComponentInstance | null
-): ComponentInstance {
+ parent: ComponentInternalInstance | null
+): ComponentInternalInstance {
// inherit parent app context - or - if root, adopt from root vnode
const appContext =
(parent ? parent.appContext : vnode.appContext) || emptyAppContext
callWithAsyncErrorHandling(
handler[i],
instance,
- ErrorTypes.COMPONENT_EVENT_HANDLER,
+ ErrorCodes.COMPONENT_EVENT_HANDLER,
args
)
}
callWithAsyncErrorHandling(
handler,
instance,
- ErrorTypes.COMPONENT_EVENT_HANDLER,
+ ErrorCodes.COMPONENT_EVENT_HANDLER,
args
)
}
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
-export const setCurrentInstance = (instance: ComponentInstance | null) => {
+export const setCurrentInstance = (
+ instance: ComponentInternalInstance | null
+) => {
currentInstance = instance
}
-export function setupStatefulComponent(instance: ComponentInstance) {
+export function setupStatefulComponent(instance: ComponentInternalInstance) {
currentInstance = instance
const Component = instance.type as ComponentOptions
// 1. create render proxy
- instance.renderProxy = new Proxy(instance, RenderProxyHandlers) as any
+ instance.renderProxy = new Proxy(instance, PublicInstanceProxyHandlers) as any
// 2. create props proxy
// the propsProxy is a reactive AND readonly proxy to the actual props.
// it will be updated in resolveProps() on updates before render
const setupResult = callWithErrorHandling(
setup,
instance,
- ErrorTypes.SETUP_FUNCTION,
+ ErrorCodes.SETUP_FUNCTION,
[propsProxy, setupContext]
)
}
})
-function createSetupContext(instance: ComponentInstance): SetupContext {
+function createSetupContext(instance: ComponentInternalInstance): SetupContext {
const context = {
// attrs, slots & refs are non-reactive, but they need to always expose
// the latest values (instance.xxx may get replaced during updates) so we
import {
- ComponentInstance,
+ ComponentInternalInstance,
Data,
currentInstance,
Component,
import { ComponentPropsOptions, ExtractPropTypes } from './componentProps'
import { Directive } from './directives'
import { VNodeChild } from './vnode'
-import { ComponentRenderProxy } from './componentProxy'
+import { ComponentPublicInstance } from './componentPublicInstanceProxy'
import { currentRenderingInstance } from './componentRenderUtils'
interface ComponentOptionsBase<
M extends MethodOptions = {}
> = ComponentOptionsBase<Props, RawBindings, D, C, M> & {
props?: undefined
-} & ThisType<ComponentRenderProxy<Props, RawBindings, D, C, M>>
+} & ThisType<ComponentPublicInstance<Props, RawBindings, D, C, M>>
export type ComponentOptionsWithArrayProps<
PropNames extends string = string,
Props = { [key in PropNames]?: unknown }
> = ComponentOptionsBase<Props, RawBindings, D, C, M> & {
props: PropNames[]
-} & ThisType<ComponentRenderProxy<Props, RawBindings, D, C, M>>
+} & ThisType<ComponentPublicInstance<Props, RawBindings, D, C, M>>
export type ComponentOptionsWithProps<
PropsOptions = ComponentPropsOptions,
Props = ExtractPropTypes<PropsOptions>
> = ComponentOptionsBase<Props, RawBindings, D, C, M> & {
props: PropsOptions
-} & ThisType<ComponentRenderProxy<Props, RawBindings, D, C, M>>
+} & ThisType<ComponentPublicInstance<Props, RawBindings, D, C, M>>
export type ComponentOptions =
| ComponentOptionsWithoutProps
// Limitation: we cannot expose RawBindings on the `this` context for data
// since that leads to some sort of circular inference and breaks ThisType
// for the entire component.
- data?: D | ((this: ComponentRenderProxy<Props>) => D)
+ data?: D | ((this: ComponentPublicInstance<Props>) => D)
computed?: C
methods?: M
// TODO watch array
}
export function applyOptions(
- instance: ComponentInstance,
+ instance: ComponentInternalInstance,
options: ComponentOptions,
asMixin: boolean = false
) {
}
}
-function applyMixins(instance: ComponentInstance, mixins: ComponentOptions[]) {
+function applyMixins(
+ instance: ComponentInternalInstance,
+ mixins: ComponentOptions[]
+) {
for (let i = 0; i < mixins.length; i++) {
applyOptions(instance, mixins[i], true)
}
hasOwn
} from '@vue/shared'
import { warn } from './warning'
-import { Data, ComponentInstance } from './component'
+import { Data, ComponentInternalInstance } from './component'
import { PatchFlags } from './patchFlags'
export type ComponentPropsOptions<P = Data> = {
[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> {
type?: PropType<T> | true | null
// - else: everything goes in `props`.
export function resolveProps(
- instance: ComponentInstance,
+ instance: ComponentInternalInstance,
rawProps: any,
_options: ComponentPropsOptions | void
) {
-import { ComponentInstance, Data } from './component'
+import { ComponentInternalInstance, Data } from './component'
import { nextTick } from './scheduler'
import { instanceWatch } from './apiWatch'
import { EMPTY_OBJ, hasOwn } from '@vue/shared'
// public properties exposed on the proxy, which is used as the render context
// in templates (as `this` in the render option)
-export type ComponentRenderProxy<
+export type ComponentPublicInstance<
P = {},
B = {},
D = {},
$attrs: Data
$refs: Data
$slots: Data
- $root: ComponentInstance | null
- $parent: ComponentInstance | null
+ $root: ComponentInternalInstance | null
+ $parent: ComponentInternalInstance | null
$emit: (event: string, ...args: unknown[]) => void
} & P &
UnwrapRef<B> &
ExtracComputedReturns<C> &
M
-export const RenderProxyHandlers = {
- get(target: ComponentInstance, key: string) {
+export const PublicInstanceProxyHandlers = {
+ get(target: ComponentInternalInstance, key: string) {
const { renderContext, data, props, propsProxy } = target
if (data !== EMPTY_OBJ && hasOwn(data, key)) {
return data[key]
}
}
},
- set(target: ComponentInstance, key: string, value: any): boolean {
+ set(target: ComponentInternalInstance, key: string, value: any): boolean {
const { data, renderContext } = target
if (data !== EMPTY_OBJ && hasOwn(data, key)) {
data[key] = value
-import { ComponentInstance, FunctionalComponent, Data } from './component'
+import {
+ ComponentInternalInstance,
+ FunctionalComponent,
+ Data
+} from './component'
import { VNode, normalizeVNode, createVNode, Empty } from './vnode'
import { ShapeFlags } from './shapeFlags'
-import { handleError, ErrorTypes } from './errorHandling'
+import { handleError, ErrorCodes } from './errorHandling'
import { PatchFlags } from './patchFlags'
// mark the current rendering instance for asset resolution (e.g.
// 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 {
type: Component,
vnode,
)
}
} catch (err) {
- handleError(err, instance, ErrorTypes.RENDER_FUNCTION)
+ handleError(err, instance, ErrorCodes.RENDER_FUNCTION)
result = createVNode(Empty)
}
currentRenderingInstance = null
-import { ComponentInstance, currentInstance } from './component'
+import { ComponentInternalInstance, currentInstance } from './component'
import { VNode, NormalizedChildren, normalizeVNode, VNodeChild } from './vnode'
import { isArray, isFunction } from '@vue/shared'
import { ShapeFlags } from './shapeFlags'
}
export function resolveSlots(
- instance: ComponentInstance,
+ instance: ComponentInternalInstance,
children: NormalizedChildren
) {
let slots: Slots | void
VNodeChildren
} from './vnode'
import {
- ComponentInstance,
+ ComponentInternalInstance,
createComponentInstance,
setupStatefulComponent
} from './component'
}
function createDevEffectOptions(
- instance: ComponentInstance
+ instance: ComponentInternalInstance
): ReactiveEffectOptions {
return {
scheduler: queueJob,
oldValue: any,
isSVG: boolean,
prevChildren?: VNode[],
- parentComponent?: ComponentInstance | null,
+ parentComponent?: ComponentInternalInstance | null,
unmountChildren?: (
children: VNode[],
- parentComponent: ComponentInstance | null
+ parentComponent: ComponentInternalInstance | null
) => void
): void
insert(el: HostNode, parent: HostNode, anchor?: HostNode): void
n2: VNode,
container: HostNode,
anchor: HostNode = null,
- parentComponent: ComponentInstance | null = null,
+ parentComponent: ComponentInternalInstance | null = null,
isSVG: boolean = false,
optimized: boolean = false
) {
n2: VNode,
container: HostNode,
anchor: HostNode,
- parentComponent: ComponentInstance | null,
+ parentComponent: ComponentInternalInstance | null,
isSVG: boolean,
optimized: boolean
) {
vnode: VNode,
container: HostNode,
anchor: HostNode,
- parentComponent: ComponentInstance | null,
+ parentComponent: ComponentInternalInstance | null,
isSVG: boolean
) {
const tag = vnode.type as string
children: VNodeChildren,
container: HostNode,
anchor: HostNode,
- parentComponent: ComponentInstance | null,
+ parentComponent: ComponentInternalInstance | null,
isSVG: boolean,
start: number = 0
) {
function patchElement(
n1: VNode,
n2: VNode,
- parentComponent: ComponentInstance | null,
+ parentComponent: ComponentInternalInstance | null,
isSVG: boolean,
optimized: boolean
) {
vnode: VNode,
oldProps: any,
newProps: any,
- parentComponent: ComponentInstance | null,
+ parentComponent: ComponentInternalInstance | null,
isSVG: boolean
) {
if (oldProps !== newProps) {
n2: VNode,
container: HostNode,
anchor: HostNode,
- parentComponent: ComponentInstance | null,
+ parentComponent: ComponentInternalInstance | null,
isSVG: boolean,
optimized: boolean
) {
n2: VNode,
container: HostNode,
anchor: HostNode,
- parentComponent: ComponentInstance | null,
+ parentComponent: ComponentInternalInstance | null,
isSVG: boolean,
optimized: boolean
) {
n2: VNode,
container: HostNode,
anchor: HostNode,
- parentComponent: ComponentInstance | null,
+ parentComponent: ComponentInternalInstance | null,
isSVG: boolean,
optimized: boolean
) {
if (n1 == null) {
mountComponent(n2, container, anchor, parentComponent, isSVG)
} else {
- const instance = (n2.component = n1.component) as ComponentInstance
+ const instance = (n2.component =
+ n1.component) as ComponentInternalInstance
if (shouldUpdateComponent(n1, n2, optimized)) {
instance.next = n2
instance.update()
n2.ref,
n1 && n1.ref,
parentComponent,
- (n2.component as ComponentInstance).renderProxy
+ (n2.component as ComponentInternalInstance).renderProxy
)
}
}
initialVNode: VNode,
container: HostNode,
anchor: HostNode,
- parentComponent: ComponentInstance | null,
+ parentComponent: ComponentInternalInstance | null,
isSVG: boolean
) {
- const instance: ComponentInstance = (initialVNode.component = createComponentInstance(
+ const instance: ComponentInternalInstance = (initialVNode.component = createComponentInstance(
initialVNode,
parentComponent
))
n2: VNode,
container: HostNode,
anchor: HostNode,
- parentComponent: ComponentInstance | null,
+ parentComponent: ComponentInternalInstance | null,
isSVG: boolean,
optimized: boolean = false
) {
c2: VNodeChildren,
container: HostNode,
anchor: HostNode,
- parentComponent: ComponentInstance | null,
+ parentComponent: ComponentInternalInstance | null,
isSVG: boolean,
optimized: boolean
) {
c2: VNodeChildren,
container: HostNode,
parentAnchor: HostNode,
- parentComponent: ComponentInstance | null,
+ parentComponent: ComponentInternalInstance | null,
isSVG: boolean,
optimized: boolean
) {
function unmount(
vnode: VNode,
- parentComponent: ComponentInstance | null,
+ parentComponent: ComponentInternalInstance | null,
doRemove?: boolean
) {
const {
}
}
- function unmountComponent(instance: ComponentInstance, doRemove?: boolean) {
+ function unmountComponent(
+ instance: ComponentInternalInstance,
+ doRemove?: boolean
+ ) {
const { bum, effects, update, subTree, um } = instance
// beforeUnmount hook
if (bum !== null) {
function unmountChildren(
children: VNode[],
- parentComponent: ComponentInstance | null,
+ parentComponent: ComponentInternalInstance | null,
doRemove?: boolean,
start: number = 0
) {
function setRef(
ref: string | Function | Ref<any>,
oldRef: string | Function | Ref<any> | null,
- parent: ComponentInstance,
- value: HostNode | ComponentInstance | null
+ parent: ComponentInternalInstance,
+ value: HostNode | ComponentInternalInstance | null
) {
const refs = parent.refs === EMPTY_OBJ ? (parent.refs = {}) : parent.refs
const renderContext = toRaw(parent.renderContext)
import { VNode, cloneVNode } from './vnode'
import { extend, isArray, isFunction } from '@vue/shared'
import { warn } from './warning'
-import { ComponentInstance } from './component'
+import { ComponentInternalInstance } from './component'
import { currentRenderingInstance } from './componentRenderUtils'
-import { callWithAsyncErrorHandling, ErrorTypes } from './errorHandling'
+import { callWithAsyncErrorHandling, ErrorCodes } from './errorHandling'
import { HostNode } from './createRenderer'
-import { ComponentRenderProxy } from './componentProxy'
+import { ComponentPublicInstance } from './componentPublicInstanceProxy'
export interface DirectiveBinding {
- instance: ComponentRenderProxy | null
+ instance: ComponentPublicInstance | null
value?: any
oldValue?: any
arg?: string
function applyDirective(
props: Record<any, any>,
- instance: ComponentInstance,
+ instance: ComponentInternalInstance,
directive: Directive,
value?: any,
arg?: string,
}
// Directive, value, argument, modifiers
-type DirectiveArguments = Array<
+export type DirectiveArguments = Array<
| [Directive]
| [Directive, any]
| [Directive, any, string]
export function invokeDirectiveHook(
hook: Function | Function[],
- instance: ComponentInstance | null,
+ instance: ComponentInternalInstance | null,
vnode: VNode,
prevVNode: VNode | null = null
) {
callWithAsyncErrorHandling(
hook[i],
instance,
- ErrorTypes.DIRECTIVE_HOOK,
+ ErrorCodes.DIRECTIVE_HOOK,
args
)
}
} else if (isFunction(hook)) {
- callWithAsyncErrorHandling(hook, instance, ErrorTypes.DIRECTIVE_HOOK, args)
+ callWithAsyncErrorHandling(hook, instance, ErrorCodes.DIRECTIVE_HOOK, args)
}
}
import { VNode } from './vnode'
-import { ComponentInstance, LifecycleHooks } from './component'
+import { ComponentInternalInstance, LifecycleHooks } from './component'
import { warn, pushWarningContext, popWarningContext } from './warning'
// contexts where user provided function may be executed, in addition to
// lifecycle hooks.
-export const enum ErrorTypes {
+export const enum ErrorCodes {
SETUP_FUNCTION = 1,
RENDER_FUNCTION,
WATCH_GETTER,
[LifecycleHooks.ERROR_CAPTURED]: 'errorCaptured hook',
[LifecycleHooks.RENDER_TRACKED]: 'renderTracked hook',
[LifecycleHooks.RENDER_TRIGGERED]: 'renderTriggered hook',
- [ErrorTypes.SETUP_FUNCTION]: 'setup function',
- [ErrorTypes.RENDER_FUNCTION]: 'render function',
- [ErrorTypes.WATCH_GETTER]: 'watcher getter',
- [ErrorTypes.WATCH_CALLBACK]: 'watcher callback',
- [ErrorTypes.WATCH_CLEANUP]: 'watcher cleanup function',
- [ErrorTypes.NATIVE_EVENT_HANDLER]: 'native event handler',
- [ErrorTypes.COMPONENT_EVENT_HANDLER]: 'component event handler',
- [ErrorTypes.DIRECTIVE_HOOK]: 'directive hook',
- [ErrorTypes.APP_ERROR_HANDLER]: 'app errorHandler',
- [ErrorTypes.APP_WARN_HANDLER]: 'app warnHandler',
- [ErrorTypes.SCHEDULER]:
+ [ErrorCodes.SETUP_FUNCTION]: 'setup function',
+ [ErrorCodes.RENDER_FUNCTION]: 'render function',
+ [ErrorCodes.WATCH_GETTER]: 'watcher getter',
+ [ErrorCodes.WATCH_CALLBACK]: 'watcher callback',
+ [ErrorCodes.WATCH_CLEANUP]: 'watcher cleanup function',
+ [ErrorCodes.NATIVE_EVENT_HANDLER]: 'native event handler',
+ [ErrorCodes.COMPONENT_EVENT_HANDLER]: 'component event handler',
+ [ErrorCodes.DIRECTIVE_HOOK]: 'directive hook',
+ [ErrorCodes.APP_ERROR_HANDLER]: 'app errorHandler',
+ [ErrorCodes.APP_WARN_HANDLER]: 'app warnHandler',
+ [ErrorCodes.SCHEDULER]:
'scheduler flush. This may be a Vue internals bug. ' +
'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(
fn: Function,
- instance: ComponentInstance | null,
- type: AllErrorTypes,
+ instance: ComponentInternalInstance | null,
+ type: ErrorTypes,
args?: any[]
) {
let res: any
export function callWithAsyncErrorHandling(
fn: Function,
- instance: ComponentInstance | null,
- type: AllErrorTypes,
+ instance: ComponentInternalInstance | null,
+ type: ErrorTypes,
args?: any[]
) {
const res = callWithErrorHandling(fn, instance, type, args)
export function handleError(
err: Error,
- instance: ComponentInstance | null,
- type: AllErrorTypes
+ instance: ComponentInternalInstance | null,
+ type: ErrorTypes
) {
const contextVNode = instance ? instance.vnode : null
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
const exposedInstance = instance.renderProxy
// in production the hook receives only the error code
callWithErrorHandling(
appErrorHandler,
null,
- ErrorTypes.APP_ERROR_HANDLER,
+ ErrorCodes.APP_ERROR_HANDLER,
[err, exposedInstance, errorInfo]
)
return
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.
// TODO we should probably make this configurable via `createApp`
if (
h('div', null, {})
**/
-interface Props {
+export interface RawProps {
[key: string]: any
key?: string | number
ref?: string | Ref<any> | Function
[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`
interface Constructor<P = any> {
// manually written render functions.
// element
-export function h(type: string, children?: Children): VNode
+export function h(type: string, children?: RawChildren): VNode
export function h(
type: string,
- props?: Props | null,
- children?: Children
+ props?: RawProps | null,
+ children?: RawChildren
): VNode
// keyed fragment
-export function h(type: typeof Fragment, children?: Children): VNode
+export function h(type: typeof Fragment, children?: RawChildren): VNode
export function h(
type: typeof Fragment,
- props?: (Props & { key?: string | number }) | null,
- children?: Children
+ props?: (RawProps & { key?: string | number }) | null,
+ children?: RawChildren
): VNode
// portal
-export function h(type: typeof Portal, children?: Children): VNode
+export function h(type: typeof Portal, children?: RawChildren): VNode
export function h(
type: typeof Portal,
- props?: (Props & { target: any }) | null,
- children?: Children
+ props?: (RawProps & { target: any }) | null,
+ children?: RawChildren
): VNode
// functional component
-export function h(type: FunctionalComponent, children?: Children): VNode
+export function h(type: FunctionalComponent, children?: RawChildren): VNode
export function h<P>(
type: FunctionalComponent<P>,
- props?: (Props & P) | null,
- children?: Children | RawSlots
+ props?: (RawProps & P) | null,
+ children?: RawChildren | RawSlots
): VNode
// stateful component
-export function h(type: ComponentOptions, children?: Children): VNode
+export function h(type: ComponentOptions, children?: RawChildren): VNode
export function h<P>(
type: ComponentOptionsWithoutProps<P>,
- props?: (Props & P) | null,
- children?: Children | RawSlots
+ props?: (RawProps & P) | null,
+ children?: RawChildren | RawSlots
): VNode
export function h<P extends string>(
type: ComponentOptionsWithArrayProps<P>,
// TODO for now this doesn't really do anything, but it would become useful
// if we make props required by default
- props?: (Props & { [key in P]?: any }) | null,
- children?: Children | RawSlots
+ props?: (RawProps & { [key in P]?: any }) | null,
+ children?: RawChildren | RawSlots
): VNode
export function h<P>(
type: ComponentOptionsWithProps<P>,
- props?: (Props & ExtractPropTypes<P>) | null,
- children?: Children | RawSlots
+ props?: (RawProps & ExtractPropTypes<P>) | null,
+ children?: RawChildren | RawSlots
): VNode
// 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>(
type: Constructor<P>,
- props?: (Props & P) | null,
- children?: Children | RawSlots
+ props?: (RawProps & P) | null,
+ children?: RawChildren | RawSlots
): VNode
// Actual implementation
// Types -----------------------------------------------------------------------
export { App, AppConfig, AppContext, Plugin } from './apiApp'
+export { RawProps, RawChildren, RawSlots } from './h'
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 { Slot, Slots } from './componentSlots'
-export { PropType, ComponentPropsOptions } from './componentProps'
-export { Directive, DirectiveBinding, DirectiveHook } from './directives'
+export { Prop, PropType, ComponentPropsOptions } from './componentProps'
+export {
+ Directive,
+ DirectiveBinding,
+ DirectiveHook,
+ DirectiveArguments
+} from './directives'
-import { handleError, ErrorTypes } from './errorHandling'
+import { handleError, ErrorCodes } from './errorHandling'
const queue: Function[] = []
const postFlushCbs: Function[] = []
try {
job()
} catch (err) {
- handleError(err, null, ErrorTypes.SCHEDULER)
+ handleError(err, null, ErrorCodes.SCHEDULER)
}
}
flushPostFlushCbs()
EMPTY_ARR,
extend
} from '@vue/shared'
-import { ComponentInstance, Data, SetupProxySymbol } from './component'
+import { ComponentInternalInstance, Data, SetupProxySymbol } from './component'
import { HostNode } from './createRenderer'
import { RawSlots } from './componentSlots'
import { PatchFlags } from './patchFlags'
key: string | number | null
ref: string | Function | null
children: NormalizedChildren
- component: ComponentInstance | null
+ component: ComponentInternalInstance | null
// DOM
el: HostNode | null
import { VNode } from './vnode'
-import { Data, ComponentInstance } from './component'
+import { Data, ComponentInternalInstance } from './component'
import { isString } from '@vue/shared'
import { toRaw } from '@vue/reactivity'
recurseCount: 0
})
}
- const parentInstance: ComponentInstance | null = (currentVNode.component as ComponentInstance)
+ const parentInstance: ComponentInternalInstance | null = (currentVNode.component as ComponentInternalInstance)
.parent
currentVNode = parentInstance && parentInstance.vnode
}
const open = padding + `<${formatComponentName(vnode)}`
const close = `>` + postfix
const rootLabel =
- (vnode.component as ComponentInstance).parent == null ? `(Root)` : ``
+ (vnode.component as ComponentInternalInstance).parent == null
+ ? `(Root)`
+ : ``
return vnode.props
? [open, ...formatProps(vnode.props), close, rootLabel]
: [open + close, rootLabel]
# @vue/runtime-dom
``` js
-import { h, render, Component } from '@vue/runtime-dom'
+import { h, createApp } from '@vue/runtime-dom'
-class App extends Component {
- data () {
- return {
- msg: 'Hello World!'
- }
- }
- render () {
- return h('div', this.msg)
+const RootComponent = {
+ render() {
+ return h('div', 'hello world')
}
}
-render(
- h(App),
- document.getElementById('app')
-)
+createApp().mount(RootComponent, '#app')
```
import { isArray } from '@vue/shared'
import {
- ComponentInstance,
+ ComponentInternalInstance,
callWithAsyncErrorHandling
} from '@vue/runtime-core'
-import { ErrorTypes } from 'packages/runtime-core/src/errorHandling'
+import { ErrorCodes } from 'packages/runtime-core/src/errorHandling'
interface Invoker extends Function {
value: EventValue
name: string,
prevValue: EventValue | null,
nextValue: EventValue | null,
- instance: ComponentInstance | null
+ instance: ComponentInternalInstance | null
) {
const invoker = prevValue && prevValue.invoker
if (nextValue) {
}
}
-function createInvoker(value: any, instance: ComponentInstance | null) {
+function createInvoker(value: any, instance: ComponentInternalInstance | null) {
const invoker = ((e: Event) => {
// async edge case #6566: inner click event triggers patch, event handler
// attached to outer element during patch, and triggered again. This
callWithAsyncErrorHandling(
value[i],
instance,
- ErrorTypes.NATIVE_EVENT_HANDLER,
+ ErrorCodes.NATIVE_EVENT_HANDLER,
args
)
}
callWithAsyncErrorHandling(
value,
instance,
- ErrorTypes.NATIVE_EVENT_HANDLER,
+ ErrorCodes.NATIVE_EVENT_HANDLER,
args
)
}