Compilation module 7: compile implementation

Keywords: Javascript Front-end Vue.js

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

Posted by CONTEMAN on Tue, 23 Nov 2021 01:24:36 -0800