Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Example Analysis of Vue3 template Compiler Optimization

2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

Editor to share with you the Vue3 template compilation optimization example analysis, I believe that most people do not know much about it, so share this article for your reference, I hope you will learn a lot after reading this article, let's go to understand it!

Compilation entry

Students who have known Vue3 must know that Vue3 has introduced a new composite Api. The setup method will be called in the component mount phase, and then it will determine whether the render method exists or not. If it does not exist, it will call the compile method to convert template to render.

/ / packages/runtime-core/src/renderer.ts const mountComponent = (initialVNode Container) = > {const instance = (initialVNode.component = createComponentInstance (/ /... params)) / / call setup setupComponent (instance)} / / packages/runtime-core/src/component.ts let compile export function registerRuntimeCompiler (_ compile) {compile = _ compile} export function setupComponent (instance) {const Component = instance.type const {setup} = Component if (setup) {/ /. Call setup} if (compile & & Component.template & &! Component.render) {/ / if there is no render method / / call compile to convert template into render method Component.render = compile (Component.template, {...})}}

This part is all the code in runtime-core. Previous articles have said that Vue is divided into full version and runtime version. If you use vue-loader to process .vue files, it is common to process template in .vue files directly into render methods.

/ / requires compiler Vue.createApp ({template:'{hi}'}) / / does not require Vue.createApp ({render () {return Vue.h ('div', {}, this.hi)}}))

The difference between the full version and the runtime version is that the full version introduces the compile method, and if it is a project generated by vue-cli, it will erase this part of the code and put the compile process into the packaging stage to optimize performance. The registerRuntimeCompiler method is provided in runtime-dom to inject the compile method.

Main process

In the full version of index.js, registerRuntimeCompiler is called to inject compile, and then let's take a look at what the injected compile method does.

/ / packages/vue/src/index.ts import {compile} from'@ vue/compiler-dom' / / compile cache const compileCache = Object.create (null) / / inject compile method function compileToFunction (/ / template template: string | HTMLElement, / / compile configuration options?: CompilerOptions): RenderFunction {if (! isString (template)) {/ / if template is not a string / / it is considered to be a DOM node Get innerHTML if (template.nodeType) {template = template[ XSS _ clean]} else {return NOOP}} / / if it exists in the cache, get const key = template const cached = compileCache [key] if (cached) {return cached} / / if it is an ID selector, after getting the DOM element Take innerHTML if (template [0] ='#') {const el = document.querySelector (template) template = el? El [XSS _ clean]:''} / / call compile to get render code const {code} = compile (template, options) / / convert render code to function const render = new Function (code) (); / / while returning the render method, put it into the cache return (compileCache [key] = render)} / / inject compile registerRuntimeCompiler (compileToFunction)

As I already said when talking about compiling Vue2 templates, the compile method is mainly divided into three steps, and the logic of Vue3 is similar:

Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community

Template compilation to convert template code to AST

Optimize AST to facilitate subsequent virtual DOM updates

Generate code that converts AST into executable code

/ / packages/compiler-dom/src/index.ts import {baseCompile, baseParse} from'@ vue/compiler-core' export function compile (template, options) {return baseCompile (template) Options)} / / packages/compiler-core/src/compile.ts import {baseParse} from'. / parse' import {transform} from'. / transform' import {transformIf} from'. / transforms/vIf' import {transformFor} from'. / transforms/vFor' import {transformText} from'. / transforms/transformText' import {transformElement} from'. / transforms/transformElement' import {transformOn} from'. / transforms/vOn' import {transformBind} from'. / transforms/vBind' import {transformModel} from'. / transforms/vModel' export function baseCompile (template) Options) {/ / parse html Convert to ast const ast = baseParse (template, options) / / optimize ast, mark the static node transform (ast, {... options, nodeTransforms: [transformIf, transformFor, transformText, transformElement, / /. Omit part of transform], directiveTransforms: {on: transformOn, bind: transformBind, model: transformModel}) / / convert ast to executable code return generate (ast, options)}

Calculate PatchFlag

The general logic here is not much different from the previous one, mainly that the optimize method has become the transform method, and some template syntax is transform by default. These transform are the key to subsequent virtual DOM optimization. Let's take a look at the transform code first.

/ packages/compiler-core/src/transform.ts export function transform (root, options) {const context = createTransformContext (root, options) traverseNode (root, context)} export function traverseNode (node, context) {context.currentNode = node const {nodeTransforms} = context const exitFns = [] for (let I = 0; I

< nodeTransforms.length; i++) { // Transform 会返回一个退出函数,在处理完所有的子节点后再执行 const onExit = nodeTransforms[i](node, context) if (onExit) { if (isArray(onExit)) { exitFns.push(...onExit) } else { exitFns.push(onExit) } } } traverseChildren(node, context) context.currentNode = node // 执行所以 Transform 的退出函数 let i = exitFns.length while (i--) { exitFns[i]() } } 我们重点看一下 transformElement 的逻辑: // packages/compiler-core/src/transforms/transformElement.ts export const transformElement: NodeTransform = (node, context) =>

{/ / transformElement did not execute any logic, but directly returned an exit function / / indicating that transformElement needs to wait until all the child nodes have been processed before executing return function postTransformElement () {const {tag, props} = node let vnodeProps let vnodePatchFlag const vnodeTag = node.tagType = = ElementTypes.COMPONENT? ResolveComponentType (node, context): `"${tag}" `let patchFlag = 0 / / detect node attributes if (props.length > 0) {/ detect the dynamic part of node attributes const propsBuildResult = buildProps (node) Context) vnodeProps = propsBuildResult.props patchFlag = propsBuildResult.patchFlag} / / detect the child node if (node.children.length > 0) {if (node.children.length = 1) {const child = node.children [0] / / detect whether the child node is dynamic text if (! getStaticType (child)) {patchFlag | = PatchFlags.TEXT } / / format patchFlag if (patchFlag! = = 0) {vnodePatchFlag = String (patchFlag)} node.codegenNode = createVNodeCall (context) VnodeTag, vnodeProps, vnodeChildren, vnodePatchFlag)}}

BuildProps traverses the attributes of the node once. Because the internal source code involves many other details, the code here is simplified and only retains the logic related to patchFlag.

Export function buildProps (node: ElementNode, context: TransformContext, props: ElementNode ['props'] = node.props) {let patchFlag = 0 for (let I = 0; I < props.length) ITunes +) {const prop = props [I] const [key, name] = prop.name.split (':') if (key = 'vMub bound' | | key = = 'class') {if (name = =' class') {/ / if it contains: class attribute, patchFlag | CLASS patchFlag | = PatchFlags.CLASS} else if (name = 'style') {/ / if it contains: style attribute PatchFlag | STYLE patchFlag | = PatchFlags.STYLE}} return {patchFlag}}

The above code shows only three types of patchFlag:

The node has only one text child node, and the text contains dynamic data (TEXT = 1)

Name: {{name}}

The node contains a mutable class attribute (CLASS = 1

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report