Как лучше всего структурировать приложение Vue.js, чтобы оно масштабировалось и оставалось обслуживаемым и расширяемым по мере его роста? Этот вопрос я слышал неоднократно, и думаю, что один из ответов на него кроется в принципе предсказуемости. Когда речь идет о создании масштабируемого проекта, вы хотите, чтобы все в нем было максимально предсказуемо.
Что именно я подразумеваю под предсказуемостью? В самом простом смысле, это способность интуитивно перейти от запроса функции или сообщения об ошибке к тому месту в кодовой базе, где эта задача может быть решена. Более того, это возможность быстро узнать, к каким инструментам вы имеете доступ в этом месте кодовой базы, чтобы выполнить поставленную задачу.
Почему это важно? Вы наверняка сталкивались с ситуацией, когда получали в наследство проект или были введены в него, а затем при выполнении первой задачи открывали кодовую базу и думали: "Я даже не знаю, с чего начать!".
Возможно, вы даже имели дело с кодовой базой в течение некоторого времени и возникала та же мысль! Предсказуемая кодовая база максимально облегчает этот опыт, делая знакомство разработчиков с проектами более простым, а продолжение работы — более эффективным.
Стоит отметить, что, хотя предсказуемость возможна, ни один проект никогда не станет предсказуемым на 100%. Каждый проект, новый или существующий, имеет хотя бы небольшую кривую обучения. Также следует знать, что предсказуемость не означает, что кодовая база или приложение будут быстро понятны в целом. Многие крупномасштабные приложения просто слишком сложны, чтобы это было возможно, и потребуется время, чтобы понять их целиком. Таким образом, предсказуемость — это не видение полной законченной картины, а скорее понимание структуры определенного фрагмента и возможность быстро понять, куда он встраивается. На самом деле, специфика хорошей кодовой базы такова, что ее можно понять по частям, и она не должна требовать от разработчиков необходимости думать обо всем сразу.
Как же добиться предсказуемости в кодовой базе? Ответ: стандарты, простые и понятные. Возможно, это не тот ответ, который вы ищете, но это правда. Лучший способ сделать что-либо предсказуемым — это следовать набору стандартов. Например, я могу почти со 100% уверенностью предсказать, что новые полноразмерные простыни, которые я купил только сегодня, подойдут к моей кровати, даже если я никогда раньше не заправлял ее ими. Почему? Потому что существует стандартная система определения размеров постельного белья.
Стандарты предсказуемости для сообщества
В связи с этим возникает вопрос, какие стандарты есть для сообщества Vue.js в целом? Я бы сказал, что существуют 4 источника.
Стайлгайд Vue.js
Временные платформы, сгенерированные Vue CLI
Официальные библиотеки Vue.js (находятся в разделе Ecosystem > Official Projects на сайте Vue.js)
и более свободные, наиболее популярные компонентные фреймворки, такие как Vuetify или Quasar.
Хотя некоторые из них официально считаются стандартами в большей степени, чем другие, я думаю, что все вместе они дают возможность иметь некоторые общие шаблоны между проектами и разработчиками, что приводит к более предсказуемым кодовым базам.
Официальные библиотеки и библиотеки компонентов
Для начала поговорим о стандартизации, которую обеспечивают официальные и популярные библиотеки компонентов. Хотя основной целью таких библиотек является предоставление функциональности, это также косвенно способствует применению общих стандартов. Если вы используете Vue Router, например, вы не только пользуетесь функциональностью самого пакета, но и в конечном итоге реализуете маршруты в одном проекте так же, как в другом, и точно так же, как их реализуют разработчики Vue.js по всему миру.
Библиотека Vuex фактически признает и рекламирует этот факт как главную особенность, называя себя «паттерн управления состоянием + библиотека».
Это может показаться очевидным, однако в этом есть смысл. Если в Vue.js существует популярное или рекомендуемое решение проблемы (и тем более, если это официальное решение), я бы крепко задумался, прежде чем использовать что-то другое. Мне, как и любому человеку, нравится создавать свои собственные компоненты, хранилища и т.д., но часто в долгосрочной перспективе действительно целесообразно использовать проверенные и верные решения не только из-за функциональности, тестового обеспечения и документации, которые они предлагают, но и из-за стандартизации, которую они привносят. (И разве в мире JavaScript мы все не можем применить немного больше стандартизации?).
Когда дело доходит до выбора использования этих более стандартизированных решений, важно помнить, что именно вы создаете. Вы создаете масштабируемый компонент многократного использования? Тогда, возможно, стандартная библиотека не для вас, потому что новая стандартная библиотека — это как раз то, что вы пытаетесь создать. Однако, вероятно, большинство из нас строит не это. Скорее всего, вы создаете приложение, и в этом случае лучше использовать стандартные (или хотя бы полустандартные) компоненты, которые уже существуют в качестве строительных блоков.
Основы стандартной файловой структуры
Когда дело доходит до стандартов проекта, файловая структура — это часто обсуждаемая тема, и хотя в Vue нет документации, определяющей конкретную структуру, она обеспечивает хорошую отправную точку из кодовой базы, созданной с помощью Vue CLI.
Большинство из нас, вероятно, знакомы с данной структурой, и это здорово! Значит, мы на шаг ближе к предсказуемости! Итак, суть заключается в том, что не стоит слишком задумываться об этом. Придерживайтесь того, что Vue дает вам из коробки, и не отклоняйтесь, пока у вас не будет действительно веской причины.
Я, конечно, думаю, что можно сделать разумные дополнения (и мы поговорим о них подробнее через минуту), но нет никаких реальных причин вносить изменения в то, что уже есть. С этой автоматически создаваемой файловой структурой у нас есть предсказуемое место для активов приложения, страниц, компонентов, маршрутов, хранения логики и четкая точка входа. Не стоит портить хорошие предсказуемые вещи.
Рекомендуемые правила для компонентов
Теперь, обращаясь к каталогу компонента, стайлгайд Vue дает нам несколько дополнительных советов, чтобы сделать нашу файловую структуру более предсказуемой. Среди прочего, стайлгайд рекомендует следующее при определении компонентов:
По возможности каждый компонент должен быть определен в собственном выделенном файле (SFC).
Однофайловые компоненты должны быть оформлены в формате PascalCase
Все базовые компоненты должны начинаться с одного и того же префикса (например, Base или App).
Вы можете рассматривать базовые компоненты как общие для всего приложения многократно используемые компоненты, например, кнопки или модалы.
Это группирует их вместе и заявляет об их глобальном, многоразовом характере.
Названия компонентов всегда должны быть многословными, чтобы не конфликтовать с существующими или будущими элементами HTML. Не создавайте компонент Table или Button.
Компоненты одного экземпляра должны начинаться с префикса The.
Например, верхний или нижний колонтитул сайта
Это группирует их вместе и объявляет их одноразовыми.
Тесно связанные дочерние компоненты должны иметь префикс с именем родительского компонента.
Например,
TodoListItem
вTodoList
.Это группирует их вместе и объявляет их связанными.
Имена компонентов должны начинаться со слов самого верхнего уровня (обычно общего) и заканчиваться самыми конкретными.
Например,
SearchWidgetInput
,SearchWidgetResultsList
,SearchWidget
Это группирует связанные компоненты вместе в структуре файла
Потерпите, если это не совсем понятно, через минуту появится изображение, которое поможет вам.
Помимо перечисленных, в полном варианте стайлгайда есть ряд других стандартов, которые помогут вашему проекту быть более предсказуемым для широкой аудитории разработчиков. Я не буду приводить их все здесь, но настоятельно рекомендую вам прочитать об этом и следовать рекомендациям из этого руководства самостоятельно.
Некоторые рекомендуемые личные/командные стандарты предсказуемости
Несмотря на то, что существует несколько отличных стандартов, установленных официальными источниками для сообщества Vue.js в целом, есть и другие паттерны, не столь широко принятые, которые, по моему опыту, могут быть столь же полезны и стать стандартами для вас или проектов вашей команды. Они необходимы, поскольку общепринятые стандарты сообщества не могут быть на 100% всеобъемлющими, но будьте осмотрительны и внимательны к тому, как принимаются и поддерживаются стандарты команды... это может быть проблемой из-за постоянно меняющихся правил, если вы не будете осторожны. Итак, вот некоторые из моих рекомендаций для стандартов вашего проекта Vue.js.
Каталог одноуровневых компонентов
Вы могли заметить общую закономерность среди большинства правил для компонентов из стайлгайда Vue. Соглашения об именах всегда помогают группировать связанные компоненты вместе в файловой системе. По этой причине, а также по причинам, приведенным ниже, я предлагаю принять стандарт каталога одноуровневых компонентов. Данный каталог имеет следующие преимущества:
Быстро и легко перейти от поиска компонента в Vue devtools к поиску файла в кодовой базе (имя файла и имя компонента совпадают).
Используйте функцию быстрого поиска или перехода по файлам в вашей IDE для фильтрации файлов на основе их наиболее общих атрибутов вплоть до более конкретных
Устраните аналитический паралич, когда нужно решить, как организовать компоненты в подкаталоги.
Возможность видеть все компоненты сразу в одном списке
Избавиться от избыточности ключевых слов в именах файлов и в каталоге (это если вы следуете рекомендациям стайлгайда (а так и должно быть) и используете вложенные каталоги) (т.е. post/PostList.vue, post/PostFeature.vue и т.д.)
Избавьтесь от соблазна использовать короткие имена компонентов из одного слова, что проще сделать с вложенными каталогами (т.е. post/List.vue, post/Feature.vue ) и нарушает рекомендации стайлгайда.
Исключить перемещение по файловой структуре в каталогах и обратно в поисках компонента
Упростить импорт компонентов (всегда будет import SomeComponent из "@/SomeComponent").
Как же выглядит плоская структура, которая следует стайлгайду? Вот хороший пример.
Хотя ваше крупномасштабное приложение будет иметь гораздо больше файлов, каждый из них — это просто еще одно имя компонента в одном хорошо организованном списке, поэтому, несмотря на то, что объем файловой структуры может расширяться, сложность не увеличивается.
Стандартизированное соглашение об именовании маршрутов/страниц
Еще одна методика — это стандартизированный способ именования маршрутов и компонентов страниц. В типичном CRUD-приложении у вас есть следующие различные страницы для каждого ресурса:
список всех ресурсов
представление отдельного ресурса
форма для создания ресурса
и форма для редактирования ресурса.
Хотя некоторые из них могут оказаться вложенными маршрутами (например, просмотр отдельного ресурса в модальном оверлее со страницы списка), обычно они имеют выделенный маршрут с соответствующей страницей.
Поскольку у меня уже есть опыт работы с PHP-фреймворком Laravel, при определении имен маршрутов и их путей предсказуемым образом я интуитивно опирался на стандарты, которые были заложены в Laravel. Это облегчило моей команде, обладающей опытом работы с Laravel, более быструю и привычную работу с Vue. Используя в качестве примера ресурс "пользователь", я рекомендую следующее соглашение об именовании, предписанное Laravel и адаптированное для Vue:
Path | Route and Component Name | What it Does |
/users | UsersIndex | List all the users |
/users/create | UsersCreate | Form to create the user |
/users/{id} | UsersShow | Display the users details |
/users/{id}/edit | UsersEdit | Form to edit the user |
Несмотря на соблазн назвать маршрут в более традиционном для Laravel стиле, например users.index
вместо UsersIndex, я заметил, что использование стиля PascalCase
работает так же хорошо и имеет дополнительное преимущество в виде соответствия имени компонента.
Для большей согласованности и гибкости необходимо всегда ссылаться на маршруты по их имени при использовании их в ссылках маршрутизатора и при программном обращении к ним. Например
<router-link :to="{name: 'UsersIndex'}">Users</router-link>
Также стоит отметить, что не все маршруты будут точно соответствовать этому шаблону, поскольку некоторые из них будут более "CRUDdy", чем другие. Для таких случаев я рекомендую продолжать использовать PascalCase в названии для обеспечения согласованности.
Более комплексная файловая структура
Помимо базовой файловой структуры, которую Vue CLI предоставляет вам из коробки, я предлагаю стандартизировать следующее для лучшей предсказуемости.
Здесь добавлены такие каталоги, как docs, helpers, layouts, mixins и plugins. Заметьте, что 4 из 5 имеют причудливую иконку Material Icon Theme рядом с ними, предоставленную расширением VS Code . Это потому, что в определенное время, для некоторых фреймворков или языков, эти соглашения о каталогах были достаточно распространены, чтобы получить свой собственный значок от разработчика расширения. Это не случайность!
Я также добавил один файл globals.js.
Итак, что стоит за этими стандартами файловой структуры? Очень рад, что вы спросили!
docs
Назначение этого файла очевидно, но важнее то, что он уже включен и при каждом открытии кодовой базы сразу предстает перед взором вашей команды. Более вероятно, что определенные аспекты проекта будут задокументированы, если разработчику никогда не придется покидать свою IDE. Я также обнаружил (и это было приятной неожиданностью), что написание документации сначала, прежде чем приступить к кодированию многократно используемого класса или компонента, обычно помогает мне лучше спроектировать интерфейс или API этого кода. Дерзайте, попробуйте!
Кроме того, помимо каталога docs, я обнаружил, что полезно помещать README.md в корень каждого стандартизированного каталога, объясняя назначение каталога и любые правила для того, что должно быть в него включено. Это особенно полезно для тех стандартов, которые не являются общими для всего сообщества.
helpers
Это общая директория во многих фреймворках для базовых функций ввода-вывода, которые можно использовать многократно в рамках всего проекта. Их обычно легко тестировать и, как правило, они используются не один раз. Мне нравится начинать с одного файла index.js, а затем, по мере роста числа хелперов, разбивать их на более сгруппированные файлы, такие как https.js, cache.js, time.js и т. д. Все в этом каталоге можно просто импортировать и использовать по требованию, а если какая-то функция в итоге вообще не будет использоваться, ее можно легко вытряхнуть из производственного пакета.
layouts
Я позаимствовал это соглашение из Nuxt, а также из Laravel. Это может быть удобно для определения не только компонентов страницы, но и компонентов макета, которые могут быть повторно использованы на нескольких страницах. Вместо того чтобы определять содержимое страницы, как следует из названия, эти компоненты определяют общий макет. Например, будет ли эта страница одноколоночной или двухколоночной? Имеет ли она левую или правую боковую панель? Включает ли макет типичные верхний и нижний колонтитулы или он совершенно пустой, возможно, с абсолютно центрированным содержимым страницы? Обычно существует всего 2 или 3 таких компонента макета, но, тем не менее, они могут быть удобной абстракцией.
mixins
Этот каталог предназначен для организации всех ваших Vue.js миксинов. Я думаю, важно по-прежнему добавлять слово Mixin в конец имени каждого файла (например, ResourceTableMixin.js
) для удобства поиска в переключателе файлов. Хотя у меня еще не было возможности поработать над более масштабным проектом Vue 3, я предполагаю, что это быстро изменится на каталог composables в пользу извлечения реактивных данных/методов с помощью Composition API, а не с помощью миксинов. Или, по крайней мере, каталог composables может быть добавлен в мою стандартную файловую структуру в дополнение к каталогу mixins.
plugins
Последний каталог, который я люблю включать во все свои проекты Vue, — это plugins. В мире пакетов и библиотек мы иногда делаем больше настроек и регистрации, чем собственно кодирования. Именно для этого и предназначен этот каталог, включающий и настраивающий все сторонние материалы Vue. Хотя они называются плагинами, я не всегда использую этот термин в буквальном смысле. Другими словами, это не обязательно должна быть сторонняя библиотека, зарегистрированная через метод Vue .use()
. В большинстве случаев это так, но иногда используются альтернативные методы установки библиотеки в Vue (например, .component()
). Для библиотек, настройка которых занимает одну или две строки, можно использовать файл plugins/index.js. Что касается более сложной настройки, то для них я предпочитаю создать отдельный файл в каталоге plugins, а затем импортировать его в plugins/index.js.
globals.js
Это единственный стандартный файл, который я действительно когда-либо добавляю. Его цель — внести ограниченное количество глобальных переменных в приложение Vue а для SPA, которые являются только клиентской стороной, обычно это окно.
Вот комментарий, который обычно располагается в верхней части этого файла.
/**
* Use this file to register any variables or functions that should be available globally
* ideally you should make it available via the window object
* as well as the Vue prototype for access throughout the app
* (register globals with care, only when it makes since to be accessible app wide)
*/
В Vue 2 это можно было сделать таким образом:
Vue.prototype.$http = () => {}
В Vue 3 это выглядит следующим образом:
const app = createApp({})
app.config.globalProperties.$http = () => {}
Хотя меня постоянно предупреждали об опасности глобальных переменных, однажды я прочитал, что "небольшое количество глобальных переменных" — это очень удобная вещь, и с тех пор она мне уже не раз пригодилась. Благодаря этому файлу я легко узнаю, какие это глобальные переменные, и мне не нужно будет долго думать, когда захочется добавить новые.
Резюме по теме предсказуемости
Хотя существуют некоторые стандарты сообщества, которые лучше не игнорировать, есть и такие, которые вы можете сделать для себя или своей команды, чтобы ваши кодовые базы стали более предсказуемыми. Несмотря на то, что некоторые из вышеупомянутых стандартов оказались полезными для меня, могут быть и другие, которые хорошо подходят для вас или вашей команды. Самое главное — придерживаться их во всех проектах, чтобы они служили для достижения поставленной цели.
Безусловно, стандарты предсказуемости — это большое преимущество для ваших крупномасштабных приложений Vue.js, но можно сделать еще больше. Обязательно ознакомьтесь со следующей статьей из этого цикла, в которой мы рассмотрим инструменты линтинга и форматирования, такие как ESLint и Prettier, чтобы ваш код был чистым, без ошибок и последовательным.
Материал подготовлен в рамках курса «Vue.js разработчик». Если вам интересно узнать подробнее о формате обучения и программе, познакомиться с преподавателем курса — приглашаем на день открытых дверей онлайн. Регистрация здесь.