Добро пожаловать обратно! Поскольку я, кажется, нашел свой ритм письма, я решил, что продолжу пахать с этой серией постов о создании чего-то. Вы можете найти предыдущие посты здесь и здесь. Подводя итог, я:

  • Настроил мою локальную среду разработки для TypeScript.
  • Разработал очень простую реализацию паттерна Observer.

Благодаря этим мелочам у меня появился действительно простой способ уведомления компонентов, когда что-то меняется в моем состоянии. Далее идет действительно интересный момент. Теперь я хочу построить конкретную реализацию Observer, которая может проходить и обновлять DOM при изменении состояния. ДАВАЙТЕ НАПИШЕМ ТЕСТ.

В этом смысле у меня есть крошечный класс под названием Toy. Теперь его ответственность состоит в том, чтобы просто зарегистрироваться в качестве наблюдателя с любым контроллером, с которым он «обновлен». Отлично — теперь мы можем подписаться на изменения в состоянии нашего Controller и можем использовать его для обновления объектной модели документа! Итак, какую функциональность мы хотим добавить в этот новый класс? ? Первоначально я хотел бы поддерживать рендеринг из двойных усов в заданном документе с любым содержимым, представленным в состоянии моего Controller. НАПРИМЕР:

<div>
{{ test }}
</div>

Становится:

<div>
Hello, World!
</div>

Почему двуусый? Потому что могут быть законные причины, по которым потребители моей любимой библиотеки хотят завернуть куски текста в одиночные усы. Давайте не будем причинять им головную боль! Итак, похоже, здесь есть еще одна простая часть функциональности, которую мы можем прогнать в паре других тестов! Давайте сделаем это:

Я обновил свой конструктор, чтобы он принимал дополнительный параметр — HTMLElement для рендеринга. Реализация update моего класса Toy теперь использует этот элемент «Root» для поиска и замены любых двойных касаний правильно отображаемым содержимым (как определено в state класса Controller). Я также обновил функцию registerObserver контроллера, чтобы она автоматически обновляла все вновь зарегистрированные наблюдатели. Это означает, что все наблюдатели получают актуальную копию состояния контроллера при регистрации.

Но что происходит при последующем повторном рендеринге? Давайте напишем еще один тест и посмотрим!

Так что это не работает по довольно веской причине — как только я снял усы с DOM, я потерял контекст того, где исходные усы были. Любое последующее удаление усов обречено на провал, потому что усов больше нет.

Давайте это исправим!

Последняя версия класса Toy просто создает глубокий клон исходного HTMLElement и использует это для поиска необходимых усов, которые нужно ИСКЛЮЧИТЬ из DOM. Это чрезвычайно наивная реализация динамического рендеринга DOM, но она хорошо работает для этого последнего теста. Только одно: мы еще не «привязали» этот код к настоящей HTML-странице. Это все догадки, причуды и капризы. Давайте разберемся с этим, как гласит старая поговорка:

Интегрируйте рано и часто

Все, что я хочу здесь сделать, это предоставить простую страницу индекса и создать экземпляр Toy с использованием тега сценария. Это тоже мы можем прогнать с тестами! Ниже показан общий подход, включающий несколько новых зависимостей npm, а именно supertest и express:.

В приведенном выше Gist есть довольно много поправок, поддерживающих это, поэтому давайте рассмотрим их все по отдельности.

app.js

Этот файл кода настраивает очень простое веб-приложение с помощью экспресс. Он обслуживает все по пути dist как статические ресурсы и обслуживает файл index.html по маршруту по умолчанию.

сервер.js

Здесь мы просто загружаем сервер Express и обслуживаем указанное выше приложение на порту 5678.

index.html

Это простой каркасный html-файл с единственной ссылкой на скрипт, которая указывает на транспилированный файл toy.js, созданный Webpack с использованием ts-loader. Заметили, что сценарий находится на странице последним? Это довольно важно…

пакет.json

Здесь я просто указываю на совершенно новую шикарную задачу serve, которая будет транспилировать весь вкусный TypeScript в один транспилированный артефакт.

сервер.test.js

Здесь мы просто устанавливаем, что Express работает правильно. Что мы обслуживаем стандартную HTML-страницу с успешным кодом состояния HTTP. Мы можем продолжить этот тест в ближайшее время, но пока это минимальное количество вещей, которые я хочу утверждать, откровенно говоря!

index.ts

Это точка входа для приложения! Он включает в себя 3 экспорта. Toy, Controller и MockController. Мы собираемся использовать MockController для начальной загрузки этого тривиального примера, но обязательно исключим его из приложения в дальнейшем!

webpack.config.js

Это очень важно! Поскольку контекст toy-js должен запускаться в браузере, крайне важно, чтобы здесь была настроена опция library. Это приводит к пространству имен переданного кода JavaScript, чтобы он был доступен в браузере. Это, в сочетании с тем фактом, что все классы TypeScript должны иметь именованный экспорт, является ключом к тому, чтобы сделать библиотеку доступной из веб-браузера. Это заняло у меня больше времени, чем я готов признать…

И вуаля! Я знаю, что в этом посте я рассмотрел миллиард вещей, но в основном он сводится к нескольким основным вещам. Я создал простой класс Toy, который может анализировать DOM и манипулировать им. Затем мы приложили небольшие усилия для создания очень простого тестового комплекта. Мы узнали немного больше о нашей конфигурации Webpack и указали новый файл экспорта по умолчанию, который используется для экспорта всех типов, которые могут нам понадобиться в окончательном транспилированном дистрибутиве.

Мое уважение к инженерам, стоящим за React, Vue и другими фреймворками, растет в геометрической прогрессии! В следующий раз я посмотрю на расширение тестов здесь, чтобы включить некоторые отзывы о производительности. Сколько времени требуется этой штуке для рендеринга простого родительского div? Как насчет дочерних компонентов?

ЭТО ВСЕ ДЛЯ ИГРЫ, БАРРИ!

Первоначально опубликовано на https://blog.thesheps.dev 24 июня 2019 г.