preface
I’ve shared a lot of Vue source code analysis, including the implementation of reactive and reactive apis, implementation of several Vue built-in components, initialization and update of props and attrs, initialization of Vue and a little DOM diff. Maybe I missed something in this article. In this post I will fill in the blanks and some other details.
(position inruntime-core/src/components.ts
)
Added a
In the initialization process, a setupContext is generated before setup is executed. SetupContext is created by createSetupContext when setupContext is set to at least one parameter. This method passes the current component instance,
The expose function is created at the beginning of the function, which limits public instances of $parent, $root, etc., to access Prototype. This function can only be executed once in setup, as explained below.
The result is an object with attrs, slots, emit, expose in it. This object is passed later when setup is executed. It is available in setup for this reason. In case libraries like test-utils overwrite instance properties (this should not be done in PROD).
expose
The implementation of the
When the user calls Expose and passes an object, the object is attached to the instance (exposed property). The data in the object is what the user sees when accessing a public instance like $parent, but that’s not all. The Options API has an Expose option, which is an array, It also lists some public instances that can be accessed.
At runtime – core/SRC/componentOptions. Ts, will the two merging, first confirm that expose options is an array to merge, and the length is not zero, Take exposed on the instance and define each of the Expose options into the Exposed property, noting that each of the Expose options exists in publicThis, which is the proxy object for the current component instance.
If expose length is 0 and exposed on the instance does not exist, the exposed property on the instance defaults to an empty object.
expose
Access restrictions
Remember from one of the Vue3.2 DOM diff process analyses: initialization and update of props and attrs, that the $XXX property is actually a set of methods that are placed in an object, and the expose limitation is implemented in those methods.
For example, $parent and $root get the parent component through the getPublicInstance method, which calls the component instance proxy object that getExposeProxy may restrict.
This method gets the exposeProxy on the instance and creates it if it doesn’t exist. There are two layers of interception, the outer layer is seen in getExposeProxy, intercepting data access also intercepts $XXX access. The inner layer is data object access interception. This function is called in many places to restrict access to public instances.
Added two
CreateAttrsProxy is called in the previously returned object to create an attrs proxy that restricts attrs access changes. Markattrsemail exchange is called when accessed in dev to verify that $attrs is being used for tracing renderings, and if $attrs warnings are being used to suppress failures. The call changes accesseAttrs to true (ps: this is what attrs does when setup is executed)
At runtime – core/SRC/componentRenderUtils. Ts is the series of warning. AccesseAttrs is true to suppress these warnings,
Add three
After the setup function is executed, a setupResult is generated. This is an object containing the data returned by the user in the setup function, which can be used in templates and other Settings. Vue responds to this data object. Runtime -core/ SRC /components.ts
Instead of using the reactive processing in basehanlder. ts and collectionhanlder. ts, a separate reactive processing is used,
Fetch makes no difference. It is mainly modified, and both refs and Reactive are taken into account. The resulting responsive data object is mounted to the instance and is named setupState
Of course, the above is a return of a data object, but also return not a data object, and the rendering function and Proomise these two cases.
Let’s start with the case where a Promise is returned. First, the server render (SSR) also returns a Promise, so that the server renderer can wait for it. In Suspense, yibu uses built-in components to also return promises. After returning asynchronous results, the dependency scope of Suspense component instances will be closed regardless of the outcome, and an asynchronous DEP will be hung in Suspense, leaving the rest of the process to be handled internally.
What is returned is a render function that will be placed on the instance in hanlderSetupResult, which will then directly begin vuE2 compatibility processing.
Added four
Since added three said to the v2 compatible processing, added four will v2 compatible processing complete analysis again, location at runtime – core/SRC/componentOptions. Ts
The resolveMergedOptions function begins by executing resolveMergedOptions, passing the component instance to find all existing options apis for the instance, and merging global and local mixins and extends. The final configuration of the component is returned.
ShouldCacheAccess is used to cache attributes on the public proxy, but do not cache attributes on the public proxy during initialization. Then beforeCreate must be executed before accessing the options. Because the beforeCreate hook function can change the contents of the options internally.
Deconstruct each option in options and start working with the configuration in each option. The operation order is as follows: props > Inject > Methods > Data > computed > Watch.
Create a check function in dev mode to check for duplicate configurations in each option by caching the existing key and that option as a key-value pair, and then telling the user exactly where the duplicate key is.
- To deal with
inject
The props is outside the function and is done, so be inject first, get the inject configuration and pass it to the resolveInjection function.
The resolveInjection function gets the injection configuration. If it is an array, it will be normalized first, which is to turn the array into an object, so it is ok to transfer the object directly, which is not explained here.
Injectapi is useful in the treatment of Inject. Here, the implementation of injectAPI is explained in advance.
Get the current instance (if the current instance is null, then go back to the current render instance, so that the functional component can call it if it does not find the instance). The provides component must come from the parent component, while the root component is in the application context.
In this case, the user is not told that the key does not exist. In the second case, the user passes a default value and a third parameter (which may be true or false) without passing the key. What is returned depends on the third argument, true means that the default value is a factory function, and false means that the direct value is returned.
Go back to the ResolveInjection injection, get the value through injectAPI based on the injectAPI option that the user wrote, and then start putting it into the context CTX.
If the value is ref, there is a configuration in Vue :unwrapInjectRef (true) automatically expands ref and uses Object.defineProperty to define CTX. It will tell the user to change unwrapInjectRef to true. This will be a new behavior, but temporary, and may not be needed in later versions. If the data is not ref, it will be put into CTX normally. Function final check whether repeat, inject processing is completed.
- To deal with
methods
The next step is to process the methods in the methods option, which are written by the user, and the processing in Vue is also very simple. The method option is traversed, and each time one is taken out, the first step is to determine whether it is a function or not, not to do any processing and directly report a warning, but to define them on CTX. And change the method’s this to the proxy object for the current instance, so this is the current component instance when the method is called. Finally, verify whether there is duplication. The methods processing is complete.
- To deal with
data
Now it is the turn of data. In Vue3.2 and later, the data option recommends function form rather than object form. Executing the data function changes this to the proxy object of the current component instance and passes it into the function.
After returning the data object, now reactive processing, then validation, is performed to expose CTX to exclude and exclude properties beginning with $and _. Data processing is complete.
Data processing is complete, indicating that state initialization is complete and cache access is started.
- To deal with
computed
options
Because the calculated attribute must have get, and the set may or may not, get and set need to be handled separately. And because users can write objects or functions directly, they need to determine whether they are functions or objects. Functions can be directly bound to this, and objects need to take get or set from it and then bind this. Generates new sets and GETS for computed API execution, returns the result of get execution, defines the values in the context, and checks for duplicate keys.
- To deal with
watch
options
The watch option is nothing to analyze. The createWatcher function is executed, internally generating the watcher via v3’s Watch API. It should be noted that the observation object written by the user needs to be judged in detail, for example, in the form of an array, that is, multiple observation objects need to be traversed, and then createWatcher is executed for each observation object.
- To deal with
provide
The provide API takes the current component instance and gets the provides in the current component instance and the parent component’s provides. By default, the instance inherits its parent’s provider object, but when it needs to provide its own value, It creates its own provider object using the parent provider object as a prototype. This way, in “inject”, we can simply look for injections from the immediate parent and let the prototype chain do the work. Finally, put the value into the provides object.
The user may write a function or object to obtain a provides object. The provides API is traversed through the object to parse the provides.
The next step is to register the lifecycle hook function and parse expoes, which I’ll talk about later,
- The rest
If the setup return is not a function, then the Render option is fetched and put on the instance, and the inheritAttrs, components, directives, filters are also put into the instance instead of null. The compatibility processing is complete.
conclusion
This time to fill in what was missed earlier, step by step analysis:
-
Examples include how the setup function executes the result (by data objects, promises, and rendering functions, respectively) and how these cases are handled. After data objects are processed responsively, they are put into the instance, while promises are handed to server renderers or Suspense after.then. Render functions are put directly into the instance.
-
Exposed exposed exposed exposed exposed exposed exposed exposed exposed exposed exposed exposed exposed The Expose API was added in Vue3.2, so there will be a merge operation for later compatibility processing
-
V2 compatibility. Actually, v3 apis are used to implement V2 functions. For example, computed options are implemented using computed API, and watch is implemented using watch API. Lifecycle functions and some hook functions will be covered in a later article.
Well, to the end of the article, or I hope you brothers and sisters can guide guidance. Any mistakes or omissions are welcome in the comments section. Thank you.