JSX Unchained: создайте шаблонизатор без React
Привет, разработчик.
Сегодня давайте поговорим о JSX, отношениях любви и ненависти всех разработчиков React. Многие его ненавидят, многим он нравится, но задумывались ли вы когда-нибудь, как можно максимально эффективно использовать возможности JSX вне обычного контекста React?
Ну, вы в правильном месте!
В огромном мире веб-разработки использование JSX в сочетании с React изменило способы создания динамических и отзывчивых пользовательских интерфейсов. Надо признать, что опыт разработки (DX), предлагаемый React, доминирует над другими фреймворками, и JSX является одним из факторов, способствовавших успеху этого начинания.
Однако иногда вы можете почувствовать необходимость освободить JSX от этой тесной связи с React, открывая тем самым двери новым творческим возможностям.
Давайте заглянем за кулисы
Вот здесь и возникают вопросы: как мы можем использовать JSX независимо, без веса React? Эта статья поможет вам создать шаблонизатор, который позволит вам сделать именно это.
Представьте себе, что вы можете использовать мощный синтаксис JSX в сценариях, выходящих за рамки традиционной среды, настроив способ оценки и отображения элементов JSX (довольно круто, да?).
Прежде чем углубиться в создание нашего шаблонизатора, давайте кратко рассмотрим, что находится за кулисами между JSX и React:
JSX, что означает JavaScript XML, — это своего рода язык разметки, очень похожий на HTML. На самом деле за тегом JSX находится функция React.createElement, которая управляет преобразованием компонентов. Да, теги JSX на самом деле являются функциями JavaScript (когда вы оправитесь от шока, продолжайте читать).
Первоначально JSX был разработан для использования исключительно с React, но со временем он все больше и больше развивался и стал рассматриваться как отдельный проект.
Поэтому наша цель — создать механизм шаблонов, который адаптируется к нашим потребностям с использованием JSX. Создаете ли вы легкое и быстрое приложение или исследуете необычные сценарии, этот механизм шаблонов станет ключом к открытию новых дверей для нашего творчества.
Дизайн шаблонизатора
Начнем с этого:
Я хочу сохранить DX React и написать ядро, способное транслировать мои функции JavaScript, обогащенные JSX, в представление чистого HTML.
Представьте себе, что вы можете декларативно определить свой пользовательский интерфейс, а затем волшебным прикосновением подготовить его к действию.
Но как нам всего этого добиться?
Все просто: нам нужен упаковщик! В частности, в этой статье я буду использовать Webpack, но вы можете все реконструировать с помощью Vite, EsBuild и т.п.
Я постараюсь вести вас шаг за шагом.
Давайте инициализируем проект.
Создайте новую папку и введите:
npm init -y
Сделанный? Большой.
Теперь нам нужны две вещи:
Первым делом нужно установить Webpack, а вторым — использовать транспилятор для «преобразования» нашего JSX в объекты JavaScript.
Что касается второго пункта, мы будем использовать Babel, но давайте пока сосредоточимся на Webpack.
npm i -D webpack webpack-cli webpack-dev-server html-webpack-plugin
Большой! Теперь давайте установим Babel.
npm i -D @babel/cli @babel/core @babel/preset-env babyl-loader
И последнее: нам нужен плагин Babel, который позволит нам транспилировать JSX. Мы углубимся в его использование позже.
npm i -D @babel/plugin-transform-react-jsx
Теперь, когда мы установили все необходимые зависимости, давайте добавим следующие скрипты в наш package.json
.
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"start": "webpack serve --open",
"dev": "webpack-dev-server --open"
}
Проще говоря, эти сценарии предназначены для запуска нашего проекта и его сборки, если мы захотим. Теперь нам нужно создать нашу «магию». Благодаря плагину Babel/plugin-transform-react-jsx
мы можем указать Babel обрабатывать специальную среду выполнения для транспиляции JSX.
По сути, теперь мы настроим, как Babel должен «оценивать» выражения JSX. Итак, в корне нашего проекта создадим файл jsx-runtime.js
.
const add = (parent, child) => {
parent.appendChild(child?.nodeType ? child : document.createTextNode(child));
};
const appendChild = (parent, child) => {
if (Array.isArray(child)) {
child.forEach((nestedChild) => appendChild(parent, nestedChild));
} else {
add(parent, child);
}
};
export const jsx = (tag, props) => {
const { children, ...rest } = props;
if (typeof tag === 'function') return tag(props, children);
const element = document.createElement(tag);
for (const p in rest) {
if (p.startsWith('on') && p.toLowerCase() in window) {
element.addEventListener(p.toLowerCase().substring(2), props[p]);
}
}
appendChild(element, children);
return element;
};
export const jsxs = jsx;
Это очень минимальное время выполнения позволяет нам преобразовать наши «компоненты» с реквизитами в чистый HTML, попрощавшись с виртуальным DOM. Учтите, что мы могли бы расширить среду выполнения для обработки пользовательских компонентов, директив или чего-либо еще, что придет на ум. Короче говоря, рассматривайте это как основу нашего шаблонизатора или будущей структуры.
Давайте добавим последний кусочек головоломки: файл конфигурации веб-пакета. Опять же в корне проекта создадим файл webpack.config.js
.
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
entry: './src/index.js',
mode: 'production',
output: {
path: `${__dirname}/dist`,
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.(?:js|jsx|mjs|cjs)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [['@babel/preset-env']],
plugins: [
[
'@babel/plugin-transform-react-jsx',
{
runtime: 'automatic',
importSource: path.resolve(__dirname + '/./'),
},
],
],
},
},
},
],
},
resolve: {
extensions: ['', '.js', '.jsx'],
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
}),
],
};
Если мы посмотрим на атрибут модуля, то обнаружим конфигурацию Babel и плагин плагина plug-in-transform-react-jsx, который ссылается на корень проекта для поиска нашего пользовательского файла времени выполнения.
Ааааа вот и все, мы закончили.
Если вам нужен рабочий пример того, что я описал до сих пор, я подготовил для вас функциональный проект на StackBlitz.
Чего не хватает? Система реактивности. Но это уже другая история...
Заключение
Итак, наше путешествие к открытию независимого шаблонизатора, основанного на JSX, подходит к концу. Мы изучили причины необходимости освобождения JSX от React, углубились в архитектуру механизма шаблонов и решили проблему реализации гибкого и мощного языка шаблонов.
Имея в своем распоряжении этот инструмент, вы теперь вооружены новым взглядом на веб-разработку. Взгляните на преимущества, которые эта свобода может принести в ваш повседневный рабочий процесс.
Ваш отзыв ценен. Если вы экспериментировали с предлагаемым шаблонизатором, у вас есть вопросы или предложения по его улучшению, поделитесь ими в комментариях. Если статья оказалась полезной, поделитесь ею со своими друзьями-разработчиками!