Source location:
vue-next/packages/compile-core/src/compile.ts
The last is the main entrance of the whole module. Just integrate the previous modules
Write it down
The code is given directly here, but I will elaborate more
// Plug in preset function getBaseTransformPreset() { return [ [transformElement, transformText], { on: transformOn, bind: transformBind, }, ]; } function baseCompile(template, options = {}) { const ast = isString(template) ? baseParse(template, options) : template; // Get plug-in preset const [nodeTransforms, directiveTransforms] = getBaseTransformPreset(); // The extend here is actually Object.assign() transform( ast, extend({}, options, { nodeTransforms: [...nodeTransforms, ...(options.nodeTransforms || [])], directiveTransforms: extend( {}, directiveTransforms, options.directiveTransforms || {} // user transforms ), }) ); return generate(ast, extend({}, options)); }
Use it
Here, the compile module is completely written, so where should I use it?
The answer is obvious. Of course, it is used to compile the component template, find the component file written by the previous runtime module, and now you can expand the render on the instance
The only thing to pay attention to is the mounting time. The code we compiled is the render function, which needs to use the context instance.ctx, and the render function needs to be used in the mounting and updating of the instance.update component. Therefore, the compilation time should be after the initialization of the context
function mountComponent(vnode, container, anchor) { // TODO initialization context if (!Component.render && Component.template) { let { template } = Component; if (template[0] === '#') { const el = document.querySelector(template); template = el ? el.innerHTML : ''; } const { code } = baseCompile(template); Component.render = new Function('ctx', code); } // TODO initialization mount / update function }
The idea here is to take the template attribute in the component as the template first, otherwise, take the content specified in the mount() method as the selector, and take the node in the selected container as the template for compilation
The constructor of Function is used here. It looks like this
new Function ([arg1[, arg2[, ...argN]],] functionBody)
It can be seen from the constructor that my approach here is to pass in ctx and code, the former as function parameters and the latter as function body content, so as to dynamically build a function
Run
Regardless of other entry functions, write the following code
<div id="app"> <div> <p class="a">hello Beggar Vue</p> <div>counter: {{ counter.value }}</div> <button @click="add">click</button> </div> </div> <script> createApp({ setup() { const counter = ref(0); const add = () => counter.value++; return { counter, add, }; }, }).mount('#app'); </script>
Just write a style for p.a
.a { font-size: large; }
The effect of running is as follows
Styles and instructions can be used. For the time being, everything is expected
summary
So far, it has basically met my expectations. I can barely finish it. Due to a lot of laziness, there are a lot of bug s and pits, but it's OK to run, just run