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