preface

Compiler is one of the three modules in Vue and is responsible for compiling templates. As we know, a render function is generated when the template is compiled and parsed, which is then called at Runtime to create the actual DOM tree. Vue3 template compilation in this site, we can see the actual render function generated by the string template after compiler.

The render function is generated by the template in compiler, but how does it work internally? PatchFlag, hoist, cacheHandlers… How do you do that?

Here we give a brief overview, and we will expand it in detail in later articles. In Compiler, there are three processes:

  1. parse: converts the string template toAST
  2. transform:ASTOptimize and add some property values in preparation for the next steps
  3. codegenWill:ASTTransgendered into onerenderfunction

In VUe2 there is no transform step, it is optimize. Both are optimizations to AST, but Transform has many new responsibilities, such as patchFLag mentioned above

The module of decoupling

Like runtime, compiler is also divided into Comolil-core and platform-specific compiler to improve extensibility. For example:

Compiler-dom, Compiler-SFC and Compiler-SSR, among which the compiler of each platform still calls the compiler-core method.

  • compiler-domBrowser:
  • compiler-sfc: single file component
  • compiler-ssr: Server rendering

compiler-dom

Now start with compiler-DOM.

export function compile(template: string, options: CompilerOptions = {}) :CodegenResult {
  return baseCompile(
    template,
    extend({}, parserOptions, options, {
      nodeTransforms: [
        ignoreSideEffectTags,
        ...DOMNodeTransforms,
        ...(options.nodeTransforms || [])
      ],
      directiveTransforms: extend(
        {},
        DOMDirectiveTransforms,
        options.directiveTransforms || {}
      ),
      transformHoist: __BROWSER__ ? null : stringifyStatic // Whether the hoist is optimized}}))Copy the code

As you can see, baseCompile is called inside the compile function. BaseCompiler is derived from compiler-core.

When you look at the arguments passed in the call, you pass in template and options mixed with many objects. ParseOptions is an option provided by compiler-DOM for the DOM platform.

Let’s move on to the parseOptions provided by compiler-DOM

export const parserOptions: ParserOptions = {
  isVoidTag, // Whether autistic and
  isNativeTag: tag= > isHTMLTag(tag) || isSVGTag(tag), // Is the label of a platform element
  isPreTag: tag= > tag === 'pre'.// Whether the label is pre
  decodeEntities: __BROWSER__ ? decodeHtmlBrowser : decodeHtml, // Decode the content

  // Check whether it is an internal label
  isBuiltInComponent: (tag: string): symbol | undefined= > {},

  // Get the namespace
  getNamespace(tag: string, parent: ElementNode | undefined): DOMNamespaces {},

  // Get the label's textMode, which affects parse
  getTextMode({ tag, ns }: ElementNode): TextModes {}
}
Copy the code

It contains these properties and methods:

  • isVoidTag: Indicates whether the device is closed automatically
  • isNativeTag: Indicates whether a native label is provided by the platform
  • isPreTag: whether it ispreThe label
  • decodeEntities: Decodes the content
  • isBuiltInComponent: Checks whether the label is internal
  • getNamespace: Gets the namespace
  • getTextMode: To obtain the labeltextMode

Among them, textMode is very important, which affects the parsing of Prase. Different TextModes judge the end of parsing and have different specific parsing.

baseCompile

As we have seen above, the core of compiler-DOM’s compile function lies in internally calling the baseCompiler function provided by compiler-core. Now let’s see what the baseCompile function does

export function baseCompile(template: string | RootNode, options: CompilerOptions = {}) :CodegenResult {
  // Check parameters
  const onError = options.onError || defaultOnError
  const isModuleMode = options.mode === 'module' // DOM platform is false
  /* istanbul ignore if */
  if (__BROWSER__) {
    if (options.prefixIdentifiers === true) {
      onError(createCompilerError(ErrorCodes.X_PREFIX_ID_NOT_SUPPORTED))
    } else if (isModuleMode) {
      onError(createCompilerError(ErrorCodes.X_MODULE_MODE_NOT_SUPPORTED))
    }
  }

  // mark code generation mode: function mode/module mode
  constprefixIdentifiers = ! __BROWSER__ && (options.prefixIdentifiers ===true || isModuleMode)
    
  if(! prefixIdentifiers && options.cacheHandlers) { onError(createCompilerError(ErrorCodes.X_CACHE_HANDLER_NOT_SUPPORTED)) }if(options.scopeId && ! isModuleMode) { onError(createCompilerError(ErrorCodes.X_SCOPE_ID_NOT_SUPPORTED)) }// 1. Convert the template string to ast
  const ast = isString(template) ? baseParse(template, options) : template
  
  Get the default transform method according to the prefixIdentifiers
  const [nodeTransforms, directiveTransforms] = getBaseTransformPreset(
    prefixIdentifiers
  )
  
  // 2. Optimize ast
  transform(
    ast,
    extend({}, options, {
      prefixIdentifiers,
      nodeTransforms: [
        ...nodeTransforms,
        ...(options.nodeTransforms || []) // user transforms].directiveTransforms: extend(
        {},
        directiveTransforms,
        options.directiveTransforms || {} // user transforms)}))// 3. Turn ast into render function
  return generate(
    ast,
    extend({}, options, {
      prefixIdentifiers
    })
  )
}
Copy the code
  1. Parameter verification is performed to mark code generation patternsprefixIdentifiers
  2. callbaseParseConverts the template string toast
  3. According to theprefixIdentifiersTo get the defaultnodeTransformsanddirectiveTransforms
  4. calltransformrightastTo optimize
  5. callgenerateAccording to theastThe generated code

You can see that all three procedures we mentioned above are called in baseCompile. We’ll take a closer look at each one in the following articles.