Сегодня мы рассмотрим процесс написания своего собственного плагина babel и опубликуем его в npm.
Babel — что это?
Исходя из официальной документации, babel — это набор инструментов, который позволяет преобразовывать код ECMAScript 2015+ в обратно совместимую версию JavaScript.
Например, плагин @babel/plugin-transform-react-jsx преобразовывает *.jsx в *.js:
jsx
const profile = ( <div> <img src="avatar.png" className="profile" /> <h3>{[user.firstName, user.lastName].join(" ")}</h3> </div> );
js
const profile = React.createElement( "div", null, React.createElement("img", { src: "avatar.png", className: "profile" }), React.createElement("h3", null, [user.firstName, user.lastName].join(" ")) );
Вся эта магия происходит благодаря Abstract Syntax Tree (AST). Грубо говоря, AST представляет ваш код как дерево нод (объектов) с определенными свойствами.

Основная идея babel — это взять ваш код -> представить его в дереве AST -> произвести трансформацию узлов дерева -> сгенерировать код из обновленного AST.

Пишем свой плагин
Теперь когда мы познакомились с тем, как работает babel мы можем приступить к написанию собственного плагина. В этом примере плагин будет добавлять брать стили из конфига и применять их для выводов console.

Для начал создадим новый проект и добавим необходимые зависимости:
mkdir babel-plugin-styled-console-output cd babel-plugin-styled-console-output touch index.js yarn add -D @babel/core
В index.js добавим следующий код:
const babel = require("@babel/core"); module.exports = function () { const LogVisitor = { CallExpression(path, state) { const { callee, arguments } = path.node; if (callee.object && callee.object.name === "console") { const styles = state.opts.types[callee.property.name]; if (styles) { let parsedStylesToString = ""; let divider; Object.keys(styles).forEach((key) => { if (key === "divider") { divider = styles[key]; } else { parsedStylesToString += `${key}: ${styles[key]}; `; } }); const str = arguments .map((arg) => { if (arg.type === "StringLiteral") { return arg.value; } }) .join(divider || " "); const newArgs = [ babel.types.stringLiteral(`%c${str}`), babel.types.stringLiteral(parsedStylesToString), ]; path.node.arguments = newArgs; path.node.callee.property.name = "log"; } } }, }; return { visitor: LogVisitor }; };
Теперь пройдем подробнее по тому что мы написали выше:
На строке 4 мы создаем новый объект, который возвращаем на строке 42. Тем самым мы создаем visitor, который будет проходить по нашему коду в момент запуска babel.
Внутри объекта (на строке 5) мы вызываем один из типов в ASTCallExpression. Вы можете спросить откуда вообще взялся этот CallExpression? Хороший вопрос!
Есть замечательный инструмент Babel AST explorer. Давайте перейдем туда и напишем console.log('text');

Кликнув на строку 1, справа мы увидим вышеупомянутое дерево AST. Теперь мы видим что наш вызов console.log представлен в дереве как узел CallExpression с полями callee и arguments. Эти поля мы достаем на строке 6 нашего кода с помощью path.node.
Теперь, когда мы немного понимаем что происходит под капотом, вернемся в наш код. На строке 8 мы проверяем что у нас действительно вызывается метод объекта Console.
На строчке 9 мы достаем данные из нашего конфига (с помощью state.opts), который выглядит следующим образом:
{ "types": { "error": { "color": "white", "background": "blue", "divider": "---" }, } }
Далее мы превращаем наш конфиг в строку, что бы в дальнейшем использовать ее как второй аргумент при вызове console.log (встроенная возможность функции log)
console.log('%csometext', 'color: red');
На строке 23 мы собираем все аргументы переданные в log в одну строку и разделяем их с помощью divider переданного в конфиг (или ' ' по умолчанию).
Затем на строке 31 мы создаем новый массив с аргументами и заменяем старые на строке 35. На 36 строке мы заменим .warn, .error и тд. на .log (тк стили доступны только для log функции).
На этом мы закончим с написание плагина и приступим к публикации его в npm.
Публикуем плагин в npm
Для публикации мы будем использовать yarn. В консоле вашего проекта напишите:
yarn init и ответьте на вопросы.
Далее, следуя этой инструкции, мы должны войти/зарегестрироваться в npm.
После того, как вы вошли, запустите:yarn publishи дождитесь окончания публикации.
Поздравляю! Мы опубликовали наш плагин в npm. Теперь настало время добавить его в проект и настроить.
Добавляем плагин в проект
Я взял свой первый попавшийся проект на React и добавил созданный плагин с помощью:
yarn add -D babel-formatted-log
Далее открыл файл .babelrc / babel.config.json и добавил конфигурацию для плагина:
{ "plugins": [ // ... [ "module:babel-formatted-log", { "types": { "error": { "color": "white", "background": "blue", "divider": "---" }, "log": { "border": "1px solid #d64021 ", "font-weight": "800", "padding": "10px" } } } ] ] }
Теперь соберем проект и напишем где-нибудь:
console.error("babel", "test"); console.log("text1", "text2", "text3");
В результате мы получим вывод похожий на этот:

Заключение
Сегодня мы написали свой собственный babel плагин и опубликовали его в npm. Этот плагин не несет какой-либо практической пользы, он создан в рамках ознакомления 🙂
Весь код и документация по плагину лежат на Github.
Спасибо что прочитали!
ссылка на оригинал статьи https://habr.com/ru/post/704028/
Добавить комментарий