Compilation module 5: implementation of directivetransforms

Keywords: Javascript Front-end Vue.js

Source location:
vue-next/packages/compile-core/src/transforms/vOn.ts
vue-next/packages/compile-core/src/transforms/vBind.ts

Here, the transform module has been basically implemented, but it needs to deal with v-on and v-bind. Take this as a simple example to see what instruction compilation will do

Explain

directiveTransforms is also a kind of transform plugin conversion plug-in, which includes some instruction processing functions such as transformOn and transformBind. This paper implements these two functions. The things done by instruction processing are relatively trivial, which can be summarized briefly

  • Different processing is performed for different instructions
    • v-on needs humping event monitoring, event processing, monitoring cache, application expansion plug-ins, etc
    • v-bind needs to handle some pre modifiers and some fault tolerance
  • Package instruction contents into JS_PROPERTY object return

Write about transformOn

Two tool functions

Here are two tool functions

capitalize

As mentioned above, to hump event monitoring, of course, there must be such a tool function

function camelize(str) {
  return str.replace(
    /-(\w)/g, 
    (neverUse, c) => (c ? c.toUpperCase() : '')
  );
}

The series here may seem a little confused. The first parameter of replace can receive a regular expression, while the second parameter receives a callback function. The parameters of the callback function are very similar to the return results of RegExp.exec(). The first parameter is the matched substring, and the second parameter starts to capture the contents of the group. The following is an example

const str = 'yes-this-is-my-handler';
// In the above example
// nerverUse is ['- t', '-i', '-m', '-h']
// c is ['t ',' I ','m', 'H']
camelize(str); // yesThisIsMyHandler

toHandlerKey

Here is a tool function to convert XXX XX into onxxxXx, which is very simple

const toHandlerKey = str => (str ? `on${capitalize(str)}` : '')

transformOn

The things to be done in transformOn are tedious, but the things to be done in our transformOn are very simple. We only need to hump event monitoring, and then package it into JS_PROPERTY type objects can be returned

const transformOn = dir => {
  const { arg } = dir;

  // Humping
  let eventName;
  if (arg.type === NodeTypes.SIMPLE_EXPRESSION) {
    if (arg.isStatic) {
      const rawName = arg.content;
      eventName = createSimpleExpression(toHandlerKey(camelize(rawName)), true);
    }
    // The source code here processes the dynamic event name into a composite expression
  } else {
    eventName = arg;
  }

  // Processing expression
  let exp = dir.exp;
  if (exp && !exp.content.trim()) {
    exp = undefined;
  }
  // The source code will handle the event cache here
  // The source code will handle the external plug-in extended compiler augmentor here

  // Package and return JS_PROPERTY node
  let ret = {
    props: [
      createObjectProperty(
        eventName,
        exp || createSimpleExpression('() => {}', false)
      ),
    ],
  };
  return ret;
};

Write about transformBind

transformBind needs to do many simple things, such as fault-tolerant processing, adding prefixes, wrapping nodes, and looking at the code directly

const transformBind = dir => {
  const { exp, modifiers } = dir;
  const arg = dir.arg;

  // Fault tolerant processing. If it is empty, an empty string will be output
  if (arg.type !== NodeTypes.SIMPLE_EXPRESSION) {
    arg.children.unshift('(');
    arg.children.push(') || ""');
  } else if (!arg.isStatic) {
    arg.content = `${arg.content} || ""`;
  }

  // Add "." prefix to prop
  // Add "^" prefix to attr
  if (modifiers.includes('prop')) {
    injectPrefix(arg, '.');
  }
  if (modifiers.includes('attr')) {
    injectPrefix(arg, '^');
  }

  // Package and return JS_PROPERTY node
  if (
    !exp ||
    (exp.type === NodeTypes.SIMPLE_EXPRESSION && !exp.content.trim())
  ) {
    return {
      props: [createObjectProperty(arg, createSimpleExpression('', true))],
    };
  }

  return {
    props: [createObjectProperty(arg, exp)],
  };
};

// Prefix handler
const injectPrefix = (arg, prefix) => {
  if (arg.type === NodeTypes.SIMPLE_EXPRESSION) {
    if (arg.isStatic) {
      arg.content = prefix + arg.content;
    } else {
      arg.content = `\`${prefix}\${${arg.content}}\``;
    }
  } else {
    arg.children.unshift(`'${prefix}' + (`);
    arg.children.push(`)`);
  }
};

summary

The above is the implementation of transformOn and transformBind, both of which belong to directiveTransforms. They are called in the previous transformElement. It should be noted here that these instruction processing plug-ins will only process instructions with args, because instructions without args have been processed in transformElement
From the perspective of these two instruction processing plug-ins, in fact, they are very similar to nodeTransforms. They do some processing and then package them according to the structure to facilitate generation. In fact, it is the same. Other instructions such as v-model and v-for will be packaged. Due to the author's limited level and energy, other instructions will not be implemented first

Posted by member123 on Tue, 23 Nov 2021 01:44:56 -0800