Поговорим об изобретении велосипеда. Основная философия, в которую я всегда верил, - это узнать как можно больше о тонкостях всех используемых вами инструментов. Загляните в репозитории GitHub с библиотеками, которые вы используете, и попытайтесь получить реальное представление о том, как крутятся механизмы в мозгу автора.
Но больше всего я предлагаю всем, кто хочет получить истинное представление о фреймворках, библиотеках и инструментах, которые они используют, - создавать свои собственные. Давай, изобретай велосипед.
Я слышу, как люди говорят о том, чтобы изобретать колесо заново, как будто это плохо, но как еще можно получить реальное, глубокое понимание того, как эти штуки устроены? Создание клонов уже существующих вещей поможет вам понять, что эти фреймворки, библиотеки, языки программирования, которые мы используем каждый день, не волшебство. В них есть ошибки и странности, как и все мы когда-то писали.
Когда я только начал программировать, я пробовал делать игры. Через некоторое время я понял, что хочу узнать больше о том, как игровые движки, которые я использовал, работают внутри - как все взаимозависимые движущиеся части системы образуют единое целое. Создание собственных языков программирования заставило меня писать более эффективный код. Эти проекты могут никогда не увидеть свет. Но их создание было бесценным и сформировало то, как я программирую сегодня.
Последние несколько месяцев я использовал React для создания веб-сайта под названием BidSquid. За это время я достаточно хорошо познакомился с жизненным циклом компонентов React и потратил много времени на написание JSX. Как ни странно писать HTML-подобный код прямо в вашем JavaScript, мне это действительно нравится. На прошедших выходных я решил немного повеселиться и создать свой собственный HTML -подобный язык, такой как JSX.
У меня были идеи для этого языка в течение нескольких месяцев, но я так и не дошел до его создания. Моя основная идея заключалась в том, что на более высоком уровне CSS и JavaScript имеют похожий синтаксис - фигурные скобки и точки с запятой. Объявления стилей CSS даже выглядят как объекты JSON. HTML, будучи языком разметки на основе XML, выглядит совершенно иначе, поскольку все вложено в , а не в фигурные скобки. Я хотел сделать простой язык, который больше подходил бы для CSS и JS и конвертировал бы напрямую в HTML. Расскажу, как это было.
Для начала я написал простой лексический анализатор. Для тех, кто не знает, что это такое, вкратце, лексер - это то, что считывает ввод (например, содержимое файла) и выводит токены - токен может быть идентификатором, строкой, фигурным скобка, точка с запятой или любой другой символ (или набор символов), который может быть в вашем коде. По большей части лексеры, как правило, почти одинаковы и могут использоваться повторно от проекта к проекту. У меня было преимущество в работе с лексером, так как я писал их на C ++ раньше, и мне нужно было просто переписать его на JavaScript.
Для следующей части я написал парсер. Синтаксический анализатор берет токены, сгенерированные лексером, и анализирует все это. Если бы мы подумали об этом в контексте письменного языка, такого как английский, вы могли бы определить токен как отдельное слово, апостроф, восклицательный знак, что у вас есть. Задача парсера - объединить эти токены в логический формат - предложение.
В отличие от лексеров, синтаксические анализаторы довольно специфичны для языка, который вы создаете. По этой причине я стал больше времени уделять синтаксическому анализатору. За несколько часов я смог собрать базовый рабочий прототип того, что я называю blockml - потому что, ну, ну, блоки. И язык разметки. (Вы можете скачать blockml с помощью npm)
После создания этого небольшого языка я решил, что мне следует сделать расширение, которое позволит пользователям определять свои собственные компоненты и писать их прямо на языке разметки, как и любой другой div
. Компоненты должны иметь свойства, состояния, вложенные дочерние компоненты, что угодно. Я решил назвать этот проект blockml-компонентом. Потому что это блочный код с компонентами. (Вы можете скачать blockml-компонент на npm)
Я начал с расширения самого blockml для поддержки пользовательских обработчиков для определенных тегов. Предполагая, что вы добавили собственный обработчик для любого элемента div, blockml отправит этот обработчик, а не выводит ‹div› в HTML, как обычно. С помощью этих настраиваемых обработчиков blockml-component может взять под контроль и реализовать более сложные функции для определяемых пользователем компонентов.
Пользовательские компоненты состоят из render()
метода, как и в React. Основное отличие состоит в том, что вместо записи элементов JSX с помощью ‹tags› функции рендеринга просто нужно вернуть строку, содержащую код blockml, который затем можно передать лексеру и синтаксическому анализатору. Используя новые строки шаблона ES6 (обратная кавычка), вы можете встроить код JavaScript с помощью встроенного ${}
, точно так же, как {}
в React или {{}}
в AngularJS.
В следующей части мы поговорим о технических деталях. Объяснять код поверх текста всегда сложно, поэтому, если вы хотите лучше понять, как работает эта часть, посмотрите ее на GitHub.
Когда вы впервые определяете компонент, blockml-component делает некоторые вещи, чтобы заставить работать props и дочерние компоненты. Он берет все атрибуты, которые были написаны для элемента, и добавляет их к объекту «props». Этот объект передается методу render
нашего компонента. Он также берет все вложенные компоненты, которые были записаны в наборе фигурных скобок компонента, помещает их в массив с именем _cachedChildren
для последующего использования и заменяет их временным элементом с именем __InnerChildren
. К этому временному элементу прикреплен атрибут index
, который мы будем использовать позже, чтобы указать нам на правильный объект в _cachedChildren
. Таким образом, дочерние компоненты не нужно подвергать анализу и синтаксическому анализу более одного раза, и их можно просто соединить позже.
У меня есть собственный обработчик, настроенный для любых найденных __InnerChildren
элементов, который просто извлекает атрибут index
и заменяет его объектом, спрятанным в _cachedChildren
. На этом этапе все должно быть заполнено, а дочерние элементы должны быть переданы вложенным элементам. Все выглядит так, как я ожидал, из мира React. Как бы просто он ни был прямо сейчас - он функционален, и он уже в той точке, где его можно надстроить и превратить во что-то потрясающее.
Спасибо, что прочитали мою статью и позволили мне рассказать вам мою историю о том, как и почему я создал свой собственный «React». Я надеюсь, что вы когда-нибудь подумаете об изобретении велосипеда. Хотя он не может быть заменой более популярных библиотек и фреймворков, вы многому научитесь и станете более умным программистом для этого.
Ссылки
- Скачайте или попробуйте blockml-компонент (расширение для blockml): https://www.npmjs.com/package/blockml-component
- Исходный код blockml-компонента на GitHub: https://github.com/ajmd17/blockml-component
- Загрузите или попробуйте blockml: https://www.npmjs.com/package/blockml
- Исходный код blockml на GitHub: https://github.com/ajmd17/blockml