Обновить
4K+
12
Arina@Stugi

Пользователь

2,3
Рейтинг
6
Подписчики
Хабр КарьераХабр Карьера
Отправить сообщение

Долгое время думала, что использовать паттерны на фронте незачем и это больше тема для собесов

Но недавно все-таки удалось использовать паттерн фабрику для фронта и моему счастью не было предела, когда после 30-минутного рефакторинга разъехавшейся вёрстки через Claude, я попросила: "брат, слушай это ж паттерн фабрика, сделай BaseModal тонким, который просто решает, какой компонент отрисовать"

Технически, классический GoF Factory Method подразумевает наследование, а здесь у меня скорее Simple Factory — функция, выбирающая что создать. Но в обиходе все называют это "фабрикой", и я не буду усложнять.

Классический паттерн фабрика на Java:

// Интерфейс
interface Modal {
    void open();
    void close();
}

// Конкретные реализации
class Dialog implements Modal { ... }
class BottomSheet implements Modal { ... }
class FullscreenSheet implements Modal { ... }

// Фабрика — решает какой класс создать
class ModalFactory {
    static Modal create(String type, boolean isMobile) {
        if (!isMobile) return new Dialog();

        return switch (type) {
            case "bottom-sheet" -> new BottomSheet();
            case "fullscreen"   -> new FullscreenSheet();
            default             -> new Dialog();
        };
    }
}

// Использование
Modal modal = ModalFactory.create("bottom-sheet", isMobile);
modal.open();

Как это работает во Vue?

На фронте есть <component :is="..."/> - динамический компонент, который рендерит то, что ему передадут. Это и есть наш аналог ModalFactory.create(...).

<!-- BaseModal.vue — фабрика -->
<template>
    <component
        :is="modalComponent"
        v-bind="$props"
        @close="emit('close')"
    >
        <slot />
    </component>
</template>

<script setup>

// Фабричный метод — выбирает компонент
const modalComponent = computed(() => {
    // Desktop → всегда Dialog (центрированный)
    if (!isMobile.value) return BaseDialog

    // Mobile → зависит от mobileStyle
    switch (props.mobileStyle) {
        case 'fullscreen':
            return BaseFullscreenSheet
        case 'bottom-sheet':
            return BaseBottomSheet
        default:
            return BaseDialog
    }
})
</script>

Получился BaseModal, который сам почти ничего не делает.

Он не знает, как устроен dialog.
Не знает, как анимируется bottom sheet.
Не знает, как выглядит fullscreen-модалка.

Он просто маршрутизирует:

BaseModal.vue  
  ├─ BaseDialog.vue    
  ├─ BaseBottomSheet.vue    
  └─ BaseFullscreenSheet.vue  

А каждая конкретная реализация живёт отдельно и отвечает только за себя.

Почему это лучше, чем один большой компонент?

Потому что большой универсальный компонент очень быстро превращается в кашу:

<!-- Каша в template -->
<div
    class="modal"
    :class="{
        'modal--open': open,
        'modal--mobile': isMobile,
        'modal--desktop': !isMobile,
        'modal--fullscreen': isMobile && mobileStyle === 'fullscreen',
        'modal--bottom-sheet': isMobile && mobileStyle === 'bottom-sheet',
    }"
>

А потом туда добавляются:

  • разные анимации

  • разные отступы и размеры

  • разное поведение закрытия

  • разные transition

  • разные layout-правила

И компонент, который должен был быть базовой модалкой, внезапно становится местом, куда страшно заходить.

С фабрикой проще:

  • BaseDialog отвечает за centered dialog

  • BaseBottomSheet отвечает за bottom sheet

  • BaseFullscreenSheet отвечает за fullscreen

  • BaseModal только выбирает, что показать

То есть вместо одного монолита появляется тонкий слой выбора и несколько изолированных компонентов.

И кстати, поделитесь: насколько паттерны актуальны сейчас? Или про них всё рассказали 20 лет назад и хватит говорить о них?

Теги:
+2
Комментарии2

Как я оптимизировала фронт на 40% и никто не заметил

Предыстория

Когда я помогала с поиском сотрудника и просматривала резюме на фронтенд разработчика, очень часто встречала фразу - "Оптимизировал(а) размер бандла на 30% / 40% / 50%, что увеличило ..." как под копирку от ИИ, а у меня из достижений в резюме - "делаю задачи и фикшу баги" 

Ну что ж, возьмем свое приложение и оптимизируем его

О приложении

Это небольшое SPA на Vue 3 для администрирования справочников. Ничего особенного, но это приложение экономит время программистам, которые не лезут в БД, и, как мне кажется, полезно для аналитиков и QA - это позволяет лучше понять, как устроена база, и почему иногда что-то не работает как ожидается.

Начнем оптимизацию

Запускаем npx vite-bundle-visualizer и получаем вот такую красивую розовую визуализацию (прикрепила бы скрин, на то что получилось, но в пост можно одну картинку добавить)

Смотрим роутинг у приложения... Все роуты импортируются сразу. Применяем легкий фикс:

  • Оставляем синхронный импорт только для страниц, которые первыми открываются у пользователей

  • Остальные подгружаем отдельно с помощью lazy import

// Было:
import PaymentTypes from '@/views/Directories/PaymentType/PaymentTypes.vue';
import OrderTypes from '@/views/Directories/OrderType/OrderTypes.vue';
import Configurations from '@/views/Directories/Configuration/Configurations.vue';
import NewConfiguration from '@/views/Directories/Configuration/NewConfiguration.vue';
import ConfigurationPage from '@/views/Directories/Configuration/ConfigurationPage.vue';
import Source from '@/views/Directories/Source/Source.vue';
import City from '@/views/Directories/City/City.vue';
import Brand from '@/views/Directories/Brand/Brand.vue';
import CloseReason from '@/views/Directories/CloseReason/CloseReason.vue';
import ChangeReason from '@/views/Directories/ChangeReason/ChangeReason.vue';
import Restaurants from '@/views/Directories/Restaurants/Restaurants.vue';
import RestaurantPage from '@/views/Directories/Restaurants/RestaurantPage.vue';
import NewRestaurant from '@/views/Directories/Restaurants/NewRestaurant.vue';
import Discounts from '@/views/Directories/Discounts/Discounts.vue';
import PriceTypes from '@/views/Directories/PriceType/PriceTypes.vue';
// Стало:
  children: [
            {
                path: 'brand',
                name: 'Бренды',
                component: () =>
                    import('@/views/Directories/Brand/Brand.vue'), // <--тут
                meta: {
                    breadcrumbs: ['Справочники', 'Бренды'],
                    requiresAuth: true,
                    permissions: ['admin.admin'],
                    title: 'Бренды',
                    section: 'directories',
                },
            },
...
]

Запускаем снова и уже получаем уже разбитый бандл. Code Splitting работает, вывод сборки теперь показывает множество маленьких JS-файлов для каждой страницы.

Итоги оптимизации:

Уменьшили основной бандл с 245 kB до 148 kB (gzip) — это минус 39%

Что получили:

  • Оптимизировала размер бандла на 40%

  • Улучшила First Contentful Paint

  • Внедрила code splitting

  • Повысила производительность

  • Уменьшила основной JavaScript-файл почти на 40% (в gzip)

  • Уменьшила сырой размер на 46%

  • Теперь загружается только то, что нужно для текущей страницы

Реальность:

  • ❌ Съэкономил ли бизнес деньги? - Нет

  • Выросла ли конверсия? - Как? 🌝 это внутренний админ-интерфейс

  • Применили ли чудо-технологию? - Нет, добавили lazy import из коробки фреймворка и рекомендацией из документации

  • Кто-то это заметил? - Только я в отчете, "на глаз" даже мне не заметно

  • ❌ Заметил ли пользователь? - Нет, потому что основное время все равно уходит на получение данных с backend

Мысли по этому поводу

И так, мы теперь можем добавить заветную строчку в резюме!

А вы встречаете эту строчку в резюме?

  • Какие чувства она у вас вызывает?

  • Красный флаг ли она для вас?

  • Или наоборот - показатель того, что человек думает о производительности?

Мой канал о поиске работы (ничего не продаю и не рекламирую, только себя)

Теги:
Всего голосов 8: ↑6 и ↓2+5
Комментарии4

Выбор вакансии: как я кинулась во всё — и это не дало результата.

Есть разработчики, у которых развитие идёт линейно и предсказуемо: верстальшик → джун фронтендер → мидл → мидл в сильной компании → сеньор/лид/уход в бэкенд

Красиво. Понятно. Логично.

Но у меня кривая черта развития сначала бэк на Java в закрытом предприятии. Потом фулстек в фудтехе: в основном Vue, но ещё и Go (и все сопутствующее), и CUBA Platform (lowcode на java, он же «Тезис»), и n8n.

Широко. Разнообразно. Интересно.

Как я начала откликаться - на всё, что блестит

И сейчас Когда я вышла на рынок, то сначала я откликалась на все что близко:

  1. Frontend - Vue / React / Angular
    Ну фронт же. Есть мнение, что «не нужно учить конкретный фреймворк — важны принципы».

  2. Go
    а почему бы нет? Знаю , умею , курсы закончены, писала на нем

  3. Fullstack (Go или JDK + фронт)

  4. N8N, автоматизаторы особенно с ИИ
    Интересно. Растущее направление.

  5. Lowcode платформы CUBA, тезис, WebTutor - замаскированный под фронтенд Опыт есть. Почему не использовать?

И это фатал еrror

  1. Ошибка №1. Переключение контекста
    Очень сложно переключать контекст и даже синтаксис языка - на первом собесе по TS я не смогла вспомнить синтаксис (на ум приходил только java, так как он изучался более долго и в закрытой среде, ирония: хоть я на нем и не пишу, но разбуди среди ночи - код напишу)

  2. Ошибка №2. Рынок
    Рассматривать вакансии на Angular, React без опыта в продакшене - на данный момент наивно.

    Рынок перегрет:
    - Vue ~ 1000 откликов за неделю,
    - React - 4000 ,

    Неужели Арина (или тот кто читает эту статью) ты думаешь, что кто-то будет рассматривать ваше резюме со Vue? Каким бы в целом хорошим инженером вы не были. Рынок не покупает «в целом».

  3. Ошибка №3. Fullstack со связкой Go + Vue или JDK + Vue
    Фуллстеки со связкой go или jdk - это бред вакансии, это карьерный тупик.
    - PHP + Vue - норм
    - Node + Vue - норм,
    но Go + Vue - это нонсенс, это только подработка для поддержания штанов. Чаще это небольшие команды, поддержка, нестабильные проекты.

  4. Ошибка №4. n8n — нравится, но это уже не совсем разработка
    Автоматизация, интеграции, AI — это интересно. Но это больше аналитика и orchestration, чем классическая инженерия. Если хочешь быть разработчиком — нужно понимать, куда ты смещаешь фокус.

  5. Ошибка №5. Low-code — карьерный тупик
    Проблем с окружением больше. Кода меньше. Рынок уже. Ты становишься зависимой от конкретной платформы. И выйти обратно в «чистую разработку» становится сложнее.

Мой Hotfix: Фокус

Я поняла, что на падающем рынке выживают либо "универсалы" c ИИ подбоком, либо эксперты

Моя новая стратегия:

  • Vue 3 + TypeScript + Nuxt (как зона роста)

  • n8n — как подработку и интересный дополнительный навык.

Иногда рост — это не добавить ещё стек. А убрать лишнее.

Теги:
Всего голосов 5: ↑3 и ↓2+2
Комментарии5

Информация

В рейтинге
1 558-й
Зарегистрирован
Активность