Буквально два дня назад я брал интервью у крупного завода, и был такой вопрос:
- Вы знали Бабеля?
Знать абстрактное синтаксическое дерево, также известное как AST, изучать его и писать на основе ASTШаблонизатор нищего, сначала лексически разобрать токен, затем создать абстрактное синтаксическое дерево, затем изменить абстрактное синтаксическое дерево, конечно же, это то, что делает плагин, и, наконец, сгенерировать код на основе нового AST.
- Вы написали плагин для Babel?
Нет, просто прочитайте соответствующую документацию
- Если бы вас попросили написать плагин, смогли бы вы его написать?
Это может сработать...
Умер....
Шучу, с тех пор, как я об этом упомянул, я ничего не ответил О, мой темперамент, я не могу спать, когда думаю об этом сегодня вечером, и я ударил его за ночь.
Итак, давайте напишем плагин с нуля.
Напишите плагин, который предварительно вычисляет простые выражения
предварительный просмотр
Before:
const result = 1 + 2 + 3 + 4 + 5;
After:
const result = 15;
Вышеприведенные примеры могут встречаться не часто, потому что глупый х напишет так, но возможно, что и вы напишете так
setTimeout(function(){
// do something
}, 1000 * 2) // 插件要做的事,就是把 1000 * 2 替换成 2000
Предварительные условия
Начало
Прежде чем писать код, вам нужно понять, как работает Babel.Проще говоря:Babel анализирует его в AST, затем плагин изменяет AST, и, наконец, Babel выводит код.
Затем подключаемый модуль Babel требует, чтобы вы предоставили функцию, и функция возвращает посетителя
module.export = function(babel){
return {
visitor:{
}
}
}
Посетитель — это место, где обрабатываются различные типы узлов AST, так как же узнать, какие узлы находятся в AST, сгенерированном Babel?
Очень просто, вы можете распечатать результат Бабелевского преобразования, или здесь есть порталы:AST explorer
Здесь мы видимconst result = 1 + 2середина1 + 1ЯвляетсяBinaryExpressionузел, то в посетителе мы обрабатываем этот узел
var babel = require('babel-core');
var t = require('babel-types');
const visitor = {
BinaryExpression(path) {
const node = path.node;
let result;
// 判断表达式两边,是否都是数字
if (t.isNumericLiteral(node.left) && t.isNumericLiteral(node.right)) {
// 根据不同的操作符作运算
switch (node.operator) {
case "+":
result = node.left.value + node.right.value;
break
case "-":
result = node.left.value - node.right.value;
break;
case "*":
result = node.left.value * node.right.value;
break;
case "/":
result = node.left.value / node.right.value;
break;
case "**":
let i = node.right.value;
while (--i) {
result = result || node.left.value;
result = result * node.left.value;
}
break;
default:
}
}
// 如果上面的运算有结果的话
if (result !== undefined) {
// 把表达式节点替换成number字面量
path.replaceWith(t.numericLiteral(result));
}
}
};
module.exports = function (babel) {
return {
visitor
};
}
Плагин написан, давайте запустим плагин и попробуем
const babel = require("babel-core");
const result = babel.transform("const result = 1 + 2;",{
plugins:[
require("./index")
]
});
console.log(result.code); // const result = 3;
как и ожидалось, то преобразованиеconst result = 1 + 2 + 3 + 4 + 5;Шерстяная ткань?
оказаться:const result = 3 + 3 + 4 + 5;
Это странно, зачем только считать1 + 2После этого нет дальнейшей операции?
Давайте посмотрим на дерево AST для этого выражения.
Вы обнаружите, что Babel анализирует выражения, а затем вкладывает их внутрь.
表达式( 表达式( 表达式( 表达式(1 + 2) + 3) + 4) + 5)
И условия нашего суждения не всем удовлетворяют, только1 + 2
// 判断表达式两边,是否都是数字
if (t.isNumericLiteral(node.left) && t.isNumericLiteral(node.right)) {}
тогда мы должны изменить
первый расчет1 + 2После этого получаем такое выражение
表达式( 表达式( 表达式(3 + 3) + 4) + 5)
в3 + 3Снова соответствует нашим условиям, мы рекурсивно обходим родительский узел вверх.
Снова преобразовал в это:
表达式( 表达式(6 + 4) + 5)
表达式(10 + 5)
15
// 如果上面的运算有结果的话
if (result !== undefined) {
// 把表达式节点替换成number字面量
path.replaceWith(t.numericLiteral(result));
let parentPath = path.parentPath;
// 向上遍历父级节点
parentPath && visitor.BinaryExpression.call(this, parentPath);
}
Здесь мы получаем результатconst result = 15;
Что касается других операций:
const result = 100 + 10 - 50 >>> const result = 60;
const result = (100 / 2) + 50 >>> const result = 100;
const result = (((100 / 2) + 50 * 2) / 50) ** 2 >>> const result = 9;
конец
К этому моменту я уже примерно объяснил вам, как написать плагин для Babel, и я больше не боюсь, что интервьюер спросит меня на то, на что я не смогу ответить...
Вы думали, что это закончилось?
нисколько
Если вы преобразуете это:const result = 0.1 + 0.2;
Ожидается, что он будет0.3, но на самом деле в Javascript есть ошибки вычисления с плавающей запятой, и результат0.30000000000000004
Этот плагин бесполезен?
Это требует, чтобы вы исправили ошибку операции с плавающей запятой, вы можете использоватьBig.js;
Например:result = node.left.value + node.right.value;изменить наresult = +new Big(node.left.value).plus(node.right.value);
Как вы думаете, это конец? Этот плагин может сделать гораздо больше
Например:Math.PI * 2 >>> 6.283185307179586
Например:Math.pow(2, 2) >>> 4
...
...
Последний адрес проекта:GitHub.com/A XE Трой/Папа…