Некоторое время назад я наткнулся на работу Кента С. Доддса над макросами babel-plugin-codegen и Babel в Twitterverse и подумал, что это круто, но в то время у меня не было варианта использования. Я попытался втиснуть это где-нибудь в глубину своей памяти для использования в будущем. Это время пришло более года спустя, и я мог сказать, что воспоминания всплыли и сказали: «Бен, ты мог бы использовать это babel-plugin-codegen прямо сейчас». Однако этого не произошло. Вместо этого я увидел другой твит о babel-plugin-codegen.

Фон

Когда мой друг назовем его Джейком (потому что это его имя) и я начали новый проект на работе, мы придумали новое соглашение об именах файлов для компонентов React / Redux. Джейка немного беспокоило то, что он видел в проектах, над которыми работал, и он придумал альтернативу. Я добавил свои два цента, и мы наконец пришли к следующему:

Пример компонента Redux / React

Структура папки

Внутри ‹component› .connect.js

Файл ‹component› .connect.js содержит функции mapStateToProps и mapDispatchToProps, необходимые для функции react-redux connect. В приведенном выше случае не было необходимости в mapStateToProps. Затем он по умолчанию экспортирует результат вызова connect(null, mapDispatchToProps).

index.js для компонента React / Redux

Пример компонента React (без подключения react-redux)

index.js для компонента React (без подключения response-redux)

Файл компонента index.js действует как связующее звено между компонентом и функцией react-redux connect, экспортирующей результат, или просто экспортирует компонент, если нет необходимости в Redux. В случае отсутствия Redux может возникнуть соблазн заставить любой потребляющий компонент напрямую импортировать компонент. Однако импорт компонентов таким же образом был предпочтительнее небольшого количества шаблонного кода. Итак, независимо от того, требуется ли компоненту Redux или нет, импорт был таким же, как вы можете видеть ниже:

Если бы мы использовали подход, не включающий index.js для компонента без Redux, у нас было бы следующее, что означает, что вам нужно было бы знать, подключен ли компонент к Redux, перед его импортом.

Разделение файловой структуры компонента на * .component.js, * .connect.js, * .styles.js и index. js предназначен для четкого разделения проблем, но также помогает искать файлы в браузере и в среде IDE.

Вы сказали что-то о генерации кода, а где это тогда?

Когда мы согласовали этот подход к структуре файлов компонентов, мы прокомментировали, что файл index.js является просто шаблонным кодом. После настройки вам, вероятно, не придется часто возвращаться к нему, только, может быть, когда вы поймете, что вам нужно подключить его к магазину Redux или вам нужно отсоединиться от Redux в рамках некоторого рефакторинга. Поэтому было бы полезно, если бы вы могли автоматически генерировать соответствующий импорт и экспорт и восстанавливать их каждый раз, когда вы добавляете / удаляете файл * .connect.js. Вот тут-то и пригодится babel-plugin-codegen.

babel-plugin-codegen

Плагин запускается во время сборки (в моем случае через webpack / babel-loader), генерируя строку кода из кода и внедряя ее в указанное вами место. Ниже показаны до и после файла компонента index.js:

Используя комментарий /* codegen */, плагин знает, что нужно выполнить код в generateComponentIndex.js во время сборки, передавая значение Node.js __dirname (имя каталога текущего модуля) и, наконец, вводя возвращаемое значение из generateComponentIndex.js вместо оператора импорта, содержащего /* codegen */.

generateComponentIndex.js использует модуль файловой системы Node.js (fs) для получения списка файлов для directory, переданного в качестве аргумента. В нашем случае это будет каталог для того компонента, который оценивается babel-loader / webpack. С babel-plugin-codegen вы можете использовать любой модуль Node.js, который работает синхронно.

Чтобы продемонстрировать, как это работает, я составил список задач. Да, это просто еще один список дел, но мне нравятся слова «список задач», потому что «дело» звучит так, как будто вы должны их выполнить, а не как список задач, ну, это не похоже на то, что он заставляет вас это делать. В конце вы найдете ссылки на репо и пример списка рабочих задач.

Предостережение - если вы реорганизуете компонент, чтобы добавить Redux (добавив файл * .connect.js) или удалить Redux (удалить файл * .connect.js ), чтобы webpack-dev-sever принял ваши изменения, вам нужно отредактировать файл index.js, чтобы вызвать перестройку. Обычно я добавляю дополнительный пробел. При использовании webpack для создания производственной сборки это не проблема, потому что он будет выполнять любой babel-plugin-codegen код каждый раз.

Влияет ли это на время сборки?

Немного.

Я провел эксперимент. Ну вроде как. Я создал два проекта React, каждый из которых содержит сотню базовых компонентов: один использует babel-plugin-codegen, а другой нет. Для каждого проекта я записал, сколько времени потребовалось для запуска webpack-dev-server сразу после установки новых зависимостей (холодный запуск), сколько времени потребовалось для запуска webpack-dev-server после предыдущего запуска (теплый запуск) и, наконец, сколько времени потребовалось webpack-dev-server для перекомпиляции, когда компонент index.js файл был изменен. Я повторил эти задания 5 раз и взял «научное» среднее значение.

Проект, не использующий babel-plugin-codegen, в среднем выполнялся немного быстрее для каждой задачи. Для теста холодного старта проект без использования babel-plugin-codegen был на 0,1758 секунды быстрее, чем проект с использованием babel-plugin-codegen, на 0,0171 секунды быстрее для теста горячего запуска и на 0,015 секунды быстрее для теста изменения отдельного файла.

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

Дальнейшие варианты использования

Как сказано в babel-plugin-codegen README: «Применение этого плагина очень широкое». В моем примере я также использовал его для обеспечения соблюдения соглашений об именах файлов для каждого файла, связанного с компонентом, убедившись, что каждое имя файла начинается с символа нижнего регистра.

С этим дополнительным фрагментом кода webpack не сможет скомпилироваться, если обнаружит ошибку (в приведенном ниже случае я изменил addTask.component.js на AddTask.component .js).

babel-plugin-codegen очень мощный. При умеренном использовании он может помочь во многих случаях использования. Но слишком широкое использование может привести к тому, что код будет труднее понять. Здесь очень помогает хорошая документация в виде комментариев. Хотя наш вариант использования может быть не идеальным, он помог нам сократить количество редко посещаемого шаблонного кода, а также дал нам повод попробовать что-то новое и интересное.

Подведение итогов

Чтобы узнать больше о babel-plugin-codegen, перейдите на https://github.com/kentcdodds/babel-plugin-codegen, а также посетите https://github.com/kentcdodds/babel-plugin-macros

Примеры кода, упомянутые выше (и список задач), можно найти здесь https://github.com/mrbenhowl/auto-gen-boilerplate-code-babel-macro-codegen и здесь https: //mrbenhowl.github .io / auto-gen-template-code-babel-macro-codegen / .

Результаты моего действительно научного эксперимента 😉 можно найти здесь и здесь.

PS - Если вы еще не подписаны на Кента в Твиттере (https://twitter.com/kentcdodds), я настоятельно рекомендую вам это сделать, за его фантастическую работу и за то, что он в целом кажется хорошим парнем.

Спасибо за прочтение. Хорошего дня 😁 🇦🇺