Кратко, ясно, логично

21 августа 2023
Кратко, ясно, логично

Сегодня поговорим про то, как можно сокращать код при работе с веб-фреймворком Svelte. Ещё расскажем обо всех основных приёмах оптимизации кода на JS и поделимся трюком создания градиентной тени в CSS на прозрачном фоне.

Пиши, сокращай: Svelte edition

Прогуливаясь по просторам YouTube, мы набрели на замечательное видео, рассказывающее, как сокращать код на примере обычной карточки:

Svelte edition

Смысл в том, чтобы не менять поведение, но при этом сделать код лаконичным и наглядным. Разберёмся, как это работает? Для этого создадим набор из пяти файлов:

  1. App.svelte
  2. Card.svelte
  3. CardButton.svelte
  4. CardDescription.svelte
  5. CardTitle.svelte

Каждый из них будет отвечать за свою часть работы. App.svelte содержит общий каркас:

<script>
    import Card from './Card.svelte'
    import CardTitle from './CardDescription.svelte'
    import CardDescription from './CardDescription.svelte'
    import CardButton from './CardButton.svelte'
</script>

<Card>
    <CardTitle>
        Hello world
    </CardTitle>
    <CardDescription>
        Lorem ipsum is simply dummy text of the printing and typesetting industry.
    </CardDescription>
    <CardButton>
        Get started
    </CardButton>
</Card>

Внутри Card.svelte и во всех остальных файлах, размещены стили:

<script>
</script>

<div class="card">
    <slot />
</div>

<style>
    .card {
        display:flex;
        justify-content: center;
        align-items: center;
        flex-direction: column;
        width: 300px;
        background-color: #181818;
        color: #ffffff;
        margin: 0px auto;
        border-radius: 8px;
        padding: 2rem;
    }
</style>

В CardButton.svelte, помимо стиля, есть активация кнопки:

<script>
    export let disabled = false;
</script>

<button {disabled}>
    <slot />
</button>

<style>
    button {
        width: 100%;
        background-color: green;
        padding: 12px;
        border-radius: 8px;
    }
</style>

Файл CardDescription.svelte совсем короткий, там задан цвет и выравнивание по центру:

<p class="description">
    <slot />
</p>

<style>
    .description {
        color: #cdcdcd;
        text-align: center;
    }
</style>

Ну и CardTitle.svelte не сильно длиннее:

<h2 class="title">
    <slot />
</h2>

<style>
    .title {
        color: #ffffff;
        font-size: 24px;
        margin: 0;
    }
</style>

Теперь немного магии: откроем App.svelte и перенесем все импорты, кроме первого, в Card.svelte. Уберём повторяющееся слово «Card» из перенесённых импортов, а в <slot> перечислим: Title, Description и Button. Таким образом у нас Card.svelte приобретёт вид:

<script>
    import Title from './CardDescription.svelte'
    import Description from './CardDescription.svelte'
    import Button from './CardButton.svelte'
</script>

<div class="card">
    <slot {Title} {Description} {Button}/>
</div>

<style>
    .card {
        display:flex;
        justify-content: center;
        align-items: center;
        flex-direction: column;
        width: 300px;
        background-color: #181818;
        color: #ffffff;
        margin: 0px auto;
        border-radius: 8px;
        padding: 2rem;
    }
</style>

Теперь удаляем повторяющееся слово Card из App.svelte, предварительно добавив наши Title, Description и Button в компонент <Card>:

<script>
    import Card from './Card.svelte'
</script>

<Card let:Title let:Description let:Button>
    <Title>
        Hello world
    </Title>
    <Description>
        Lorem ipsum is simply dummy text of the printing and typesetting industry.
    </Description>
    <Button>
        Get started
    </Button>
</Card>

Логика работы при этом не будет нарушена, а файл стал выглядеть лучше. Вернёмся в Card.svelte и после импортов объявляем константу:

<script>
    import Title from './CardDescription.svelte'
    import Description from './CardDescription.svelte'
    import Button from './CardButton.svelte'

    const C = {
        Title,
        Description,
        Button
    }
</script>

<div class="card">
    <slot {C}/>
</div>

<style>
    .card {
        display:flex;
        justify-content: center;
        align-items: center;
        flex-direction: column;
        width: 300px;
        background-color: #181818;
        color: #ffffff;
        margin: 0px auto;
        border-radius: 8px;
        padding: 2rem;
    }
</style>

Это даст возможность сделать App.svelte ещё изящнее:

<script>
    import Card from './Card.svelte'
</script>

<Card let:C>
    <C.Title>
        Hello world
    </C.Title>
    <C.Description>
        Lorem ipsum is simply dummy text of the printing and typesetting industry.
    </C.Description>
    <C.Button>
        Get started
    </C.Button>
</Card>

Так что берите на вооружение. Оставляем ссылку на оригинальное видео. Лайк, шер, репост!

Способы оптимизации JS

Когда кодовая база распухла, а производительность упала, пора задуматься над оптимизацией. Но прежде чем что-либо делать, нужен детальный и хорошо продуманный план. Так что будет не лишним иметь под рукой список из самых эффективных приёмов.

Минификация и объединение множества файлов в единый пакет (bundle). Про первый способ мы рассказывали в нашем прошлом дайджесте. Второй способ, когда вместо кучи мелких файлов у нас есть один пакет, сокращает количество HTTP-запросов. Меньше запросов — лучше работает кэширование, снижается нагрузка на сеть и быстрее работает парсинг.

Асинхронные операции не творят чудеса, но способны повысить отзывчивость приложения. Так что async/await и иные подходы к асинхронному программированию стоит рассматривать, если приложение сильно снизило скорость отклика или стало потреблять значительно больше системных ресурсов.

«Ленивая загрузка» (Lazy loading) дополнительных модулей и ресурсов JavaScript — удел больших и сложных веб-приложений. Для простых проектов это лишено смысла, ведь даже при использовании дополнительных модулей общее время загрузки невелико. Бонусами от использования можно считать снижение нагрузки на сервер, улучшенное SEO и поисковое ранжирование.

Кэширование часто используется в качестве отправной точки оптимизации. Этот механизм применим для самых разных ресурсов: от изображений и CSS до файлов JS и ответов API. Всё это значительно улучшает производительность, сокращая время загрузки и давая возможность горизонтального масштабирования.

Правильное управление памятью способно на чудеса. Если не задумываться о рациональном использовании ресурсов, то рано или поздно приложение подкинет проблем в виде утечек памяти (memory leaking) и снижении производительности. Особенно остро это проявляется на мобильных устройствах, ведь их вычислительная мощность обычно меньше рядовых ПК. В Chrome DevTools есть удобные инструменты для профилирования потребления памяти, так что не стоит ими пренебрегать.

Разделение кода также может помочь веб-приложениям работать быстрее. Большое приложение делится на несколько частей и каждая из них будет загружаться по мере необходимости. Этот метод подойдёт, когда нужно визуально ускорить загрузку приложения и добиться лучшей утилизации доступных ресурсов. Но, как уже говорилось выше, чем больше будет частей, тем хуже станет работать кэширование и вырастет нагрузка на сеть.

Снижение количества циклов и итераций потребуется, если приложение оперирует большими наборами данных или выполняет сложные вычисления. В этом поможет две стратегии: развёртка цикла и мемоизация. Развёртка применяется, если тело цикла невелико. Так что для эффективной работы имеет смысл многократно его продублировать, чтобы интенсивнее использовать регистры процессора и его кэш. Ну а мемоизация представляет собой разновидность кэширования, при котором в кэш помещается вывод функции. Таким образом, последующие вызовы смогут использовать его без повторных вычислений.

Отложенное выполнение JavaScript добавлением defer позволит браузеру пользователя продолжить разбирать HTML, одновременно в фоновом режиме загружая JS-файлы. Страницы будут грузиться быстрее.

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

Градиентные тени CSS

Сто к одному, что в вашей голове промелькнула мысль: «Ещё один текст про градиентные тени». Но мы попробуем переломить ваш скепсис и сконцентрируемся не на самих тенях, а на прозрачности. Большая часть примеров в сети рассчитаны на использование с непрозрачным фоном. Мы нашли отличную статью, позволяющую расширить границы и показать, как делать это с прозрачным фоном.

Прежде всего, действительно, нам надо взглянуть на существующие и миллион раз продемонстрированные примеры с непрозрачным фоном. Создаёте псевдоэлемент, помещаете его за реальным элементом и применяете фильтр с размытием. Что-то вроде такого:

.box {
  position: relative;
}
.box::before {
  content: "";
  position: absolute;
  inset: -5px; /* control the spread */
  transform: translate(10px, 8px); /* control the offsets */
  z-index: -1; /* place the element behind */
  background: /* your gradient here */;
  filter: blur(10px); /* control the blur */
}

Многие разработчики также применяют 3D transform и отрицательный сдвиг по оси Z для получения градиентной тени:

.box {
  position: relative;
  transform-style: preserve-3d;
}
.box::before {
  content: "";
  position: absolute;
  inset: -5px;
  transform: translate3d(10px, 8px, -1px); /* (X, Y, Z) */
  background: /* .. */;
  filter: blur(10px);
}

3D transform

Если же по каким-то причинам использовать 3D transform нельзя, то можно использовать два псевдоэлемента ::before и ::after. Первый создаст нужную нам тень, а второй воспроизведёт основной фон и стили, которые могут понадобиться:

.box {
  position: relative;
  z-index: 0; /* We force a stacking context */
}
/* Creates the shadow */
.box::before {
  content: "";
  position: absolute;
  z-index: -2;
  inset: -5px;
  transform: translate(10px, 8px);
  background: /* .. */;
  filter: blur(10px);
}
/* Reproduces the main element styles */
.box::after {
  content: """;
  position: absolute;
  z-index: -1;
  inset: 0;
  /* Inherit all the decorations defined on the main element */
  background: inherit;
  border: inherit;
  box-shadow: inherit;
}

Как видим, непрозрачный фон даёт отличные возможности для манёвра. Но что насчёт прозрачного фона?

Для работы с прозрачным фоном мы должны удалить фон с основного элемента. Смысл в том, чтобы оставить видимой лишь часть тени, а всё остальное внутри области элемента скрыть. Возьмём ту же тень, что и в 3D transform, но с параметрами смещения и распространения равными нулю:

3D transform

В идеальном мире было круто разрезать элемент, оставив лишь то, что снаружи зелёной рамки. Увы, но сделать это невозможно. Но никто не мешает нам смоделировать это при помощи такого шаблона:

clip-path: polygon(-100vmax -100vmax,100vmax -100vmax,100vmax 100vmax,-100vmax 100vmax,-100vmax -100vmax,0 0,0 100%,100% 100%,100% 0,0 0)

3D transform

Вуаля. Это и есть нужная нам градиентная тень, поддерживающая прозрачность. Хотите деталей? Тогда обязательно прочитайте оригинальную статью. Ну и бонусом её авторы запилили крутой генератор градиентных теней. Полезный инструмент, который упростит вам жизнь.

Митапы

Онлайн

Frontend meetup

11 октября 2023

Осенью мы соберёмся на замечательный Frontend Meetup. Программа мероприятия формируется, но регистрация уже открыта. Если хотите примерить на себе роль спикера,то можно подать доклад прямо в режиме онлайн. Заявки на участие принимаются до 20 сентября!

Теперь следить за митапами Evrone стало удобнее. В Telegram-канале Evrone meetups мы выкладываем анонсы с подробными описаниями докладов, а также студийные записи после мероприятий. А ещё, у нас можно выступить, мы поможем оформить вашу экспертизу в яркое выступление. Подписывайтесь и пишите @andrew_aquariuss, чтобы узнать подробности.

Регистрация

Вакансии

Удаленка / Офис

Evrone 

 

Мы рады новым Frontend-разработчикам. Удалённая работа с первого дня, помощь в подготовке выступлений на профессиональных конференциях, поощрение и оплата участия в Open-source проектах. Прозрачный способ увеличить грейд через обучение и проверку навыков под контролем ментора. Здесь есть понимание, как организовать разработку комфортно и эффективно. Присоединяйтесь!

Подробнее

Подписаться
на Digest →
Важные новости и мероприятия без спама
Технологии которыми вы владеете и которые вам интересны
Ваш адрес электронной почты в безопасности - вот наша политика конфиденциальности.