vue3源码阅读-compiler-sfc


vue-compiler-sfc主要是用来解析SFC组件,我们都知道,一个SFC(*.vue)文件三大要素是template、script、style,vue-compiler-sfc就是负责解析这三大要素。从源码src目录下,每个文件的命名大致就可以看出来各个文件的作用,我先从 compiler-sfc 的 index.ts 开始。

(最近看源码深有感触的是,官文只是在说要怎么做,看了源码才知道为什么要这么做,并且还可以怎么做……,再就是测试用例真的很有用)

index.ts 主要是导出了其他文件的功能。

1.parse.ts:解析三大要素

三大要素template、script、style的类型定义:

想要看看具体解析后的sfc里面descriptor的结构,可以去运行vue-next/packages/compiler-sfc/__tests__ 下面个文件的测试用例。

我们运行一个单测,看看parse script的结果:

test('should expose top level declarations', () => {
    const script = compile(`
      <script setup>
      import { x } from './x'
      let a = 1
      const b = 2
      function c() {}
      class d {}
      </script>
      `)
    assertCode(script.content)
    console.log('----------------------')
    console.log(script)
    expect(script.content).toMatch('return { a, b, c, d, x }')
  })

// 结果
{
      type: 'script',
      // 可以看到,编译后的content,帮忙 return 了所有变量
      content: "import { x } from './x'\n" +
        '      \n' +
        'export default {\n' +
        '  expose: [],\n' +
        '  setup(__props) {\n' +
        '\n' +
        '      let a = 1\n' +
        '      const b = 2\n' +
        '      function c() {}\n' +
        '      class d {}\n' +
        '      \n' +
        'return { a, b, c, d, x }\n' +
        '}\n' +
        '\n' +
        '}',
      loc: {
        source: '\n' +
          "      import { x } from './x'\n" +
          '      let a = 1\n' +
          '      const b = 2\n' +
          '      function c() {}\n' +
          '      class d {}\n' +
          '      ',
        start: { column: 21, line: 2, offset: 21 },
        end: { column: 7, line: 8, offset: 131 }
      },
      attrs: { setup: true },
      setup: true,
      bindings: {
        x: 'setup-maybe-ref',
        a: 'setup-let',
        b: 'setup-const',
        c: 'setup-const',
        d: 'setup-const'
      },
      map: SourceMap {
        version: 3,
        file: null,
        sources: [ 'anonymous.vue' ],
        sourcesContent: [
          '\n' +
            '      <script setup>\n' +
            "      import { x } from './x'\n" +
            '      let a = 1\n' +
            '      const b = 2\n' +
            '      function c() {}\n' +
            '      class d {}\n' +
            '      </script>\n' +
            '      '
        ],
        names: [],
        mappings: 'AAEM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,CAAC,CAAC,CAAC,CAAC,CAAC;;;;AAFe;AACpB,CAAC,CAAC,CAAC,CAAC,CAAC,CACC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACf,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChB,CAAC,CAAC,CAAC,CAAC,CAAC;;;;'
      },
      scriptAst: undefined,
      scriptSetupAst: [
        Node {
          type: 'ImportDeclaration',
          start: 7,
          end: 30,
          loc: [SourceLocation],
          range: undefined,
          leadingComments: undefined,
          trailingComments: undefined,
          innerComments: undefined,
          extra: undefined,
          specifiers: [Array],
          source: [Node]
        },
        Node {
          type: 'VariableDeclaration',
          start: 37,
          end: 46,
          loc: [SourceLocation],
          range: undefined,
          leadingComments: undefined,
          trailingComments: undefined,
          innerComments: undefined,
          extra: undefined,
          declarations: [Array],
          kind: 'let'
        },
        Node {
          type: 'VariableDeclaration',
          start: 53,
          end: 64,
          loc: [SourceLocation],
          range: undefined,
          leadingComments: undefined,
          trailingComments: undefined,
          innerComments: undefined,
          extra: undefined,
          declarations: [Array],
          kind: 'const'
        },
        Node {
          type: 'FunctionDeclaration',
          start: 71,
          end: 86,
          loc: [SourceLocation],
          range: undefined,
          leadingComments: undefined,
          trailingComments: undefined,
          innerComments: undefined,
          extra: undefined,
          id: [Node],
          generator: false,
          async: false,
          params: [],
          body: [Node]
        },
        Node {
          type: 'ClassDeclaration',
          start: 93,
          end: 103,
          loc: [SourceLocation],
          range: undefined,
          leadingComments: undefined,
          trailingComments: undefined,
          innerComments: undefined,
          extra: undefined,
          id: [Node],
          superClass: null,
          body: [Node]
        }
      ]
    }

 

 

vue3的sfc的style模块多了一个 parseCssVars 的功能,支持在css中使用响应式的变量,用过v-bind去绑定。

示例见:vue-next/packages/compiler-sfc/__tests__/cssVars.spec.ts

 

2.compileStyle.ts 编译style模块

vue3 内置了对各种css语法的预处理器,详情见:vue-next/packages/compiler-sfc/src/stylePreprocessors.ts,主要包括:

export type PreprocessLang = 'less' | 'sass' | 'scss' | 'styl' | 'stylus'

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM