Создание компонентов Vue.JS
Используйте макросы babel и макрос codegen для создания компонентов, совместимых с SSR.
Недавно я создал компонент кнопки, который должен был иметь значок либо слева, либо справа от текста. API примерно такой:
<icon-button right-glyph="lock">Sign In</icon-button
Свойство right-glyph
принимает строку, соответствующую некоторому SVG. Проблема, с которой я столкнулся, заключалась в том, что мне нужно было импортировать все SVG в объект и сопоставлять свойства глифа с ключами объекта.
const svgs = { lock: () => import('src/assets/svg/lock.svg'), eye: () => import('src/assets/svg/eye.svg'), ... }
Это было бы утомительно поддерживать; каждый SVG в assets/svg
должен иметь соответствующий ключ в объекте svgs
.
Хорошим решением этой проблемы является создание объекта svgs
из SVG, которые существуют в папке во время компиляции. Таким образом, наш объект всегда синхронизируется, и мы можем использовать папку SVG в качестве ссылки при передаче свойств нашему компоненту.
Для реализации этого решения мы можем использовать babel-макросы. babel-macros позволяет запускать преобразования кода в виде пользовательских макросов. Мы используем макрос codegen. Макрос codegen требует, чтобы код, который вы хотите выполнить во время времени выполнения, был преобразован в строку во время во время компиляции.
Я создал функцию, которая находит все файлы в моей папке SVG и сопоставляет их имена файлов со строковым представлением объекта. Этот объект будет выглядеть так:
{
name: 'lock',
component: () => require.ensure(
[],
(require) => require('../../assets/svgs/lock.svg'
)
}
Функция возвращает строку, которая при преобразовании в код сократит отображаемые объекты в один объект для использования.
Примечание. Я использую Webpack для включения разделения кода, поэтому require.ensure
.
Примечание 2. vue-svg-loader загружает svgs как компоненты Vue.js.
Использовать функцию generateSvgComponents
теперь легко. Нам просто нужно сказать codegen
экспортировать результат функции:
Теперь, когда мы запускаем нашу среду разработки или собираем приложение, codegen сгенерирует код, необходимый для установки переменной svgs
, что позволит нам использовать ее в другом месте:
<svg-loader :name="selectedSvg" />
Настраивать
Добавьте макросы babel и настройте babel
$ yarn add --dev babel-macros
В файле .babelrc
добавьте "babel-macros"
к плагинам:
{ "presets": [...], "plugins": [ "babel-macros", ... ] }
Добавьте свои макросы
$ yarn add --dev babel-plugin-codegen
См. этот пост для получения дополнительной информации о макросах babel и доступных макросах.
Примечания
Если вы собираетесь использовать vue-svg-loader
или что-то подобное, гораздо проще импортировать SVG как точку разделения кода:
{ template: `<div><lock-icon /></div>`, components: { LockIcon: () => import('./lock.svg') } }
Это гораздо более явно. Подход, который я описал, действительно полезен только в некоторых конкретных случаях, например, для компонента IconButton.
Кодекс
Источник: https://github.com/johnnynotsolucky/samples/tree/master/generated-svgs
Демонстрация: https://johnnynotsolucky.github.io/samples/generated-svgs/
P.S. У меня не было возможности понять, как использовать () => import('...')
вместо () => require.ensure(...)
. import
является предпочтительным способом для динамического разделения кода, но он генерирует синтаксическую ошибку при запуске внутри макроса. Если у кого-то есть решение, это было бы здорово!