The runtime of the mini – vue – core
Hello, everyone, I am a self-taught front end of the small rookie, the current work less than a year, still trying to learn, I hope that THE content I write, helpful to you, also hope that you have any opinions and suggestions can tell me, let me less detours, thank you!!
Through the implementation of a mini-vue3 to deepen their understanding of VUE, slowly learn, record what you have learned, there are detailed notes
This Mini-vue3 is learned through The Git warehouse of Cui Xiaorui. Teacher Ruan Yifeng recommended to learn Vue3
Address of this warehouse: Mini-VUe-IMPl
Source: the mini – vue
Pure own learning, if there are mistakes, but also hope you correct, including
In the study-every-day warehouse, there are big boss brain map, need to take oh ~
The previous article on responsive systems is here
1.Responsive system
2. Core runtime
Speaking of the core runtime, again, take a look at the vue architecture schema diagram to see what it does
From the figure, we can see that the Run-time core is responsible for connecting the run-time DOM and the reactivity responsive system in our runtime, so as to achieve the function of cross-platform. Why cross-platform?
This is because VUe3 provides a custom renderer, and we can provide different renderer interfaces according to different platforms to achieve cross-platform rendering. The main reason for this is also that virtual nodes are used to render real nodes, and stable APIS are needed to help us render nodes on the page
For example: browser DOM
// Create a node and add it to the HTML body node
const div = document.createElement('div')
div.textContent = 'Hello World'
document.body.append(div)
Copy the code
In this example we use the browser’s DOM API to create a node and add it to the view
There are other platforms in WXML for applets that provide stable apis to turn our virtual nodes into real nodes
At this point, we know what run-time Core does. ~
- Providing virtual nodes
VNode
Is used to create real nodes anddiff
More updates - Provides a custom renderer interface that allows users to create renderers based on the platform
- call
reactivity
The module is triggered by the dependency collection of a responsive systemdiff
Update our view
1. Provide virtual nodesvirtual DOM
In fact, I have always been very confused about the difference between virtual nodes and component instances, are objects, have corresponding attributes, what is the difference, until this time I through the implementation of a simple version, finally can distinguish
1.1 Virtual Nodes
The virtual node is a mirror image of the real DOM, and we use this mirror to create the real DOM and optimize more of the above, for example
By marking static nodes, we can update them with finer granularity. Static nodes will never move. Where do I write to die
Why do you need the virtual DOM?
- cross-platform
- Avoid repeated manipulation of reality
DOM
Unnecessary performance drain - Description by virtual node
DOM
Tree, can go throughdiff
Know exactly which point is updated and make updates to avoid unnecessary backflow redrawing
The core of the virtual DOM is to use efficient JS operations to reduce low performance DOM operations, so as to improve web page performance
Other platforms, similarly, use DOM as a description point
Look at the code
Vue3 also has many attributes, such as static node tags, which can be skipped in diff
export function createVNode(type, props? , children?) {
const vnode = {
type.// Node type
props, / / property
children, / / child nodes
shapeFlag: getShapeFlag(type), // Virtual node type
el: null // Real DOM references, accurate DOM updates
}
if (typeof children === 'string') {
// If the child component is text, mark the current node as element + text
vnode.shapeFlag |= ShapeFlag.TEXT_CHILDREN
} else if (Array.isArray(children)) {
// If the subcomponent is an array, it may be a new component, or the element's child node is element + child element
vnode.shapeFlag |= ShapeFlag.ARRAY_CHILDREN
}
// Whether there is a slot
if (
vnode.shapeFlag & ShapeFlag.STATEFUL_COMPONENT &&
typeof children === 'object'
) {
vnode.shapeFlag |= ShapeFlag.SLOT_CHILDREN
}
return vnode
}
export function createTextVnode(text: string) {
return createVNode(Text, {}, text) / / text
}
/ * * *@description Gets the type identifier * of the current child node@param Type Current vNode type */
function getShapeFlag(type: any) {
return typeof type= = ='string'
? ShapeFlag.ELEMENT / / element
: ShapeFlag.STATEFUL_COMPONENT / / component
}
Copy the code
In the virtual node, there’s a bit operation, which I’m sure you’ve all heard of, to mark the node type with a binary switch, which is really high, and normally we would use a map to determine the type, like this
const vnodeType = {
element: false.stateful_component: false.text_children: false.array_children: false
}
// If the component is an element, the child node is text
vnodeType.element = true
vnodeType.text_children = true
// The result will be this
if (vnodeType.element && vnodeType.text_children) {
// Related operations
}
Copy the code
Actually such readability is very high, but performance is poor, we all need a mapping object each virtual node, and then create the marked, and the reference object storage, determine the consumption is high, on the contrary we use binary switch, will be much faster, digital, consume the space is little, the binary is more suitable for computer analysis
See what VUE3 does
/** * Virtual node type identifier * Each bit represents a type */
export const enum ShapeFlag {
ELEMENT = 1./ / 0001 elements
STATEFUL_COMPONENT = 1 << 1./ / 0010 components
TEXT_CHILDREN = 1 << 2.// 0100 child nodes are text
ARRAY_CHILDREN = 1 << 3.// 1000 child nodes are arrays
SLOT_CHILDREN = 1 << 4 // 1 0000 component uses a slot
}
/ / about the types of judgment, the use of | and & to operate
/ / create the node, to open the corresponding identifier bit by | =
// Use ampersand (1 &) to indicate the bit identifier
Copy the code
2. Provide renderer interface
The renderer interface is not difficult to provide, passing in the API for manipulating nodes as a closure. The effect is to call the passed stable API when the virtual node needs to create the real node
/ * * *@description Create renderers through external definitions to render different platform elements *@param The Options element node handles the provided interface */
export function createRenderer(options) {
// Provides a custom rendering interface
const {
createElement: hostCreateElement, // Create operation
patchProp: hostPatchProp, // Attribute manipulation
insert: hostInsert, // Insert operations
createTextNode: hostCreateTextNode // Text manipulation
} = options
/ /... Operations on virtual nodes and components
return {
// Provide exposure to the entrance
createApp: createAppAPI(render)
}
}
export function createAppAPI(render) {
return function createApp(rootComponent) {
return {
mount(rootContainer) {
// 1. Convert the component or 'Dom' into a virtual node
const vnode = createVNode(rootComponent)
// 2. Process 'vnode'
render(vnode, rootContainer)
}
}
}
}
Copy the code
3. Component instance object
As I mentioned earlier, I didn’t know the difference between a component object and a virtual node object. I said virtual nodes. Now let’s look at component instances
Component instance objects, it is my usual operation. The vue file export the entire object, we can normal operation that the API documentation on the component instance has defined, is our operational view of interaction and rendering of an abstract, because components needs to be done within a lot, we can abstract out an object, to help us do these things
Take a look at the code:
export function createComponentInstance(vnode, parent) {
const component: any = {
vnode, // The component corresponds to a virtual node
type: vnode.type, // Component type => is the configuration information we provide to the component, such as: {name: 'App, setup... }
setupState: {}, // The status information returned by setup
props: {}, // Component property information, which is passed by the parent component
slots: {}, / / slots
provides: parent ? parent.provides : {}, / / dojo.provide/inject function
parent, // The parent of the component
isMounted: false.// Indicates whether to mount
subTree: null.// Component node tree for diff
emit: () = > {} // Implementation of emit functionality
}
component.emit = emit
return component
}
Copy the code
It should be clear from these functional apis that a component instance is a state store where we write components and provide operations, recording the current state of our component, while a virtual node is a mapping of the current real DOM
4. Invoke a responsive system
function setupRenderEffect(instance, container) {
// Call the component's render function with 'effect'
Dependency collection is triggered when we use reactive objects like 'ref/reactive' in the component
// When the dependency changes, the current function will be called again, which will trigger 'patch' to perform 'diff' algorithm comparison and update to the view
// Component-level dependency collection to avoid performance waste
effect(() = > {
// @tips: First load
if(! instance.isMounted) {// 1. Call the render function, get the virtual node tree of the component, bind 'this' as the proxy object, implement the' render 'function to access the component state
const subTree = instance.render.call(instance.proxy, h)
// 2. Continue 'patch' and mount components recursively
patch(null, subTree, container, instance)
// 3. Component instance binding 'EL' is used for precise update of 'patch'
instance.vnode.el = subTree.el
// 4. Store the old virtual node tree, and then call 'patch'
instance.subTree = subTree
// 5. Indicates that the vm is mounted
instance.isMounted = true
}
/ / @ Tips: update
else {
// 1. Obtain a new virtual node tree
const subTree = instance.render.call(instance.proxy, h)
2. Obtain the old virtual node tree
const prevSubTree = instance.subTree
// 3. Update page of 'patch'
patch(prevSubTree, subTree, container, instance)
// 4. New tree becomes old tree after comparison
instance.subTree = subTree
}
})
}
Copy the code
That’s it. Thank you for watching
Warehouse address: Mini-VUe-IMPl
Welcome to correct: study together
You can also implement a simple version, or go to my warehouse to have a look, the commit record is the corresponding, this week I will tag the corresponding easy to read and review, hope you like, if you like to give a star, thank you