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.
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:

View File

@ -9,23 +9,21 @@ export interface ReactiveEffect {
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
@ -33,8 +31,6 @@ export interface DebuggerEvent {
key: string | symbol | undefined
}
export type Debugger = (event: DebuggerEvent) => void
export const activeReactiveEffectStack: ReactiveEffect[] = []
export const ITERATE_KEY = Symbol('iterate')

View File

@ -8,7 +8,12 @@ export {
markReadonly,
markNonReactive
} from './reactive'
export { computed, ComputedRef, WritableComputedOptions } from './computed'
export {
computed,
ComputedRef,
WritableComputedRef,
WritableComputedOptions
} from './computed'
export {
effect,
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.
``` ts
import { createRenderer, h } from '@vue/runtime-core'
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`.
const { render } = createRenderer({
nodeOps,
patchData,
teardownVNode
## Building a Custom Renderer
``` ts
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,
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 () => {
@ -99,7 +98,7 @@ describe('directives', () => {
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 = {

View File

@ -1,6 +1,6 @@
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'
@ -20,7 +20,7 @@ export interface App {
rootComponent: Component,
rootContainer: string | HostNode,
rootProps?: Data
): ComponentRenderProxy
): ComponentPublicInstance
provide<T>(key: InjectionKey<T> | string, value: T): void
}
@ -29,12 +29,12 @@ export interface AppConfig {
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
}
@ -136,7 +136,7 @@ export function createAppAPI(render: RootRenderFunction): () => App {
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.`

View File

@ -7,7 +7,7 @@ import {
} 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'
@ -29,7 +29,7 @@ export function createComponent<
>(
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
@ -44,7 +44,7 @@ export function createComponent<
>(
options: ComponentOptionsWithArrayProps<PropNames, RawBindings, D, C, M>
): {
new (): ComponentRenderProxy<
new (): ComponentPublicInstance<
{ [key in PropNames]?: unknown },
RawBindings,
D,
@ -65,7 +65,7 @@ export function createComponent<
options: ComponentOptionsWithProps<PropsOptions, RawBindings, D, C, M>
): {
// for Vetur and TSX support
new (): ComponentRenderProxy<
new (): ComponentPublicInstance<
ExtractPropTypes<PropsOptions>,
RawBindings,
D,

View File

@ -1,10 +1,10 @@
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'
@ -13,7 +13,7 @@ import { pauseTracking, resumeTracking } from '@vue/reactivity'
function injectHook(
type: LifecycleHooks,
hook: Function,
target: ComponentInstance | null
target: ComponentInternalInstance | null
) {
if (target) {
;(target[type] || (target[type] = [])).push((...args: any[]) => {
@ -43,56 +43,56 @@ function injectHook(
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)
}
@ -100,10 +100,10 @@ export function onRenderTracked(
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)
}

View File

@ -8,9 +8,9 @@ import {
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'
@ -93,14 +93,14 @@ function doWatch(
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 = () => {
@ -110,7 +110,7 @@ function doWatch(
return callWithErrorHandling(
source,
instance,
ErrorTypes.WATCH_CALLBACK,
ErrorCodes.WATCH_CALLBACK,
[registerCleanup]
)
}
@ -125,7 +125,7 @@ function doWatch(
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)
}
}
@ -138,7 +138,7 @@ function doWatch(
if (cleanup) {
cleanup()
}
callWithAsyncErrorHandling(cb, instance, ErrorTypes.WATCH_CALLBACK, [
callWithAsyncErrorHandling(cb, instance, ErrorCodes.WATCH_CALLBACK, [
newValue,
oldValue,
registerCleanup
@ -190,7 +190,7 @@ function doWatch(
// this.$watch
export function instanceWatch(
this: ComponentInstance,
this: ComponentInternalInstance,
source: string | Function,
cb: Function,
options?: WatchOptions

View File

@ -1,11 +1,14 @@
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'
@ -59,11 +62,11 @@ export interface SetupContext {
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
@ -81,7 +84,7 @@ export interface ComponentInstance {
props: Data
attrs: Data
slots: Slots
renderProxy: ComponentRenderProxy | null
renderProxy: ComponentPublicInstance | null
propsProxy: Data | null
setupContext: SetupContext | null
refs: Data
@ -110,8 +113,8 @@ const emptyAppContext = createAppContext()
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
@ -171,7 +174,7 @@ export function createComponentInstance(
callWithAsyncErrorHandling(
handler[i],
instance,
ErrorTypes.COMPONENT_EVENT_HANDLER,
ErrorCodes.COMPONENT_EVENT_HANDLER,
args
)
}
@ -179,7 +182,7 @@ export function createComponentInstance(
callWithAsyncErrorHandling(
handler,
instance,
ErrorTypes.COMPONENT_EVENT_HANDLER,
ErrorCodes.COMPONENT_EVENT_HANDLER,
args
)
}
@ -191,20 +194,22 @@ export function createComponentInstance(
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
@ -217,7 +222,7 @@ export function setupStatefulComponent(instance: ComponentInstance) {
const setupResult = callWithErrorHandling(
setup,
instance,
ErrorTypes.SETUP_FUNCTION,
ErrorCodes.SETUP_FUNCTION,
[propsProxy, setupContext]
)
@ -290,7 +295,7 @@ const SetupProxyHandlers: { [key: string]: ProxyHandler<any> } = {}
}
})
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

View File

@ -1,5 +1,5 @@
import {
ComponentInstance,
ComponentInternalInstance,
Data,
currentInstance,
Component,
@ -33,7 +33,7 @@ import { warn } from './warning'
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<
@ -68,7 +68,7 @@ export type ComponentOptionsWithoutProps<
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,
@ -79,7 +79,7 @@ export type ComponentOptionsWithArrayProps<
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,
@ -90,7 +90,7 @@ export type ComponentOptionsWithProps<
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
@ -151,7 +151,7 @@ export interface LegacyOptions<
// 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
@ -180,7 +180,7 @@ export interface LegacyOptions<
}
export function applyOptions(
instance: ComponentInstance,
instance: ComponentInternalInstance,
options: ComponentOptions,
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++) {
applyOptions(instance, mixins[i], true)
}

View File

@ -12,14 +12,14 @@ import {
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
@ -90,7 +90,7 @@ type NormalizedPropsOptions = Record<string, NormalizedProp>
// - else: everything goes in `props`.
export function resolveProps(
instance: ComponentInstance,
instance: ComponentInternalInstance,
rawProps: any,
_options: ComponentPropsOptions | void
) {

View File

@ -1,4 +1,4 @@
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'
@ -7,7 +7,7 @@ import { UnwrapRef } from '@vue/reactivity'
// 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 = {},
@ -20,8 +20,8 @@ export type ComponentRenderProxy<
$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> &
@ -29,8 +29,8 @@ export type ComponentRenderProxy<
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]
@ -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
if (data !== EMPTY_OBJ && hasOwn(data, key)) {
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 { 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,
@ -38,7 +44,7 @@ export function renderComponentRoot(instance: ComponentInstance): VNode {
)
}
} catch (err) {
handleError(err, instance, ErrorTypes.RENDER_FUNCTION)
handleError(err, instance, ErrorCodes.RENDER_FUNCTION)
result = createVNode(Empty)
}
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 { isArray, isFunction } from '@vue/shared'
import { ShapeFlags } from './shapeFlags'
@ -31,7 +31,7 @@ const normalizeSlot = (key: string, rawSlot: Function): Slot => (
}
export function resolveSlots(
instance: ComponentInstance,
instance: ComponentInternalInstance,
children: NormalizedChildren
) {
let slots: Slots | void

View File

@ -8,7 +8,7 @@ import {
VNodeChildren
} from './vnode'
import {
ComponentInstance,
ComponentInternalInstance,
createComponentInstance,
setupStatefulComponent
} from './component'
@ -44,7 +44,7 @@ const prodEffectOptions = {
}
function createDevEffectOptions(
instance: ComponentInstance
instance: ComponentInternalInstance
): ReactiveEffectOptions {
return {
scheduler: queueJob,
@ -77,10 +77,10 @@ export interface RendererOptions {
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
@ -120,7 +120,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
n2: VNode,
container: HostNode,
anchor: HostNode = null,
parentComponent: ComponentInstance | null = null,
parentComponent: ComponentInternalInstance | null = null,
isSVG: boolean = false,
optimized: boolean = false
) {
@ -226,7 +226,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
n2: VNode,
container: HostNode,
anchor: HostNode,
parentComponent: ComponentInstance | null,
parentComponent: ComponentInternalInstance | null,
isSVG: boolean,
optimized: boolean
) {
@ -244,7 +244,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
vnode: VNode,
container: HostNode,
anchor: HostNode,
parentComponent: ComponentInstance | null,
parentComponent: ComponentInternalInstance | null,
isSVG: boolean
) {
const tag = vnode.type as string
@ -283,7 +283,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
children: VNodeChildren,
container: HostNode,
anchor: HostNode,
parentComponent: ComponentInstance | null,
parentComponent: ComponentInternalInstance | null,
isSVG: boolean,
start: number = 0
) {
@ -296,7 +296,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
function patchElement(
n1: VNode,
n2: VNode,
parentComponent: ComponentInstance | null,
parentComponent: ComponentInternalInstance | null,
isSVG: boolean,
optimized: boolean
) {
@ -407,7 +407,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
vnode: VNode,
oldProps: any,
newProps: any,
parentComponent: ComponentInstance | null,
parentComponent: ComponentInternalInstance | null,
isSVG: boolean
) {
if (oldProps !== newProps) {
@ -453,7 +453,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
n2: VNode,
container: HostNode,
anchor: HostNode,
parentComponent: ComponentInstance | null,
parentComponent: ComponentInternalInstance | null,
isSVG: boolean,
optimized: boolean
) {
@ -490,7 +490,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
n2: VNode,
container: HostNode,
anchor: HostNode,
parentComponent: ComponentInstance | null,
parentComponent: ComponentInternalInstance | null,
isSVG: boolean,
optimized: boolean
) {
@ -552,14 +552,15 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
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()
@ -573,7 +574,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
n2.ref,
n1 && n1.ref,
parentComponent,
(n2.component as ComponentInstance).renderProxy
(n2.component as ComponentInternalInstance).renderProxy
)
}
}
@ -582,10 +583,10 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
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
))
@ -692,7 +693,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
n2: VNode,
container: HostNode,
anchor: HostNode,
parentComponent: ComponentInstance | null,
parentComponent: ComponentInternalInstance | null,
isSVG: boolean,
optimized: boolean = false
) {
@ -776,7 +777,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
c2: VNodeChildren,
container: HostNode,
anchor: HostNode,
parentComponent: ComponentInstance | null,
parentComponent: ComponentInternalInstance | null,
isSVG: boolean,
optimized: boolean
) {
@ -813,7 +814,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
c2: VNodeChildren,
container: HostNode,
parentAnchor: HostNode,
parentComponent: ComponentInstance | null,
parentComponent: ComponentInternalInstance | null,
isSVG: boolean,
optimized: boolean
) {
@ -1035,7 +1036,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
function unmount(
vnode: VNode,
parentComponent: ComponentInstance | null,
parentComponent: ComponentInternalInstance | null,
doRemove?: boolean
) {
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
// beforeUnmount hook
if (bum !== null) {
@ -1107,7 +1111,7 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
function unmountChildren(
children: VNode[],
parentComponent: ComponentInstance | null,
parentComponent: ComponentInternalInstance | null,
doRemove?: boolean,
start: number = 0
) {
@ -1125,8 +1129,8 @@ export function createRenderer(options: RendererOptions): RootRenderFunction {
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)

View File

@ -14,14 +14,14 @@ return applyDirectives(h(comp), [
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
@ -50,7 +50,7 @@ const valueCache = new WeakMap<Directive, WeakMap<any, any>>()
function applyDirective(
props: Record<any, any>,
instance: ComponentInstance,
instance: ComponentInternalInstance,
directive: Directive,
value?: any,
arg?: string,
@ -92,7 +92,7 @@ function applyDirective(
}
// Directive, value, argument, modifiers
type DirectiveArguments = Array<
export type DirectiveArguments = Array<
| [Directive]
| [Directive, any]
| [Directive, any, string]
@ -115,7 +115,7 @@ export function applyDirectives(vnode: VNode, directives: DirectiveArguments) {
export function invokeDirectiveHook(
hook: Function | Function[],
instance: ComponentInstance | null,
instance: ComponentInternalInstance | null,
vnode: VNode,
prevVNode: VNode | null = null
) {
@ -125,11 +125,11 @@ export function invokeDirectiveHook(
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)
}
}

View File

@ -1,10 +1,10 @@
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,
@ -32,27 +32,27 @@ export const ErrorTypeStrings: Record<number | string, string> = {
[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
@ -66,8 +66,8 @@ export function callWithErrorHandling(
export function callWithAsyncErrorHandling(
fn: Function,
instance: ComponentInstance | null,
type: AllErrorTypes,
instance: ComponentInternalInstance | null,
type: ErrorTypes,
args?: any[]
) {
const res = callWithErrorHandling(fn, instance, type, args)
@ -81,12 +81,12 @@ export function callWithAsyncErrorHandling(
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
@ -108,7 +108,7 @@ export function handleError(
callWithErrorHandling(
appErrorHandler,
null,
ErrorTypes.APP_ERROR_HANDLER,
ErrorCodes.APP_ERROR_HANDLER,
[err, exposedInstance, errorInfo]
)
return
@ -117,7 +117,7 @@ export function handleError(
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 (

View File

@ -47,7 +47,7 @@ h('div', {}, 'foo') // text
h('div', null, {})
**/
interface Props {
export interface RawProps {
[key: string]: any
key?: string | number
ref?: string | Ref<any> | Function
@ -57,7 +57,14 @@ interface Props {
[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> {
@ -68,63 +75,63 @@ 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

View File

@ -43,9 +43,26 @@ export { resolveComponent, resolveDirective } from './componentOptions'
// 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'

View File

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

View File

@ -6,7 +6,7 @@ import {
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'
@ -40,7 +40,7 @@ export interface VNode {
key: string | number | null
ref: string | Function | null
children: NormalizedChildren
component: ComponentInstance | null
component: ComponentInternalInstance | null
// DOM
el: HostNode | null

View File

@ -1,5 +1,5 @@
import { VNode } from './vnode'
import { Data, ComponentInstance } from './component'
import { Data, ComponentInternalInstance } from './component'
import { isString } from '@vue/shared'
import { toRaw } from '@vue/reactivity'
@ -77,7 +77,7 @@ function getComponentTrace(): ComponentTraceStack {
recurseCount: 0
})
}
const parentInstance: ComponentInstance | null = (currentVNode.component as ComponentInstance)
const parentInstance: ComponentInternalInstance | null = (currentVNode.component as ComponentInternalInstance)
.parent
currentVNode = parentInstance && parentInstance.vnode
}
@ -108,7 +108,9 @@ function formatTraceEntry(
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]

View File

@ -1,21 +1,13 @@
# @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')
```

View File

@ -1,9 +1,9 @@
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
@ -45,7 +45,7 @@ export function patchEvent(
name: string,
prevValue: EventValue | null,
nextValue: EventValue | null,
instance: ComponentInstance | null
instance: ComponentInternalInstance | null
) {
const invoker = prevValue && prevValue.invoker
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) => {
// async edge case #6566: inner click event triggers patch, event handler
// attached to outer element during patch, and triggered again. This
@ -77,7 +77,7 @@ function createInvoker(value: any, instance: ComponentInstance | null) {
callWithAsyncErrorHandling(
value[i],
instance,
ErrorTypes.NATIVE_EVENT_HANDLER,
ErrorCodes.NATIVE_EVENT_HANDLER,
args
)
}
@ -85,7 +85,7 @@ function createInvoker(value: any, instance: ComponentInstance | null) {
callWithAsyncErrorHandling(
value,
instance,
ErrorTypes.NATIVE_EVENT_HANDLER,
ErrorCodes.NATIVE_EVENT_HANDLER,
args
)
}