vue中.vue文件解析流程

发表于:2018-4-24 16:28

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:梅旭东    来源:个人博客

  我们平时写的 .vue 文件称为 SFC(Single File Components),本文介绍将 SFC 解析为 descriptor 这一过程在 vue 中是如何执行的。
  vue 提供了一个 compiler.parseComponent(file, [options])方法,来将 .vue 文件解析成一个 descriptor:
  // an object format describing a single-file component.
  declare type SFCDescriptor = {
      template: ?SFCBlock;
      script: ?SFCBlock;
      styles: Array<SFCBlock>;
      customBlocks: Array<SFCBlock>;
  };
  文件入口
  解析 sfc 文件的入口在 src/sfc/parser.js 中,该文件 export 了parseComponent方法,parseComponent方法用来对单文件组件进行编译。
  接下来我们看看parseComponent方法都做了哪些事情。
  parseComponent方法
  function start (tag, attrs, unary, start, end,) {
  }
  function end (tag, start, end) {
  }
  parseHTML(content, {
      start,
      end
  })
  parseComponent方法中定义了start``end两个函数,之后调用了parseHTML方法来对 .vue 文件内容践行编译。
  那么这个parseHTML方法是做啥的呢?
  parseHTML方法
  该方法看名字就知道是一个 html-parser,可以简单理解为,解析到每个起始标签时,调用 option 中的 start;每个标签结束时,调用 option 中的 end。
  对应到这里,就是分别调用parseComponent方法中定义的 start 和 end 函数。
  在parseComponent中维护一个 depth 变量,在start中将depth++,在end中depth--。那么,每个depth === 0的标签就是我们需要获取的信息,包含 template、script、style 以及一些自定义标签。
  start
  每当遇到一个起始标签时,执行start函数。
  1.记录下 currentBlock。
  每个 currentBlock 包含以下内容:
  declare type SFCBlock = {
      type: string;
      content: string;
      start?: number;
      end?: number;
      lang?: string;
      src?: string;
      scoped?: boolean;
      module?: string | boolean;
  };

  2.根据 tag 名称,将 currentBlock 对象在返回结果对象中。
  返回结果对象定义为 sfc,如果tag不是 script,style,template 中的任一个,就放在 sfc.customBlocks 中。如果是style,就放在 sfc.styles 中。script 和 template 则直接放在 sfc 下。
  if (isSpecialTag(tag)) {
      checkAttrs(currentBlock, attrs)
      if (tag === 'style') {
          sfc.styles.push(currentBlock)
      } else {
          sfc[tag] = currentBlock
      }
  } else { // custom blocks
      sfc.customBlocks.push(currentBlock)
  }

  end
  每当遇到一个结束标签时,执行end函数。
  1.如果当前是第一层标签(depth === 1),并且 currentBlock 变量存在,那么取出这部分text,放在 currentBlock.content 中。
  if (depth === 1 && currentBlock) {
    currentBlock.end = start
    let text = deindent(content.slice(currentBlock.start, currentBlock.end))
    // pad content so that linters and pre-processors can output correct
    // line numbers in errors and warnings
    if (currentBlock.type !== 'template' && options.pad) {
      text = padContent(currentBlock, options.pad) + text
    }
    currentBlock.content = text
    currentBlock = null
  }

  2.depth--。
  得到 descriptor
  在将 .vue 整个遍历一遍后,得到的 sfc 对象即为我们需要的结果。
  生成 .js ?
  compiler.parseComponent(file, [options])得到的只是一个组件的 SFCDescriptor,最终编译成.js 文件是交给 vue-loader 等库来做的。



上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号