The vuE-next [1] version has come to 3.1.2 unwittingly, recently compared with the source code to learn Vue3 global Api, while learning to sort down, I hope to make progress with you.

Let’s take a look at them in terms of official definition, usage, and source code analysis.

The following is about the Vue3 global Api. If you have a better understanding or idea, feel free to leave a comment in the comments section and I will reply to each one

Global API A global API is a method of mounting directly on a Vue. In Vue, there are 13 global apis. Respectively is:

Createapp returns an application instance that provides the application context; H returns a “virtual node; Definecomponent returns the options object, under TS, that gives the component the correct argument type inference; Defineasynccomponent creates an asynchronous component that loads only when needed; Resolvecomponent resolves the component by the name of the component passed in; Resolvedynamiccomponent returns a parsed Component or a new VNode. Resolvedirective resolves a directive by its name; Withdirectives Returns a VNode containing the application directives; Createrenderer cross-platform custom rendering; Nexttick delays calling the callback function until the next DOM update. Mergeprops combines multiple objects containing VNode Prop into a single object; Usecssmodule accesses CSS modules. Version Displays the version of the installed Vue. CreateApp Returns an application instance that provides context for the application. The entire tree of components mounted by the application instance shares the same context.

CreateApp, as the name suggests, acts as the startup function for vUE and returns an application instance. Each VUE application first creates a new application instance using the following functions. Most methods exposed by an application instance return the same instance and can be called in chain. Such as:

Vue.createapp ({}).component(‘SearchInput’, SearchInputComponent) Copy code usage first argument: receives a root component option

The second parameter: Import {createApp, h, nextTick} from ‘vue’ const app = createApp({data() {return {… } }, methods: {… }, computed: {… }… }, {username: ‘Evan’})

EnsureRenderer () : ensureRenderer() : ensureRenderer() : ensureRenderer() : ensureRenderer() : ensureRenderer() : ensureRenderer() : ensureRenderer() : ensureRenderer() : ensureRenderer() : ensureRenderer() : ensureRenderer() : Line 419-424 content [3][4] baseCreateRenderer() : 448-2418 [4][5] app._component: [1] export const createApp = ((… Args) => {// create an app object with ensureRenderer().createApp() above the source location [2] // -> The ensureRenderer method calls createRenderer from runtime-core above the source location [3] // -> createRenderer(HostNode, HostElement), two generic parameters HostNode(a node in the host environment) and HostElement(an element in the host environment), corresponding to the host environment. // -> reateRenderer(create a Renderer instance with the (optional) option.) [4] // -> baseCreateRenderer finally returns the render Hydrate createApp function, The generated render is passed to createAppAPI, hydrate is optional and will be used in SSR scenarios. const app = ensureRenderer().createApp(… args)

InjectNativeTagCheck (app) if (DEV) {// DEV check component name for native tag or SVG tag injectNativeTagCheck(app) // DEV check component name for deprecated CompilerOptions. Show warning injectCompilerOptionsCheck (app)}

Const {mount} = app. Mount = (containerOrSelector: Element | ShadowRoot | string): Any => {// container is a real DOM element, and normalizeContainer uses document.querySelector to handle arguments passed in, If the element does not exist in the DEV environment or is a shadow DOM and the mode state is closed, Const container = normalizeContainer(containerOrSelector) // Return if (! container) return

// App. _component is the first parameter to createApp in the global API. [5] Const Component = app._component // Component is not a function and does not include render, template if (! isFunction(component) && ! component.render && ! Component.template) {// Unsafe situation // Cause: JS expressions may be executed in DOM templates. // The user must ensure that the internal DOM template is trusted. If it is // the template should not contain any user data. // Use DOM innerHTML as component.template content Component. template = container.innerhtml // 2. If the name is not a V-cloak state and the attribute name contains v-, :, @, the vUE document link prompts if (__COMPAT__ && __DEV__) {for (let I = 0; i < container.attributes.length; i++) { const attr = container.attributes[i] if (attr.name ! == 'v-cloak' && /^(v-|:|@)/.test(attr.name)) { compatUtils.warnDeprecation( DeprecationTypes.GLOBAL_MOUNT_CONTAINER, Null) break}}}} // Clear content before mount container.innerHTML = "// True mount (element, Const proxy = mount(container, false, Container Instanceof SVGElement) if (Container Instanceof Element) {// Remove the V-cloak instruction on the Element Container. RemoveAttribute (' v - cloak ') / / set properties data - v - app container. The setAttribute (' data - v - app ', ')} return proxyCopy the code

}

return app }) as CreateAppFunction

Official definition: Returns a “virtual node”, often abbreviated to VNode: a common object that contains information describing to Vue what kind of nodes it should render on the page, including descriptions of all child nodes. It is intended for hand-written rendering functions;

What does h stand for? According to grandfather’s reply, the meaning of H is as follows:

It comes from the term “hyperscript”, which is commonly used in many virtual-dom implementations. “Hyperscript” itself stands for “script that generates HTML structures” because HTML is the acronym for “hyper-text markup language”.

It comes from the term “Hyperscript,” which is used for many virtual DOM implementations. “Hyperscript” itself stands for “script that generates HTML structure,” because HTML is an acronym for “Hypertext Markup Language.”

github.com/vuejs/babel… [7]

Both the h() and createVNode() functions create DOM nodes. They do the same thing, but in VUE3 the createVNode() function has more functions than the H () function and has been optimized for performance, rendering nodes faster.

Usage First argument: HTML tag name, component, asynchronous component, or functional component. A comment is rendered using a function that returns NULL. This parameter is required.

The second argument: an object that corresponds to the attribute, prop, class, style, and event that we will use in the template. Optional.

Third argument: child VNode, generated using h(), or using a string to get a “text VNode”, or an object with a slot. Optional.

// Usage example h(‘div’, {}, [‘Some text comes first.’, h(‘h1’, ‘A headline’), h(MyComponent, {someProp: ‘foobar’})])

[6] export function h(type: any, propsOrChildren? : any, children? : any): VNode {const l = arguments. Length // If the arguments are two if (l === 2) {// If (isObject(propsOrChildren) &&! IsArray (propsOrChildren) {// All VNode objects have a __v_isVNode attribute, which isVNode methods use to determine whether they are VNode objects. if (isVNode(propsOrChildren)) { return createVNode(type, null, [propsOrChildren])} return createVNode(type, PropsOrChildren)} else {// Ignore props attribute return createVNode(type, null, propsOrChildren) } } else { if (l > 3) { // Array.prototype.slice.call(arguments, The arguments are converted to an array object. The arguments can be used as an array object. Let the arguments have slice children = Array () method. The prototype. Slice. The call (the arguments, } else if (l === 3 && isVNode(children)) { Children = [children]} // Return createVNode(type, propsOrChildren, children)}} Define defineComponent DefineComponent only returns the objects passed to it. In terms of type, however, the returned value has a synthesized type constructor for manual rendering functions, TSX, and IDE tool support

DefinComponent is mainly used to help Vue correctly infer the parameter types of the Setup () component under TS

Introduce defineComponent() to correctly infer the parameter types of the Setup () component;

DefineComponent can be used correctly for functions such as props and array props.

Usage ** Parameters: ** An object with component options or a setup function whose name will be used as the component name

// We need to declare the related data type. // Declare the props and return Data types interface Data {[key: string]: Export default {setup(props: Data): Data {//… return { // … DefineComponent can accept explicit custom props interfaces or automatic inferences from attribute validation objects.

Usage Example 1: import {defineComponent} from ‘vue’

const MyComponent = defineComponent({ data() { return { count: 1 } }, methods: { increment() { this.count++ } } })

// Usage Example 2: // Not only for setup, as long as the Vue API itself, defineComponent can automatically deduce for you. import { defineComponent } from ‘vue’ export default defineComponent({ setup (props, context) { // …

return { // … }}} GitHub address: source file location [9]

. . . Export default defineComponent({}) is equivalent to export default defineComponent({}). Setup must be a function and props must be undefined or an object. export function defineComponent(options: unknown) { return isFunction(options) ? {setup: options, name: options.name} : options} Copy code defineAsyncComponent Official definition: Create an asynchronous component that is loaded only when needed.

Usage argument: Accepts a factory function that returns a Promise. The Promise’s resolve callback should be invoked after the server returns the component definition.

Const asyncModal = () => import(‘./ modal.vue ‘) // or const asyncModal = {component: () => import(‘./Modal.vue’), delay: 200, timeout: 3000, error: ErrorComponent, loading: LoadingComponent }

// Now, in Vue 3, since functional components are defined as pure functions, the definition of asynchronous components needs to be explicitly defined by wrapping them in the new defineAsyncComponent helper method: import { defineAsyncComponent } from ‘vue’ import ErrorComponent from ‘./components/ErrorComponent.vue’ import LoadingComponent from ‘./components/LoadingComponent.vue’

// Async component with no option const asyncModal = defineAsyncComponent(() => import(‘./ modal.vue ‘))

// Asynchronous components with options. Another change to 2.x is that the Component option is now renamed loader to accurately convey that component definitions cannot be provided directly. Note: defineAsyncComponent cannot be used on Vue routers! const asyncModalWithOptions = defineAsyncComponent({ loader: () => import(‘./Modal.vue’), delay: 200, timeout: 3000, errorComponent: errorComponent, loadingComponent: loadingComponent})

Export function defineAsyncComponent< T extends Component = {new (): ComponentPublicInstance}

(source: AsyncComponentLoader | AsyncComponentOptions): T {

if (isFunction(source)) { source = { loader: Source}} // Async component const {loader, loadingComponent, errorComponent, delay = 200, timeout, // undefined = never times out suspensible = true, onError: userOnError } = source

let pendingRequest: Promise | null = null let resolvedComp: ConcreteComponent | undefined

Let retries = 0 // load to obtain component content const retry = () => {retries++ pendingRequest = null return load()}

const load = (): Promise => { let thisRequest: Promise return (// Return if pendingRequest exists, Otherwise the loader () pendingRequest | | (thisRequest = pendingRequest = loader () / / failure scenario processing. Catch (err = > {err = err instanceof Error ? err : New Error(String(err)) if (userOnError) {return new Promise((resolve, reject) => { const userRetry = () => resolve(retry()) const userFail = () => reject(err) userOnError(err, userRetry, userFail, retries + 1) }) } else { throw err } }) .then((comp: Any) => {// ThisRequest = pendingRequest = loader(), loader() is initially in the wait state, assigns value to pendingRequest, at thisRequest moment they are in the equal wait state, PendingRequest has changed when entering then, so return pendingRequest if (thisRequest! PendingRequest == pendingRequest && pendingRequest) {return pendingRequest} comp) { warn( Async component loader resolved to undefined. + If you are using retry(), make sure to return its return value. ) } // interop module default if ( comp && (comp.__esModule || Comp [symbol.tostringTag] === ‘Module’)) {comp = comp.default} // Warning if (DEV && comp &&! isObject(comp) && ! isFunction(comp)) { throw new Error(Invalid async component load result: ${comp}) } resolvedComp = comp return comp })) ) }

Return defineComponent({__asyncLoader: load, // asyncloader: load ‘AsyncComponentWrapper’, // the component has a setup method to go setup logic setup() {const instance = currentInstance!

// already resolved if (resolvedComp) { return () => createInnerComp(resolvedComp! , instance) } const onError = (err: Error) => { pendingRequest = null handleError( err, instance, ErrorCodes.ASYNC_COMPONENT_LOADER, ! errorComponent /* do not throw in dev if user provided error component */ ) } // suspense-controlled or SSR. // Suspense (__FEATURE_SUSPENSE__ && Suspensible &&) returns only the promise result if the parent component is suspense instance.suspense) || (__NODE_JS__ && isInSSRComponentSetup) ) { return load() .then(comp => { return () => createInnerComp(comp, instance) }) .catch(err => { onError(err) return () => errorComponent ? createVNode(errorComponent as ConcreteComponent, { error: err }) : null }) } const loaded = ref(false) const error = ref() const delayed = ref(!! delay) if (delay) { setTimeout(() => { delayed.value = false }, delay) } if (timeout ! = null) { setTimeout(() => { if (! loaded.value && ! error.value) { const err = new Error( `Async component timed out after ${timeout}ms.` ) onError(err) error.value = err } }, Then (() => {// Promise returns successfully and triggers the component to update and rerender the component. Value = true}). Catch (err) Value = err}) // The function returned will be treated as the render function of the component instance. Return () => {render initial execution triggers loaded's dependency collection if (loaded.value && resolvedComp) { return createInnerComp(resolvedComp, instance) } else if (error.value && errorComponent) { return createVNode(errorComponent as ConcreteComponent, { error: error.value }) } else if (loadingComponent && ! delayed.value) { return createVNode(loadingComponent as ConcreteComponent) } } }Copy the code

}) as any }

Official definition of resolveComponent: Allows resolution of component by name, returning a Component, if available in the current application instance. If not found, the received parameter name is returned.

Usage argument: The name of the loaded component

const app = createApp({}) app.component(‘MyComponent’, { /* … */ })

Import {resolveComponent} from ‘vue’ render() {const MyComponent = resolveComponent(‘MyComponent’) Making address:

[7][11] resolveAsset() : [7] export function resolveComponent(name: string, maybeSelfReference? : boolean ): ConcreteComponent | string { return resolveAsset(COMPONENTS, name, true, maybeSelfReference) || name }

[8] function resolveAsset(type: AssetTypes, name: String, warnMissing = true, maybeSelfReference = false) { Does not exist for the current instance const instance = currentRenderingInstance | | currentInstance if (instance) {const Component = instance. The type

If (type === COMPONENTS) {// getComponentName first checks whether the Component argument passed in is a function. Name const selfName = getComponentName(Component) if (// Camelize uses replace, re /-(\w)/gname, ToUpperCase () is converted to capitalize // capitalize: STR. CharAt (0). The toUpperCase () + STR. Slice (1) capitalize the first letter + processed characters selfName && (selfName = = = name | | selfName = = = camelize (name) | | selfName = = = capitalize (camelize (name)))) {return Component}} const res = / / registered [type] / / check first instance, It is resolved as option API resolve (instance [type] | | (Component as ComponentOptions) [type]. Registered name) | | / / global resolve (the instance. The appContext [type], name) if (! res && maybeSelfReference) { return Component } if (__DEV__ && warnMissing && ! res) { warn(`Failed to resolve ${type.slice(0, -1)}: ${name}`) } return resCopy the code

} else if (DEV) {// If the instance does not exist, and in the DEV environment warning: can only be used in render() or setup() warn( resolve${capitalize(type.slice(0, -1))} + can only be used in render() or setup().)}} Returns a parsed Component or newly created VNode with the Component name as the node label. If Component is not found, a warning is issued.

Usage argument: Takes one argument: Component

import { resolveDynamicComponent } from ‘vue’ render () { const MyComponent = resolveDynamicComponent(‘MyComponent’) } GitHub address:

[9][13] resolveAsset() : [14] // The source location is above [9] // This function is used to parse dynamic components. In resolveDynamicComponent, if the component argument is a string, The resolveAsset method is called to resolve the component, and if the resolveAsset function fails to retrieve the component, it returns the value of the current Component argument. [1] export function resolveDynamicComponent(component: unknown): VNodeTypes { if (isString(component)) { return resolveAsset(COMPONENTS, component, False) | | component} else {/ / invalid type will trigger a warning, but if the component parameters of type string, will return to the component | | NULL_DYNAMIC_COMPONENT this line statement execution results, The NULL_DYNAMIC_COMPONENT value is a Symbol object. return (component || NULL_DYNAMIC_COMPONENT) as any } }

ResolveDirective allows resolution of a directive by its name if it is available in the current application instance. Return a Directive. If not found, undefined is returned.

Usage First argument: the name of the loaded instruction. GitHub address:

ResolveDirective () : lines 43-48 [10][15] resolveAsset() : lines 62-123 [16] /**

  • See [10] above for the source location

*/ export function resolveDirective(name: string): Directive | undefined {/ / and then call resolveAsset method to parse the components described above, resolveAsset function analytical see [8] above location return resolveAsset (DIRECTIVES, Name)} Duplicate code withDirectives Official definition: Allow directives to be applied to VNode. Returns a VNode containing the application instructions.

Usage The first argument: a virtual node, usually created using h()

Second argument: an array of instructions, each of which is itself an array and can define up to 4 indexes. import { withDirectives, resolveDirective } from ‘vue’ const foo = resolveDirective(‘foo’) const bar = resolveDirective(‘bar’)

Return withDirectives(H (‘div’), [[foo, this.x], [bar, this.y]])

[11] export function with cache (vnode: T, cache: DirectiveArguments ): T {// Get the current instance const internalInstance = currentRenderingInstance if (internalInstance === null) {// If used outside the render function WithDirectives () throws an exception: DEV && warn(withDirectives can only be used inside render functions.) return vnode } const instance = // Bind the DIRS property on vNode and walk through the incoming directives const Bindings: DirectiveBinding[] = vnode.dirs || (vnode.dirs = []) for (let i = 0; i < directives.length; i++) { let [dir, value, arg, modifiers = EMPTY_OBJ] = directives[i] if (isFunction(dir)) { dir = { mounted: dir, updated: dir } as ObjectDirective } bindings.push({ dir, instance, value, oldValue: void 0, arg, modifiers }) } return vnode }

The createRenderer function takes two generic parameters, HostNode and HostElement, corresponding to the Node and Element types in the host environment.

Usage The first parameter: HostNode Node in the host environment. The second argument: Element The Element in the host environment. // For runtime-DOM, HostNode will be the DOM Node interface, and HostElement will be the DOM Element interface. // Custom renderers can pass platform-specific types like this:

// createRenderer(HostNode, HostElement), two generic parameters HostNode(node in the host environment) and HostElement(element in the host environment), corresponding to the host environment. // reateRenderer(Create an instance of Renderer with the (optional) option.) BaseCreateRenderer export function createRenderer< HostNode = RendererNode, HostElement = RendererElement

(options: RendererOptions<HostNode, HostElement>) {

BaseCreateRenderer <HostNode, HostElement>(options)} createRenderer () : Line 419-424 content [3][18] baseCreateRenderer() : [4][19] Function createRenderer< HostNode = RendererNode, HostElement = RendererElement

(options: RendererOptions<HostNode, HostElement>) {

return baseCreateRenderer<HostNode, HostElement>(options) }

// baseCreateRenderer contains the core code for rendering, and the API is removed from the platform feature Options to implement methods such as patch, processing nodes, processing components, updating components, installing component instances, etc. Finally, a Renderer object is returned. function baseCreateRenderer( options: RendererOptions, createHydrationFns? : typeof createHydrationFunctions ): any { // compile-time feature flags check if (ESM_BUNDLER && ! TEST) { initFeatureFlags() }

if (DEV || FEATURE_PROD_DEVTOOLS) { const target = getGlobalThis() target.VUE = true setDevtoolsHook(target.VUE_DEVTOOLS_GLOBAL_HOOK) }

const { insert: hostInsert, remove: hostRemove, patchProp: hostPatchProp, forcePatchProp: hostForcePatchProp, createElement: hostCreateElement, createText: hostCreateText, createComment: hostCreateComment, setText: hostSetText, setElementText: hostSetElementText, parentNode: hostParentNode, nextSibling: hostNextSibling, setScopeId: hostSetScopeId = NOOP, cloneNode: hostCloneNode, insertStaticContent: hostInsertStaticContent } = options … . . // Return the render hydrate createApp function, which generates render to createAppAPI. This is an optional parameter, used in SSR scenarios. Return {render, hydrate, createApp: createAppAPI(render, hydrate)}} Copy code nextTick Official definition: Delay the callback until after the next DOM update cycle. Use it immediately after you have changed some data to wait for DOM updates.

import { createApp, nextTick } from ‘vue’

const app = createApp({ setup() { const message = ref(‘Hello! ‘) const changeMessage = async newMessage => { message.value = newMessage await nextTick() console.log(‘Now DOM is Updated ‘)}}})

NextTick () : Lines 42-48 [20] // The source is at the top

// Create an asynchronous task directly, but changing dom properties is also an asynchronous strategy, Vue2.x does not support the promise attribute (MutationObserver). SetImmediate mediate (Mediate) does not support setTimeout (IE11). So nextTick uses Promise directly

// Vue performs DOM updates asynchronously. Whenever a data change is observed, Vue opens a queue and buffers all data changes that occur in the same event loop. If the same watcher is triggered more than once, it will only be pushed into the queue once. This removal of duplicate data while buffering is important to avoid unnecessary computation and DOM manipulation. Then, in the next event loop, “TICK,” Vue refreshes the queue and performs the actual (de-duplicated) work.

export function nextTick( this: ComponentPublicInstance | void, fn? : () => void ): Promise { const p = currentFlushPromise || resolvedPromise return fn ? p.then(this ? fn.bind(this) : fn) : p }

// If you set vm.someData = ‘new value’, the component will not be rerendered immediately. When the queue is refreshed, the component updates with the next “tick” when the event loop queue is empty. If you want to do something after a DOM status update, you can use vue.nexttick (callback) immediately after the data changes. Copy code mergeProps official definition: To merge multiple objects containing VNode prop into a single object. It returns a newly created object, and the object passed as a parameter is not modified.

Usage parameters: Can pass an unlimited number of objects

import { h, mergeProps } from ‘vue’ export default { inheritAttrs: False, render() {const props = mergeProps({// This class will be merged with other classes in attrs. Class: ‘active’}, this.attrs) return h(‘div’, props)}} class: ‘active’}, this.attrs) return h(‘div’, props)}

MergeProps () : 687-712 line [21] Export function mergeProps(… args: (Data & VNodeProps)[]) {// extend is object.assign, Const ret = extend({}, args[0]) // iterate over args for (let I = 1; i < args.length; I ++) {const toMerge = args[I] for (const key in toMerge) {if (key === ‘class’) {// Merge class if (ret.class! == toMerge.class) { ret.class = normalizeClass([ret.class, ToMerge. Class])}} else if (key === ‘style’) {// Merge style ret.style = normalizeStyle([ret.style, ToMerge. Style])} else if (isOn(key) {, // Const existing = ret[key] const incoming = toMerge[key] if (existing ! == incoming) {// add ret[key] = existing? [].concat(existing as any, incoming as any) : incoming } } else if (key ! Ret [key] = toMerge[key]}} return ret} useCssModule Allows CSS modules to be accessed in the single-file component [23] function of Setup [22].

Usage parameter: name of the CSS module. The default is’ style ‘//useCssModule can only be used in render or setup functions. // useCssModule can only be used in render or setup functions. //useCssModule can only be used in render or setup functions. /* *

  • .

* */ // We can use const style = useCssModule(‘ aaa’) to get the corresponding content

// When you add a module to the module, the $style attribute is automatically injected into the component. .six color: red; } .one font-size:62px; }

$style = “$style”; $style = “$style”;

UseCssModule () : lines 1-30 [24]

import { warn, getCurrentInstance } from ‘@vue/runtime-core’ import { EMPTY_OBJ } from ‘@vue/shared’

/ / remove this. StyleexportfunctionuseCssModule (name = ‘style export function useCssModule (name = ‘styleexportfunctionuseCssModule (name =’ style ‘) : Record the < string, the string > {/ * if is Istanbul coverage testing out * / if (! GLOBAL) {// Get the current instance const instance = getCurrentInstance()! if (! Instance) {// useCssModule can only be used in render or setup functions. DEV && WARN (useCssModule must be called inside setup()) // EMPTY_OBJ is used to freeze objects with object.freeze () return EMPTY_OBJ} const Modules = instance.type.__cssModules // If CSS modules do not exist, warn if (! modules) { DEV && warn(Current instance does not have CSS modules injected.) return EMPTY_OBJ } const mod = Modules [name] // If there is no CSS module whose name is not found, warning if (! mod) { DEV && warn(Current instance does not have CSS module named “${name}”.) return EMPTY_OBJ } return mod as Record

} else {if (DEV) {warn(useCssModule() is not supported in the global build.)} return EMPTY_OBJ Version Official definition: Provides the version number of the installed Vue as a string.
,>

/ / the vue – next/packages/vue/package. The json version for granted, in use. The split (‘. ‘) [0]. Const version = Number(vue.version.split (‘.’)[0]) if (version === 3) {// Vue 3} else if (version === 2) {// Vue 2 } else {// Unsupported Vue version} Copy code Reference Vue- next-github [25]

Vue3 Official documentation [26]

Vue3 source code Analysis [27]

vue3 VNode[28]

That’s the end of this article.

If you have any questions or other comments please post them in the comments section below!

The code word is not easy. If you find this article helpful, I hope you can leave a comment and like it. Thank you very much

About this article

Source: Tz juejin.cn/post/697939…