diff --git a/packages/reactivity/README.md b/packages/reactivity/README.md index d633eb6f3..b8fa70c90 100644 --- a/packages/reactivity/README.md +++ b/packages/reactivity/README.md @@ -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: diff --git a/packages/reactivity/src/effect.ts b/packages/reactivity/src/effect.ts index 9c701f3e9..76ff3f1e6 100644 --- a/packages/reactivity/src/effect.ts +++ b/packages/reactivity/src/effect.ts @@ -9,23 +9,21 @@ export interface ReactiveEffect { raw: Function deps: Array 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') diff --git a/packages/reactivity/src/index.ts b/packages/reactivity/src/index.ts index 60103d4cb..febfac082 100644 --- a/packages/reactivity/src/index.ts +++ b/packages/reactivity/src/index.ts @@ -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, diff --git a/packages/runtime-core/README.md b/packages/runtime-core/README.md index 58b4e4744..e36fb1cbf 100644 --- a/packages/runtime-core/README.md +++ b/packages/runtime-core/README.md @@ -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. diff --git a/packages/runtime-core/__tests__/directives.spec.ts b/packages/runtime-core/__tests__/directives.spec.ts index 586b39e32..4ce5e577e 100644 --- a/packages/runtime-core/__tests__/directives.spec.ts +++ b/packages/runtime-core/__tests__/directives.spec.ts @@ -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 = { diff --git a/packages/runtime-core/src/apiApp.ts b/packages/runtime-core/src/apiApp.ts index 94a05bb41..a42c69f2d 100644 --- a/packages/runtime-core/src/apiApp.ts +++ b/packages/runtime-core/src/apiApp.ts @@ -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(key: InjectionKey | 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.` diff --git a/packages/runtime-core/src/apiCreateComponent.ts b/packages/runtime-core/src/apiCreateComponent.ts index 098452e1e..a35ea7662 100644 --- a/packages/runtime-core/src/apiCreateComponent.ts +++ b/packages/runtime-core/src/apiCreateComponent.ts @@ -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 ): { - new (): ComponentRenderProxy + new (): ComponentPublicInstance } // overload 3: object format with array props declaration @@ -44,7 +44,7 @@ export function createComponent< >( options: ComponentOptionsWithArrayProps ): { - new (): ComponentRenderProxy< + new (): ComponentPublicInstance< { [key in PropNames]?: unknown }, RawBindings, D, @@ -65,7 +65,7 @@ export function createComponent< options: ComponentOptionsWithProps ): { // for Vetur and TSX support - new (): ComponentRenderProxy< + new (): ComponentPublicInstance< ExtractPropTypes, RawBindings, D, diff --git a/packages/runtime-core/src/apiLifecycle.ts b/packages/runtime-core/src/apiLifecycle.ts index d2644b636..25bc21747 100644 --- a/packages/runtime-core/src/apiLifecycle.ts +++ b/packages/runtime-core/src/apiLifecycle.ts @@ -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) } diff --git a/packages/runtime-core/src/apiWatch.ts b/packages/runtime-core/src/apiWatch.ts index 3c14d915f..e2ebd0bdc 100644 --- a/packages/runtime-core/src/apiWatch.ts +++ b/packages/runtime-core/src/apiWatch.ts @@ -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 diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index db0f72374..59dc958b4 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -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 } = {} } }) -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 diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 790f1fcfd..60c2033ab 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -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?: undefined -} & ThisType> +} & ThisType> export type ComponentOptionsWithArrayProps< PropNames extends string = string, @@ -79,7 +79,7 @@ export type ComponentOptionsWithArrayProps< Props = { [key in PropNames]?: unknown } > = ComponentOptionsBase & { props: PropNames[] -} & ThisType> +} & ThisType> export type ComponentOptionsWithProps< PropsOptions = ComponentPropsOptions, @@ -90,7 +90,7 @@ export type ComponentOptionsWithProps< Props = ExtractPropTypes > = ComponentOptionsBase & { props: PropsOptions -} & ThisType> +} & ThisType> 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) => D) + data?: D | ((this: ComponentPublicInstance) => 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) } diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index 488c84704..e7969bb85 100644 --- a/packages/runtime-core/src/componentProps.ts +++ b/packages/runtime-core/src/componentProps.ts @@ -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

= { [K in keyof P]: Prop | null } -type Prop = PropOptions | PropType +export type Prop = PropOptions | PropType interface PropOptions { type?: PropType | true | null @@ -90,7 +90,7 @@ type NormalizedPropsOptions = Record // - else: everything goes in `props`. export function resolveProps( - instance: ComponentInstance, + instance: ComponentInternalInstance, rawProps: any, _options: ComponentPropsOptions | void ) { diff --git a/packages/runtime-core/src/componentProxy.ts b/packages/runtime-core/src/componentPublicInstanceProxy.ts similarity index 87% rename from packages/runtime-core/src/componentProxy.ts rename to packages/runtime-core/src/componentPublicInstanceProxy.ts index b95806231..409cf496c 100644 --- a/packages/runtime-core/src/componentProxy.ts +++ b/packages/runtime-core/src/componentPublicInstanceProxy.ts @@ -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 & @@ -29,8 +29,8 @@ export type ComponentRenderProxy< ExtracComputedReturns & 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 diff --git a/packages/runtime-core/src/componentRenderUtils.ts b/packages/runtime-core/src/componentRenderUtils.ts index b988f67df..0534183cd 100644 --- a/packages/runtime-core/src/componentRenderUtils.ts +++ b/packages/runtime-core/src/componentRenderUtils.ts @@ -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 diff --git a/packages/runtime-core/src/componentSlots.ts b/packages/runtime-core/src/componentSlots.ts index 2cff5e0b7..ba4cb2152 100644 --- a/packages/runtime-core/src/componentSlots.ts +++ b/packages/runtime-core/src/componentSlots.ts @@ -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 diff --git a/packages/runtime-core/src/createRenderer.ts b/packages/runtime-core/src/createRenderer.ts index a70dce625..987f0ac7e 100644 --- a/packages/runtime-core/src/createRenderer.ts +++ b/packages/runtime-core/src/createRenderer.ts @@ -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, oldRef: string | Function | Ref | 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) diff --git a/packages/runtime-core/src/directives.ts b/packages/runtime-core/src/directives.ts index 41a184efb..6acf27c4a 100644 --- a/packages/runtime-core/src/directives.ts +++ b/packages/runtime-core/src/directives.ts @@ -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>() function applyDirective( props: Record, - 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) } } diff --git a/packages/runtime-core/src/errorHandling.ts b/packages/runtime-core/src/errorHandling.ts index 42cc356da..7a614c852 100644 --- a/packages/runtime-core/src/errorHandling.ts +++ b/packages/runtime-core/src/errorHandling.ts @@ -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 = { [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 ( diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index 5ebb485d9..fbb43c13d 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -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 | 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

{ @@ -68,63 +75,63 @@ interface Constructor

{ // 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

( type: FunctionalComponent

, - 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

( type: ComponentOptionsWithoutProps

, - props?: (Props & P) | null, - children?: Children | RawSlots + props?: (RawProps & P) | null, + children?: RawChildren | RawSlots ): VNode export function h

( type: ComponentOptionsWithArrayProps

, // 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

( type: ComponentOptionsWithProps

, - props?: (Props & ExtractPropTypes

) | null, - children?: Children | RawSlots + props?: (RawProps & ExtractPropTypes

) | 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

( type: Constructor

, - props?: (Props & P) | null, - children?: Children | RawSlots + props?: (RawProps & P) | null, + children?: RawChildren | RawSlots ): VNode // Actual implementation diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index c5f7d1585..46d0406fd 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -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' diff --git a/packages/runtime-core/src/scheduler.ts b/packages/runtime-core/src/scheduler.ts index 6f8ccaa91..3a73af959 100644 --- a/packages/runtime-core/src/scheduler.ts +++ b/packages/runtime-core/src/scheduler.ts @@ -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() diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts index 2bee91c10..f81533e75 100644 --- a/packages/runtime-core/src/vnode.ts +++ b/packages/runtime-core/src/vnode.ts @@ -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 diff --git a/packages/runtime-core/src/warning.ts b/packages/runtime-core/src/warning.ts index 138b565b0..24e6d9c72 100644 --- a/packages/runtime-core/src/warning.ts +++ b/packages/runtime-core/src/warning.ts @@ -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] diff --git a/packages/runtime-dom/README.md b/packages/runtime-dom/README.md index e351b743e..07cbf6128 100644 --- a/packages/runtime-dom/README.md +++ b/packages/runtime-dom/README.md @@ -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') ``` diff --git a/packages/runtime-dom/src/modules/events.ts b/packages/runtime-dom/src/modules/events.ts index d6663fd53..f283b9922 100644 --- a/packages/runtime-dom/src/modules/events.ts +++ b/packages/runtime-dom/src/modules/events.ts @@ -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 ) }