MCPcopy
hub / github.com/ygs-code/vue

github.com/ygs-code/vue @main sqlite

repository ↗ · DeepWiki ↗
418 symbols 1,126 edges 2 files 61 documented · 15%
README

begin

vue source code spare time to see almost a year, before looking for posts on the Internet, found that many posts are very scattered, are part of a part said, a lot of chapters, so they decided to see line by line, after their own persistence and efforts, now basically read. This vue source line by line analysis, I basically every line on the annotation, plus the whole framework of the process mind map, is basically a small white can also understand the vue source code.

Said very detailed, inside the source code notes, some are their own years of experience in developing vue, some are their own context program to know, if there are shortcomings can contact me QQ group: 302817612 modification, or send an email to me 281113270@qq.com thank you. If you feel good, please move your little finger to help me click a satr, your support is my motivation.

vue How to see vue source code? In fact, mvvm source code is not as mysterious as imagined, from the beginning of 12 years to the present mvvm development has more than a decade of history, from the previous direct operation of the dom jq development has more than a decade of history, but this decade of historical development, and there is not much change, the idea is still those, the module is still divided into several chunks:

1. Template conversion:

Is we write a vue template or react jsx we can understand is a template, and then it will go through the template compilation conversion, like vue is into a method paseHTML method converted into the ast tree, paseHTML inside the while loop template, Then through the RE match to the vue instructions, as well as vue properties, event methods, etc., collected into an ast tree.

2. Corresponding data:

vue is a dual data corresponding framework, the underlying use is Object.defineProperty to listen for and hijack data changes, and then call callback methods to update the view update. The principle of dual data binding is as follows: The obersve() method determines whether value has no ob___ attribute and is not Obersve instantiated, and whether value is Vonde instantiated. If not, it calls Obersve to add the data to the observer and add the __ob attribute to the data. Obersve calls the defineReactive method, which is a channel connecting the Dep and wacther methods, and listens for data using the get and set methods in Object.definpropty(). In the get method, new Dep calls depend(). To add a wacther class to dep, watcher has a method to update the view. run calls update to update the vonde and then updates the view. Then the set method is to call the notify method in dep to call the run update view in wacther

3. Virtual dom:

vnode, used in vue, is via ast objects, escaped into vonde needs to render functions, such as _c('div' s('')) and such functions, compiled into vonde virtual dom. Then update the data to updata and call patch to turn vonde into a true dom element through diff algorithm.

4.diif algorithm:

​ The diff algorithm of vue2 is depth-first traversal, and then the comparison algorithm compares the old vnode with the new vnode, first compares their basic attributes, such as key labels, etc. If they are the same, the diff algorithm compares the old Vnode with the new Vnode, and then there are four pointer indexes. Two new vnode start Pointers and two new vnode end Pointers, two old vnode start Pointers and old vnode end Pointers. Then first determine whether the vnode is empty, if it is empty, move to the center of the start pointer ++ end pointer --. Then after comparing the two sides, cross-compare until you can't find the same vnode, if there are more, delete it, if there are fewer, add it, and then update it to the real dom after comparing.

new Vue calls vue.prototype. _init. From this function, after merging with the $options parameter, initLifecycle initializes the life cycle, marking the initialization event, and initializing the rendering function. The initialization state is the data. Add data to the observer for double data binding.

new Vue instantiates the program entry

 Vue.prototype._init = function (options) { //初始化函数
  //... 省略code

    initLifecycle(vm); //初始化生命周期 标志
            initEvents(vm); //初始化事件
            initRender(vm); // 初始化渲染
            callHook(vm, 'beforeCreate'); //触发beforeCreate钩子函数
            initInjections(vm); // resolve injections before data/props 在数据/道具之前解决注入问题 //初始化 inject
            initState(vm);  //    //初始化状态
            initProvide(vm); // resolve provide after data/props  解决后提供数据/道具  provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的属性,用于组件之间通信。
            callHook(vm, 'created'); //触发created钩子函数


  //... 省略code
    // 然后挂载模板,这里大概就是把模板转换成ast的入口
    vm.$mount(vm.$options.el);

 }

Find and mount templates

vm.$mount goes to the mount template method and determines whether it has a render function or a template, and if not, uses el.outerHTML, which is essentially getting the html content of the template

 Vue.prototype.$mount = function (el, hydrating) { 
   //... 省略code
       el = el && query(el); //获取dom
         if (!options.render) {
              if (template) {

              }else if (template.nodeType) { 
                  template = template.innerHTML;
              } else if (el) {
                template = getOuterHTML(el);
              }
         }


              // render 函数 也是 ast 转换 方法
                var ref = compileToFunctions(
                    template, //模板字符串
                    {
                        shouldDecodeNewlines: shouldDecodeNewlines, //flase //IE在属性值中编码换行,而其他浏览器则不会
                        shouldDecodeNewlinesForHref: shouldDecodeNewlinesForHref, //true chrome在a[href]中编码内容
                        delimiters: options.delimiters, //改变纯文本插入分隔符。修改指令的书写风格,比如默认是{{mgs}}  delimiters: ['${', '}']之后变成这样 ${mgs}
                        comments: options.comments //当设为 true 时,将会保留且渲染模板中的 HTML 注释。默认行为是舍弃它们。
                    },
                    this
                );




     //... 省略code
      //执行$mount方法     用$mount的方法把扩展挂载到dom上
        return mount.call(
            this,
            el, //真实的dom
            hydrating //undefined
        )

 }

Compile the AST and render functions

After you call the Vue.prototype.$mount method and get the template, you enter the following methods, which use a lot of functional programming

compileToFunctions

createCompiler

createCompilerCreator

baseCompile

parse

parseHTML

The important thing here is that parseHTML is a while (html) {// loop through the html and then through the re match to the vue directive, as well as vue properties, event methods, etc., collected into an ast tree.

``` function parseHTML( html, //字符串模板 options //参数 ) { var stack = []; // parseHTML 节点标签堆栈 var expectHTML = options.expectHTML; //true var isUnaryTag$$1 = options.isUnaryTag || no; //函数匹配标签是否是 'area,base,br,col,embed,frame,hr,img,input,isindex,keygen, link,meta,param,source,track,wbr' var canBeLeftOpenTag$$1 = options.canBeLeftOpenTag || no; //函数 //判断标签是否是 'colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source' var index = 0; var last, // lastTag; // console.log(html)

    while (html) { //循环html
        last = html; //
        // Make sure we're not in a plaintext content element like script/style 确保我们不在像脚本/样式这样的纯文本内容元素中
        if (
            !lastTag || //lastTag 不存在
            !isPlainTextElement(lastTag)  // 如果标签不是script,style,textarea
        ) {

            var textEnd = html.indexOf('<'); //匹配开始标签或者结束标签的位置
            if (textEnd === 0) { //标识是开始标签
                // Comment:
                if (comment.test(html)) { //匹配 开始字符串为'); //获取注释标签的结束位置

                    if (commentEnd >= 0) { //如果注释标签结束标签位置大于0,则有注释内容
                        console.log(html.substring(4, commentEnd))
                        if (options.shouldKeepComment) { //shouldKeepComment为真时候。获取注释标签内容

                            //截取注释标签的内容
                            options.comment(html.substring(4, commentEnd));
                        }
                        //截取字符串重新循环  while 跳出循环就是靠该函数,每次匹配到之后就截取掉字符串,知道最后一个标签被截取完没有匹配到则跳出循环
                        advance(commentEnd + 3);
                        continue
                    }
                }

                //这里思路是先匹配到注释节点,在匹配到这里的ie浏览器加载样式节点
                // http://en.wikipedia.org/wiki/Conditional_comment#Downlevel-revealed_conditional_comment
                if (conditionalComment.test(html)) {  //匹配开始为 <![ 字符串  <![endif]-->   匹配这样动态加ie浏览器的 字符串  
                    //匹配ie浏览器动态加样式结束符号
                    var conditionalEnd = html.indexOf(']>');

                    if (conditionalEnd >= 0) {
                        //截取字符串重新循环  while 跳出循环就是靠该函数,每次匹配到之后就截取掉字符串,知道最后一个标签被截取完没有匹配到则跳出循环
                        advance(conditionalEnd + 2);
                        continue
                    }
                }

                // Doctype:
                //匹配html的头文件 <!DOCTYPE html>
                var doctypeMatch = html.match(doctype);
                if (doctypeMatch) {
                    //截取字符串重新循环  while 跳出循环就是靠该函数,每次匹配到之后就截取掉字符串,知道最后一个标签被截取完没有匹配到则跳出循环
                    advance(doctypeMatch[0].length);
                    continue
                }

                // End tag:
                //匹配开头必需是</ 后面可以忽略是任何字符串  ^<\\/((?:[a-zA-Z_][\\w\\-\\.]*\\:)?[a-zA-Z_][\\w\\-\\.]*)[^>]*>
                var endTagMatch = html.match(endTag);
                if (endTagMatch) {

                    var curIndex = index;
                    //标签分隔函数 while 跳出循环就是靠该函数,每次匹配到之后就截取掉字符串,知道最后一个标签被截取完没有匹配到则跳出循环
                    advance(endTagMatch[0].length);
                    console.log(endTagMatch)
                    console.log(curIndex, index)
                    //查找parseHTML的stack栈中与当前tagName标签名称相等的标签,
                    //调用options.end函数,删除当前节点的子节点中的最后一个如果是空格或者空的文本节点则删除,
                    //为stack出栈一个当前标签,为currentParent变量获取到当前节点的父节点
                    parseEndTag(
                        endTagMatch[1],
                        curIndex,
                        index
                    );
                    continue
                }

                // Start tag:
                //解析开始标记 标记开始标签
                //  获取开始标签的名称,属性集合,开始位置和结束位置,并且返回该对象
                var startTagMatch = parseStartTag();

                if (startTagMatch) {
                    //把数组对象属性值循环变成对象,这样可以过滤相同的属性
                    //为parseHTML 节点标签堆栈 插入一个桟数据
                    //调用options.start  为parse函数 stack标签堆栈 添加一个标签
                    handleStartTag(startTagMatch);
                    //匹配tag标签是pre,textarea,并且第二个参数的第一个字符是回车键
                    if (shouldIgnoreFirstNewline(lastTag, html)) {
                        //去除回车键空格
                        advance(1);
                    }
                    continue
                }
            }

            var text = (void 0),
                rest = (void 0),
                next = (void 0);
            if (textEnd >= 0) {

                rest = html.slice(textEnd); //截取字符串  var textEnd = html.indexOf('<'); //匹配开始标签或者结束标签的位置
                console.log(rest)

                while (
                    !endTag.test(rest) && //匹配开头必需是</ 后面可以忽略是任何字符串
                    !startTagOpen.test(rest) && // 匹配开头必需是< 后面可以忽略是任何字符串
                    !comment.test(rest) && // 匹配 开始字符串为/g, '$1') // #7298
                        .replace(/<!\[CDATA\[([\s\S]*?)]]>/g, '$1');
                }
                //匹配tag标签是pre,textarea,并且第二个参数的第一个字符是回车键
                if (shouldIgnoreFirstNewline(stackedTag, text)) {
                    text = text.slice(1);

Core symbols most depended-on inside this repo

isDef
called by 142
vue.js
isUndef
called by 48
vue.js
extend
called by 30
vue.js
isTrue
called by 20
vue.js
getAndRemoveAttr
called by 20
vue.js
hasOwn
called by 19
vue.js
makeMap
called by 18
vue.js
isObject
called by 17
vue.js

Shape

Function 418

Languages

TypeScript100%

Modules by API surface

vue.js418 symbols

For agents

$ claude mcp add vue \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact