Сложность постов в канале
Anonymous Poll
19%
Все темы в постах для меня примитивны
75%
Бывает как что-то простое, так и что-то сложное
5%
Большинство постов читать даётся сложно
🐳9🔥2
Зачем нужна семантика?
В одном из прошлых постов я разобрал что такое семантика. В этом посте хочу рассказать зачем она нужна.
Чаще всего о семантике говорят со стороны SEO, и не зря:
1. Поисковые роботы, прежде чем добавить ваш сайт в выдачу, открывают вашу страницу и прогружают весь её контент. Чем лучше свёрстана страница, тем больше “баллов” она наберёт — лучше определится категория контента, его содержимое, ключевые запросы. Чем больший рейтинг набирает страница, тем вероятнее она появится в выдаче при поиске. А посещения почти всегда конвертируются в доход.
2. Повышение доступности
Не у каждого пользователя есть возможность пользоваться мышкой. Сайтом также могут пользоваться люди с ограниченными возможностями, особенностями зрения и слуха, и такие пользователи нуждаются в специальных инструментах для взаимодействия с сайтом. Чаще всего на слуху бывает скринридер
Так вот, скринридеры завязываются как раз на эти самые семантические теги и семантические атрибуты типа
При этом, доступность — это не только про незрячих, это и про самых обычных людей. Вот используете вы беспроводную мышку и она неожиданно села. Как пользоваться компьютером и сайтами в частности? Конечно же с клавиатуры. Семантика в этом также помогает.
3. Множество предустановок
Как я и говорил в прошлом посте, есть категория семантичных тегов, которые имеют дополнительные свойства "из коробки", типа тега
4. Улучшение читаемости кода
Лично для меня это минорно, особенно в эпоху господства компонентного подхода. Но, всё таки, семантические теги позволяют разработчикам быстрее разбираться в вёрстке, это тоже немаловажно
🌐 Также советую доклад Вадима Макеева на тему семантики. Вадим — амбассадор доступности, у него шикарные материалы на эту тему.
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #web #useful
В одном из прошлых постов я разобрал что такое семантика. В этом посте хочу рассказать зачем она нужна.
Чаще всего о семантике говорят со стороны SEO, и не зря:
1. Поисковые роботы, прежде чем добавить ваш сайт в выдачу, открывают вашу страницу и прогружают весь её контент. Чем лучше свёрстана страница, тем больше “баллов” она наберёт — лучше определится категория контента, его содержимое, ключевые запросы. Чем больший рейтинг набирает страница, тем вероятнее она появится в выдаче при поиске. А посещения почти всегда конвертируются в доход.
2. Повышение доступности
Не у каждого пользователя есть возможность пользоваться мышкой. Сайтом также могут пользоваться люди с ограниченными возможностями, особенностями зрения и слуха, и такие пользователи нуждаются в специальных инструментах для взаимодействия с сайтом. Чаще всего на слуху бывает скринридер
Скринридер — это специальная программа, которая озвучивает всё, что происходит на экране и чаще всего используется незрячими пользователями.
Пример работы скринридера в видео
Так вот, скринридеры завязываются как раз на эти самые семантические теги и семантические атрибуты типа
alt
у тега image
. При этом, доступность — это не только про незрячих, это и про самых обычных людей. Вот используете вы беспроводную мышку и она неожиданно села. Как пользоваться компьютером и сайтами в частности? Конечно же с клавиатуры. Семантика в этом также помогает.
3. Множество предустановок
Как я и говорил в прошлом посте, есть категория семантичных тегов, которые имеют дополнительные свойства "из коробки", типа тега
<button>
. Использовать такой тег в разы удобнее, чем сделать кнопку из тега <div>
4. Улучшение читаемости кода
Лично для меня это минорно, особенно в эпоху господства компонентного подхода. Но, всё таки, семантические теги позволяют разработчикам быстрее разбираться в вёрстке, это тоже немаловажно
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #web #useful
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥24❤7👍6🐳3
Управление фокусировкой
Часто на собеседовании могут спросить об управлении состоянием фокуса. Обычно вопрос подаётся в контексте следующей задачи:
Представим, что у нас есть страница авторизации. Как сделать так, чтобы при открытии страницы пользователь сразу же был сфокусирован на поле ввода логина?
Начнем с того, у тега
Его проблема заключается лишь в том, что работает этот атрибут не всегда, когда хотелось бы, а его поддержка составляет всего 83.5 процента.
Тогда мы приходим к решению этой задачи через
Ведь есть не менее прекрасный метод
О методе
У документа есть свойство
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #javascript #web
Часто на собеседовании могут спросить об управлении состоянием фокуса. Обычно вопрос подаётся в контексте следующей задачи:
Представим, что у нас есть страница авторизации. Как сделать так, чтобы при открытии страницы пользователь сразу же был сфокусирован на поле ввода логина?
Начнем с того, у тега
input
есть прекрасный атрибут autofocus
, который и был придуман для решения таких задач:<input id="login" name="login" autofocus />
Его проблема заключается лишь в том, что работает этот атрибут не всегда, когда хотелось бы, а его поддержка составляет всего 83.5 процента.
Тогда мы приходим к решению этой задачи через
JavaScript
:document.getElementById('login').focus();
Ведь есть не менее прекрасный метод
focus
, после вызова которого, фокус перенесётся на конкретный элемент. Его поддержка уже значительно лучше, а самое главное — весь контроль за происходящим на странице лежит в наших руках, что, в целом, достаточно удобно.О методе
focus
знают уже многие, но знаете этот вопрос может развиться: как посмотреть, на каком элементе мы сейчас сфокусированы? Такой вопрос уже может поставить многих в ступор, потому что с этим далеко не каждый день работаешь. Но, на самом деле, всё просто:document.activeElement
У документа есть свойство
activeElement
, на которое мы и можем завязаться.Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #javascript #web
Caniuse
"autofocus" | Can I use... Support tables for HTML5, CSS3, etc
"Can I use" provides up-to-date browser support tables for support of front-end web technologies on desktop and mobile web browsers.
👍42❤13🔥5🐳4🤩2
Определяющие тайпгарды
Как я и писал в одном из прошлых постов, тайпгарды есть двух видов: уточняющие и определяющие. Уточняющие попроще, их я разобрал как раз в прошлом посте.
Определяющие тайпгарды — это функции, которые позволяют уточнить тип
И представим, что в коде у нас есть некоторая переменная с неизвестным типом, которую мы хотим обработать:
Определяющие тайпгарды любую переменную воспринимают как
Это может выглядеть очень некрасиво, но главное, что работает)
На практике встречается не так часто, но тот самый раз, когда он будет нужен, будет спасительным для типобезопасности вашего кода. Такие тайпгарды позволяют легко избежать использования
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #code #typescript
Как я и писал в одном из прошлых постов, тайпгарды есть двух видов: уточняющие и определяющие. Уточняющие попроще, их я разобрал как раз в прошлом посте.
Определяющие тайпгарды — это функции, которые позволяют уточнить тип
unknown
переменной. Сразу рассмотрим пример и рассмотрим следующий интерфейс:interface User {
name: string;
age: number;
roles: string[];
}
И представим, что в коде у нас есть некоторая переменная с неизвестным типом, которую мы хотим обработать:
const foo: any = ...
if (isUser(foo)) {
// обработать как пользователя
} else {
// обработать как что-то иное
}
Определяющие тайпгарды любую переменную воспринимают как
unknown
, это их ключевая особенность. Каждое свойство мы проверяем отдельно и таким образом, чтобы однозначно убедиться в его типе. Для интерфейса из примера, хороший тайпгард будет выглядеть так:function isUser(value: unknown): value is User {
const user = value as User;
return user !== null
&& typeof user === 'object'
&& typeof user.name === 'string'
&& typeof user.age === 'number'
&& Array.isArray(user.roles)
&& user.roles?.every(role => typeof role === 'string');
}
Это может выглядеть очень некрасиво, но главное, что работает)
На практике встречается не так часто, но тот самый раз, когда он будет нужен, будет спасительным для типобезопасности вашего кода. Такие тайпгарды позволяют легко избежать использования
any
типов и раскрыть возможности TypeScript
в полной мере. Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #code #typescript
👍17❤5🔥4🤔1🐳1
Что такое Git Flow?
Git Flow — это модель ветвления для Git, основная идея которой заключается в использовании отдельной ветки для каждого этапа разработки. Обычно выделяются следующие ветки:
1. Основная ветка — чаще всего это
Эта ветка содержит стабильную версию продукта, которая готова к выпуску. В ней всегда должен быть работающий и протестированный код. Каждый коммит в
2. Ветка разработки — чаще всего это
В этой ветке происходит активная разработка. Все новые фичи и изменения сначала попадают сюда. После тестирования и проверки они будут слиты в
Также есть вспомогательные ветки, которые маркируются своим префиксом — чаше всего это
1. Ветки для разработки новых функций —
Они создаются от develop и после завершения работы сливаются обратно в develop. Нужны такие ветки для организации разработки отдельной фичи.
2. Ветка для фикса багов —
Почти то же самое, что и
3. Ветка для подготовки версии продукта —
Создаются от
Чаще всего процесс разработки выглядит таким образом: берём задачку → делаем отдельную ветку → вносим изменения → сливаемся через код ревью в нужную ветку
В зависимости от компании, проекта и команды, нейминги веток могут отличаться, но суть всегда будет оставаться примерно похожей при использовании такого подхода
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #useful
Git Flow — это модель ветвления для Git, основная идея которой заключается в использовании отдельной ветки для каждого этапа разработки. Обычно выделяются следующие ветки:
1. Основная ветка — чаще всего это
master
Эта ветка содержит стабильную версию продукта, которая готова к выпуску. В ней всегда должен быть работающий и протестированный код. Каждый коммит в
master
обычно соответствует одной версии продукта2. Ветка разработки — чаще всего это
develop
В этой ветке происходит активная разработка. Все новые фичи и изменения сначала попадают сюда. После тестирования и проверки они будут слиты в
master
Также есть вспомогательные ветки, которые маркируются своим префиксом — чаше всего это
feature/*
, release/*
, bugfix/*
, hotfix/*
:1. Ветки для разработки новых функций —
feature/*
Они создаются от develop и после завершения работы сливаются обратно в develop. Нужны такие ветки для организации разработки отдельной фичи.
2. Ветка для фикса багов —
bugfix/*
и hotfix/*
Почти то же самое, что и
feature/*
, только эти ветки нужны для фикса багов. hotfix/*
— для фикса багов в мастере или релизе. bugfix/*
— для фикса багов в ветке develop
3. Ветка для подготовки версии продукта —
release/*
Создаются от
develop
, когда разработка новых функций завершена и нужно подготовить релиз. После завершения сливаются в master
и develop
Чаще всего процесс разработки выглядит таким образом: берём задачку → делаем отдельную ветку → вносим изменения → сливаемся через код ревью в нужную ветку
В зависимости от компании, проекта и команды, нейминги веток могут отличаться, но суть всегда будет оставаться примерно похожей при использовании такого подхода
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #useful
❤29👍19🔥5🐳2🙏1🤝1
Какими способами можно скрыть элемент со страницы?
Для многих каверзный вопрос. В этом посте коротко рассмотрим какие есть варианты
1. Использовать
Как мне кажется, самый часто используемый вариант. В этом случае элемент полностью исчезает из потока документа, то есть полностью пропадает из вёрстки и больше никак не влияет на неё
2. Использовать
Этот вариант, в отличии от
3. Использовать
То же самое, что и прошлый вариант, только в этом случае скрытый элемент мало того, что продолжит занимать место в вёрстке, так ещё и продолжить обрабатывать разные события, например, клик. То есть у нас может быть условно невидимая кнопка, по которой всё ещё можно нажать
4. Позиционировать элемент далеко и надолго
Абсолютно точно не советую использовать этот вариант, хотя работать будет
Есть ещё всякая экзотика типа
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #web #useful
Для многих каверзный вопрос. В этом посте коротко рассмотрим какие есть варианты
1. Использовать
display: none
Как мне кажется, самый часто используемый вариант. В этом случае элемент полностью исчезает из потока документа, то есть полностью пропадает из вёрстки и больше никак не влияет на неё
2. Использовать
visibility: hidden
Этот вариант, в отличии от
display: none
, не выводит элемент из потока документа. Элемент скрывается для глаз пользователя, но всё ещё продолжает обрабатываться и занимает место в вёрстке 3. Использовать
opacity: 0
То же самое, что и прошлый вариант, только в этом случае скрытый элемент мало того, что продолжит занимать место в вёрстке, так ещё и продолжить обрабатывать разные события, например, клик. То есть у нас может быть условно невидимая кнопка, по которой всё ещё можно нажать
4. Позиционировать элемент далеко и надолго
.element {
position: absolute;
left: -999999px;
}
Абсолютно точно не советую использовать этот вариант, хотя работать будет
Есть ещё всякая экзотика типа
<div hidden>
, но это именно экзотика. Способы выше — основные, их точно хватит на практике.Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #web #useful
👍27❤7🐳5🔥3
Что такое декларативность и императивность?
Императивный подход написания кода фокусируется на том, КАК именно должна быть выполнена задача. В императивном стиле вы указываете шаг за шагом, что должно происходить, ничего не скрывая, например:
В этом примере мы явно указываем, как именно нужно создать список: создаем элементы, задаем им текст и добавляем в список.
Декларативный же подход фокусируется на том, ЧТО нужно сделать. В декларативном стиле вы описываете результат, который хотите получить, а не процесс его достижения, например:
В этом примере с использованием React мы описываем, что хотим увидеть: список элементов. Мы не указываем, как именно React должен создать и добавить эти элементы, мы просто описываем структуру, которую хотим получить
Императивный стиль дает вам полный контроль над процессом выполнения, что может быть полезно для сложных алгоритмов и точной настройки.
Декларативный стиль, как правило, делает код более читаемым и легким для понимания, так как вы описываете только конечный результат. Также декларативный код часто легче поддерживать и изменять, так как он фокусируется на описании желаемого состояния, а не на пошаговом выполнении.
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #code #javascript #principles
Императивный подход написания кода фокусируется на том, КАК именно должна быть выполнена задача. В императивном стиле вы указываете шаг за шагом, что должно происходить, ничего не скрывая, например:
// Императивный способ создания списка из элементов массива
const items = [1, 2, 3, 4, 5];
const ul = document.createElement('ul');
for (let i = 0; i < items.length; i++) {
const li = document.createElement('li');
li.textContent = items[i];
ul.appendChild(li);
}
document.body.appendChild(ul);
В этом примере мы явно указываем, как именно нужно создать список: создаем элементы, задаем им текст и добавляем в список.
Декларативный же подход фокусируется на том, ЧТО нужно сделать. В декларативном стиле вы описываете результат, который хотите получить, а не процесс его достижения, например:
import React from 'react';
import ReactDOM from 'react-dom';
const items = [1, 2, 3, 4, 5];
const App = () => (
<ul>
{items.map(item => (
<li key={item}>{item}</li>
))}
</ul>
);
ReactDOM.render(<App />, document.getElementById('root'));
В этом примере с использованием React мы описываем, что хотим увидеть: список элементов. Мы не указываем, как именно React должен создать и добавить эти элементы, мы просто описываем структуру, которую хотим получить
Императивный стиль дает вам полный контроль над процессом выполнения, что может быть полезно для сложных алгоритмов и точной настройки.
Декларативный стиль, как правило, делает код более читаемым и легким для понимания, так как вы описываете только конечный результат. Также декларативный код часто легче поддерживать и изменять, так как он фокусируется на описании желаемого состояния, а не на пошаговом выполнении.
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #code #javascript #principles
❤25👍13🔥6🐳2
Остановка распространения событий: event.stopPropogation и event.stopImmediatePropagation()
Итак, эти методы используются для управления событиями в JavaScript. Сначала разберём каждый из них по отдельности:
🟢 event.stopPropagation()
Этот метод предотвращает дальнейшее распространение события в фазе захвата или всплытия. Это значит, что событие сработает только на
Так как мы используем
🟢 event.stopImmediatePropagation()
Этот метод не только предотвращает дальнейшее распространение события к родителям, но и останавливает выполнение других обработчиков событий на том же элементе. Рассмотрим пример:
При клике на элемент, в консоли мы увидим только лишь
В этом посте в качестве эксперимента сделал блок "коротко о главном", чтобы проще было усваивать материал и не приходилось читать очень длинные посты, если тема вам оказалась неинтересна. Накидайте 🔥 если этот блок — пушка-гонка, а я постараюсь добавлять его чаще
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #code #javascript
Итак, эти методы используются для управления событиями в JavaScript. Сначала разберём каждый из них по отдельности:
Этот метод предотвращает дальнейшее распространение события в фазе захвата или всплытия. Это значит, что событие сработает только на
event.target
, то есть на самом элементе, но не на всех его родителях, как это сделано по умолчанию. Рассмотрим код:document.getElementById('child').addEventListener('click', event => {
event.stopPropagation();
console.log('Ребёнок');
});
document.getElementById('parent').addEventListener('click', () => {
console.log('Родитель');
});
Так как мы используем
event.stopPropogation()
, в консоли мы увидим только Ребёнок
. Без использования этого метода, мы увидим вывод: Ребёнок
, Родитель
Этот метод не только предотвращает дальнейшее распространение события к родителям, но и останавливает выполнение других обработчиков событий на том же элементе. Рассмотрим пример:
const element = document.getElementById('child')
element.addEventListener('click', event => {
event.stopImmediatePropagation();
console.log('Первый обработчик нажатия');
});
element.addEventListener('click', () => {
console.log('Второй обработчик нажатия');
});
При клике на элемент, в консоли мы увидим только лишь
Первый обработчик нажатия
. Второй обработчик не выполнится, потому что event.stopImmediatePropagation()
остановил выполнение других обработчиков на этом элементеКоротко о главном:
- event.stopPropagation() используется для остановки распространения события на родительские элементы
- event.stopImmediatePropagation() используется для полной остановки события, включая другие обработчики на текущем элементе
В этом посте в качестве эксперимента сделал блок "коротко о главном", чтобы проще было усваивать материал и не приходилось читать очень длинные посты, если тема вам оказалась неинтересна. Накидайте 🔥 если этот блок — пушка-гонка, а я постараюсь добавлять его чаще
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #code #javascript
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥42👍11❤2🐳2
JavaScript не в браузере: NodeJS, Deno и Bun
Начать стоит с того, что JavaScript может выполняться далеко не только в браузере. Для этого есть такая штука, как рантайм — это среда выполнения, которая обеспечивает все необходимое для выполнения JavaScript кода: движок языка, API среды и т.д.
Рантаймов несчётном множество, как и всего в мире JS, но в этом поговорим о самых интересных: NodeJS, Deno и Bun
👩💻 NodeJS — это рантайм JavaScript, построенный на движке V8 от Google Chrome. Он позволяет выполнять JavaScript-код на сервере. По сути, это почти то же самое, что и выполнять код в браузере, за тем лишь исключением, что NodeJS предоставляет API по работе с файлами, операционной системой, среду исполнения тестов и кучу всего ещё
— NodeJS сейчас — это основной рантайм для всех серверных решений на JavaScript и TypeScript
—
👩💻 Deno — более новый, чем NodeJS, рантайм, от создателя NodeJS. Deno разработан для того, чтобы устранить некоторые недостатки и ограничения ноды, улучшить безопасность и лучшей поддержкой TypeScript. В целом, всё так и есть, только лично мне субъективно кажется, что Deno почти никто не использует(
👩💻 Bun — самый новый из этой тройки инструмент, который разработан для того, чтобы быть самым быстрым и легким в использовании, предлагая ряд улучшений по сравнению с другими инструментами. Bun быстрее запускает код, сильно лучше работает с асинхронными запросами, быстрее устанавливает зависимости... Но ему слишком мало лет, чтобы активно тащить его в прод — пока рановато
Лично я ставлю на то, что доминирующего рантайма пока что не будет, получится зоопарк, так как всем просто не угодить
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #javascript #typescript #useful
Начать стоит с того, что JavaScript может выполняться далеко не только в браузере. Для этого есть такая штука, как рантайм — это среда выполнения, которая обеспечивает все необходимое для выполнения JavaScript кода: движок языка, API среды и т.д.
Рантаймов несчётном множество, как и всего в мире JS, но в этом поговорим о самых интересных: NodeJS, Deno и Bun
— NodeJS сейчас — это основной рантайм для всех серверных решений на JavaScript и TypeScript
—
npm
(Node Package Manager) — это тоже про нодуКраткий итог:
— NodeJS - это зрелая платформа с обширной экосистемой и большим сообществом
— Deno - альтернатива NodeJS с улучшенной безопасностью, поддержкой TypeScript и другими плюшками
— Bun - новая и перспективная платформа с упором на скорость и интеграцию различных инструментов
Лично я ставлю на то, что доминирующего рантайма пока что не будет, получится зоопарк, так как всем просто не угодить
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #javascript #typescript #useful
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥22👍12❤11🐳1
Виды операторов в JavaScript
Операторы в языке (почти во всех языках, кстати), можно строго разделить на три категории:
1. Унарные операторы
Работают с одним операндом — то есть применяются только к одной переменной. Это, например, такие операторы, как
2. Бинарные операторы
Бинарные операторы работают с двумя операндами. Это самые распространенные операторы, включающие арифметические, логические, сравнительные и присваивающие операции
3. Тернарный оператор
Тернарный оператор — единственный оператор, который работает с тремя операндами и является сокращенной формой конструкции
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #code #javascript
Операторы в языке (почти во всех языках, кстати), можно строго разделить на три категории:
1. Унарные операторы
Работают с одним операндом — то есть применяются только к одной переменной. Это, например, такие операторы, как
i++
или --i
, смены знака -i
или отрицания !isTrue
let a = 5;
a++; // теперь a равно 6
let b = -a; // теперь b равно -6
Операнд — это элемент данных, над которым выполняется операция. В выражении i++ переменная i будет операндом, а ++ — оператором
2. Бинарные операторы
Бинарные операторы работают с двумя операндами. Это самые распространенные операторы, включающие арифметические, логические, сравнительные и присваивающие операции
const x = 10;
const y = 20;
const sum = x + y; // (+) - арифметический оператор
const isEqual = x == y; // (==) - сравнительный оператор
3. Тернарный оператор
Тернарный оператор — единственный оператор, который работает с тремя операндами и является сокращенной формой конструкции
if-else
. Он часто используется для кратких условийconst age = 31
const canKupitPivo = age >= 18 ? true : false
Краткий итог:
Операторы бывают трёх видов — унарные, бинарные и тернарные. Работают они с одним, двумя и тремя операндами соответственно
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #code #javascript
👍25❤9🔥5🐳1
Как определить с какого устройства открыт сайт
Самым простым способом является анализ строки User-Agent’a — это специальный заголовок, который передаётся браузером устройства вместе с любым запросом.
Сразу рассмотрим на примере:
Из этой строки можно достать информацию об устройстве пользователя, его операционной системе и браузере.
Чтобы проанализировать строку, можно воспользоваться либо готовыми библиотеками, либо написать примерно такой код:
Выше достаточно упрощённая версия кода, просто чтобы передать основную идею.
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #code #javascript
Самым простым способом является анализ строки User-Agent’a — это специальный заголовок, который передаётся браузером устройства вместе с любым запросом.
Сразу рассмотрим на примере:
Запрос с айфона из Safari:
Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1
Запрос с комьютера из Google Chrome:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
Из этой строки можно достать информацию об устройстве пользователя, его операционной системе и браузере.
Чтобы проанализировать строку, можно воспользоваться либо готовыми библиотеками, либо написать примерно такой код:
const isMobile = () => /Mobi|Android/i.test(navigator.userAgent)
if (isMobile()) {
console.log("Мобильное устройство");
} else {
console.log("Десктопное устройство");
}
Выше достаточно упрощённая версия кода, просто чтобы передать основную идею.
Пригодиться это может в нескольких кейсах:
— для изменения вёрстки под особенности устройства
— для сбора аналитики
— подключение и использование специфичных API (геолокация, сенсорные жесты, вибрация и пр.)
— ну и точно что-то ещё, о чём я мог забыть
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #code #javascript
👍25🔥6❤5🐳2
Что такое Callback Hell и как с ним бороться?
Частый вопрос с собеса, особенно если идти куда-то повыше стажёра.
Callback Hell — это ситуация в асинхронном программировании, когда вложенные друг в друга функции обратного вызова (он же callback) образуют "лесенку", что делает код трудным для чтения и сопровождения.
Как с этим можно бороться?
Конечно же промисы и async/await синтаксис:
Промисы позволяют писать асинхронный код более линейно и читаемо благодаря цепочке вызовов (chaining):
А async/await — это более современный синтаксис над промисами, который так же позволяет развернуть вложенные колбеки в плоский код:
И о Promise, и о async/await у меня уже есть более подробные посты
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #code #javascript #patterns #data
Частый вопрос с собеса, особенно если идти куда-то повыше стажёра.
Callback Hell — это ситуация в асинхронном программировании, когда вложенные друг в друга функции обратного вызова (он же callback) образуют "лесенку", что делает код трудным для чтения и сопровождения.
doSomething(function(result) {
doSomethingElse(result, function(newResult) {
doAnotherThing(newResult, function(finalResult) {
doSomethingMore(finalResult, function(lastResult) {
console.log(lastResult);
});
});
});
});
Как с этим можно бороться?
Конечно же промисы и async/await синтаксис:
Промисы позволяют писать асинхронный код более линейно и читаемо благодаря цепочке вызовов (chaining):
doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doAnotherThing(newResult))
.then(finalResult => console.log(finalResult))
.catch(error => console.error(error));
А async/await — это более современный синтаксис над промисами, который так же позволяет развернуть вложенные колбеки в плоский код:
async function process() {
try {
const result = await doSomething();
const newResult = await doSomethingElse(result);
const finalResult = await doAnotherThing(newResult);
console.log(finalResult);
} catch (error) {
console.error(error);
}
}
process();
И о Promise, и о async/await у меня уже есть более подробные посты
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #code #javascript #patterns #data
🔥18❤9👍9🐳3
Как открыть ссылку в новом окне или вкладке
Чтобы ссылка открывалась в новом окне или вкладке, достаточно добавить к тегу
Атрибут
Накидайте побольше китов 🐳 на пост и, если это будет актуально, сделаю отдельный пост с разбором
Если же вы сомневаетесь, ставить их или нет — ставьте всегда
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #web #useful
Чтобы ссылка открывалась в новом окне или вкладке, достаточно добавить к тегу
<a>
атрибут target="_blank"
:<a
href="https://t.me/prog_way_blog"
target="_blank"
rel="noopener noreferrer"
>
Ну чё-то какой-то канал в телеге
</a>
Атрибут
target="_blank"
сообщает браузеру, что ссылку нужно открыть в новой вкладке. И также стоит обратить внимание на атрибут rel
. Он предотвращает передачу информации о странице, с которой была открыта ссылка, а также защищает от потенциальных уязвимостейНакидайте побольше китов 🐳 на пост и, если это будет актуально, сделаю отдельный пост с разбором
noopener noreferrer
и зачем оно надоЕсли же вы сомневаетесь, ставить их или нет — ставьте всегда
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #web #useful
🐳71❤6🔥3👍1
Разделение чанков в Vite
Часто может быть так, что не малое приложение с большим количеством зависимостей весит несколько мегабайт. Такое приложение будет грузиться клиенту очень долго, особенно, если у него низкая скорость соединения. Далеко не в любых условиях у пользователей есть возможность загружать наши фронтенды на 100 МБитной линии, поэтому оптимизация загрузки — очень важно.
Пользовательский код можно загружать ленивой подгрузкой, но что сделать с библиотеками, которые собираются в один JS файл? Использовать разделение на чанки.
Чанк — собранные блоки кода, в виде которых пользователь загружает себе ваше приложение.
Идея в том, чтобы разделить приложение на несколько чанков. Это может быть полезно по нескольким причинам:
1. Открываются прелести асинхронной загрузки нескольких чанков
2. Есть возможность загружать не весь фронтенд сразу, а порционно, по мере необходимости
Выглядеть конфигурация может вот так:
Не очень красиво, но как есть. В единый чанк стоит объединять те библиотеки, что не могут работать друг без друга, например чанк
Что в итоге? Скорость загрузки приложения можно значимо увеличить. Для отрисовки, например, страницы авторизации, нам не нужны таблицы, графики и прочие красивости — загрузим чанки
Обычно, ленивая загрузка библиотек всё же не применяется, однако для организации кода внутри самого приложения — очень часто.
Выглядеть это будет примерно так:
Более подробно о
Спасибо за прочтение, для меня это важно ❤️
@prog_way_blog — чат — #theory #web #useful
Часто может быть так, что не малое приложение с большим количеством зависимостей весит несколько мегабайт. Такое приложение будет грузиться клиенту очень долго, особенно, если у него низкая скорость соединения. Далеко не в любых условиях у пользователей есть возможность загружать наши фронтенды на 100 МБитной линии, поэтому оптимизация загрузки — очень важно.
Пользовательский код можно загружать ленивой подгрузкой, но что сделать с библиотеками, которые собираются в один JS файл? Использовать разделение на чанки.
Чанк — собранные блоки кода, в виде которых пользователь загружает себе ваше приложение.
Идея в том, чтобы разделить приложение на несколько чанков. Это может быть полезно по нескольким причинам:
1. Открываются прелести асинхронной загрузки нескольких чанков
2. Есть возможность загружать не весь фронтенд сразу, а порционно, по мере необходимости
Выглядеть конфигурация может вот так:
build: {
rollupOptions: {
output: {
manualChunks: {
core: [
'react',
'react-dom',
'react-router-dom'
],
network: [
'axios',
'@tanstack/react-query'
],
utils: [
'classnames',
'dayjs',
'escape-html',
'tailwind-merge',
'zustand',
'@loadable/component'
],
table: [
'@tanstack/react-table',
'@tanstack/react-virtual'
],
chart: [
'reactflow',
'@dagrejs/dagre'
],
icons: ['@ant-design/icons'],
ui: [
'@chakra-ui/react',
'chakra-react-select',
'framer-motion',
'prismjs',
'react-simple-code-editor'
],
},
},
},
}
Не очень красиво, но как есть. В единый чанк стоит объединять те библиотеки, что не могут работать друг без друга, например чанк
core
. Также есть ещё и частотная группировка — когда легковесные библиотеки собирают в один чанк, чтобы быстро загрузить их все, так как понадобятся они на всех страницах, например чанк utils
Что в итоге? Скорость загрузки приложения можно значимо увеличить. Для отрисовки, например, страницы авторизации, нам не нужны таблицы, графики и прочие красивости — загрузим чанки
core
и network
, остальное нам не нужно. Остальные чанки мы можем загрузить по мере необходимости, используя асинхронные инструменты загрузки. Это могут быть @loadable
, который рекомендует команда React или же вовсе обычный import
. Обычно, ленивая загрузка библиотек всё же не применяется, однако для организации кода внутри самого приложения — очень часто.
Выглядеть это будет примерно так:
const About = lazy(() => import("./pages/about")); // для реакт компонентов
// более сложный пример импорта компонента с @loadable/components
const PageComponent = loadable((props) => import(`./pages/${props.page}`), {
fallback: <div>Page is Loading...</div>,
cacheKey: (props) => props.page
});
async function foo() {
const utils = await import("./utils.js") // для, например, утилсов
}
Более подробно о
manualChunks
можно прочитать в доке rollupСпасибо за прочтение, для меня это важно ❤️
@prog_way_blog — чат — #theory #web #useful
👍17❤5🔥3🐳2
noopener и noreferrer в браузере
При открытии ссылки в новой вкладке через атрибут
🟢 Атрибут
🟢 Атрибут
1. Предотвращает доступ к
2. Удаляет HTTP-заголовок
Для нас это просто дополнительная защита, которая запрещает ещё один способ просмотреть url, с которого открыта страница
Обычно эти атрибуты используют в паре.
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #web #useful
При открытии ссылки в новой вкладке через атрибут
target="_blank"
, браузер делает несколько не самых желанных для нас действий, от которых и спасают атрибуты noopener
и noreferrer
:noopener
предотвращает доступ новой вкладки к объекту window.opener
. Почему это важно? Без этого атрибута, сайт, открытый в новой вкладке, может получить доступ к оригинальной вкладке и потенциально выполнить вредоносный код, что представляет угрозу безопасности.window.opener
содержит слепок объекта window
для страницы, с которой был открыт сайт. Информация в таком объекте всё же сильно ограничена — новая вкладка не может получить доступ, например, к переменным с прошлой страницы, зато может осуществлять навигацию по старой вкладке, что открывает огромные возможности для фишинга.Представим, что вы находитесь на каком-нибудь some-bank.com и переходите на другой сайт с вредоносным кодом без noopener. Тогда новая вкладка может получить доступ к pathname откуда вы перешли и к API навигации по старой вкладке, и, уже абсолютно невидимо для вас, средиректить старую вкладку с some-bank.com на some-bauk.com (подмена символа в слове bank). Вернувшись на старую вкладку, вы увидите тот же сайт, но проблема в том, что он уже подменён на фишинг-страницу. Входите через эту страницу в личный кабинет банка и все данные улетают злоумышленникам.
Такая атака, кстати, называется tabnabbing
noreferrer
выполняет сразу две функции:1. Предотвращает доступ к
window.opener
, как и noopener
2. Удаляет HTTP-заголовок
Referer
при переходе по ссылке, что скрывает источник переходаReferer: https://some-bank.com/login
Для нас это просто дополнительная защита, которая запрещает ещё один способ просмотреть url, с которого открыта страница
Обычно эти атрибуты используют в паре.
noreferrer
как бы включает в себя noopener
, а значит вроде бы можно использовать только его, но на практике так никто не делает. Связано это попросту с тем, что каждый браузер Referrer-Policy
раньше реализовал по своему, да и так просто спокойнее что лиЕсли кратко:
- noopener — блокирует доступ на новой вкладке к информации и навигации на старой
- noreferrer — noopener + удаляет заголовок Referrer
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #web #useful
Please open Telegram to view this post
VIEW IN TELEGRAM
👍32❤10🔥7🐳1
Как скачать файл с сайта
У тега ссылки <a> есть очень удобный атрибут
Также в атрибут
Стоит учитывать, что скачивать файлы мы можем только с тех хостов, в которых выполняются CORS политики для нашего сайта. Более подробно о CORS я писал как у себя в канале, так в статье на doka.guide
Сейчас этот атрибут уже достиг порога поддержки в более чем 97% согласно
@prog_way_blog — чат — #theory #web #useful
У тега ссылки <a> есть очень удобный атрибут
download
, который позволяет скачать любой файл с сайта. Выглядит его использование примерно так:<a
download
href="https://.../files/example.zip"
>
Скачать файл
</a>
Также в атрибут
download
можно передать собственное название для файла, например:<a
download="новое_название_файла.zip"
href="https://.../files/example.zip"
>
Скачать файл
</a>
Стоит учитывать, что скачивать файлы мы можем только с тех хостов, в которых выполняются CORS политики для нашего сайта. Более подробно о CORS я писал как у себя в канале, так в статье на doka.guide
Сейчас этот атрибут уже достиг порога поддержки в более чем 97% согласно
caniuse
и не поддерживается полноценно только в IEРебята, если у вас есть идеи о чём ещё вам было бы интересно прочитать, обязательно отпишитесь в чатик или мне в личку.
Всем добра)
@prog_way_blog — чат — #theory #web #useful
🔥18👍7🐳3
CSS для печати страниц
Несколько лет назад я делал пет-проект — конструктор резюме. Кейс был такой, что хотелось сразу же печатать созданное резюме при нажатии сочетания клавиш
То есть во время печати мы можем скрыть все ненужные элементы:
Ну или ещё проще:
А сам класс
Также есть ещё специальные CSS свойства печати, например,
В реальной практике также особенно полезно использовать подобные поднастройки стилей для печати кастомных чеков, накладных, этикеток для маркетплейсов и прочих документов, что иногда реально верстаются где-то кроме ворда.
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #code #web #useful
Несколько лет назад я делал пет-проект — конструктор резюме. Кейс был такой, что хотелось сразу же печатать созданное резюме при нажатии сочетания клавиш
Ctrl+P
в браузере. Но проблема в том, что помимо самого резюме на печать попадало не только само резюме, а все кнопки, поля и прочие элементы страницы для его настройки. Такие кейсы можно решать при помощи CSS медиазапроса @media print
:@media print {
/* стили для печати */
}
То есть во время печати мы можем скрыть все ненужные элементы:
@media print {
.navbar, .footer, .controls {
display: none;
}
}
Ну или ещё проще:
@media print {
.no-print {
display: none;
}
}
А сам класс
.no-print
проставлять на все скрываемые при печати элементы.Также есть ещё специальные CSS свойства печати, например,
break-inside
, которое дополнительно настраивает можно ли переместить блок со страницы на страницу при печати, что особенно актуально для целостных блоков типа “контакты” в резюме. Если указать break-inside: avoid
, то такой элемент не сможет быть расположен на двух страницах сразу, а перенесётся весь, если для него не хватает места.В реальной практике также особенно полезно использовать подобные поднастройки стилей для печати кастомных чеков, накладных, этикеток для маркетплейсов и прочих документов, что иногда реально верстаются где-то кроме ворда.
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #code #web #useful
👍34🔥8❤4🐳1
Что такое CI/CD
Помимо того, что разработчики должны уметь писать сам код, было бы неплохо уметь автоматизировать его публикацию и все попутные процессы, что с этим связаны — тестирование, сборка…
Для этого есть CI/CD — набор практик, который позволяет автоматизировать практически всё, кроме написания самого кода.
🟢 CI — Continuous Integration — это всё, что касается интеграции нового кода в репозиторий. В основном, это автоматизация сборки, тестирования и разные проверки в коде, типа eslint, prettier или biome.
🟢 CD — Continuous Delivery (иногда расшифровывают как Continuous Deployment) — это всё, что связано с доставкой готового собранного образа вашего приложения на какое-то окружение (сервер) и его запуск для дальнейшей работы. Ведь собрать приложение недостаточно для его публикации — сборку нужно ещё куда-то загрузить и как-то запустить.
Если поверхностно, CI/CD — это именно об этом. Думаю, что сделаю ещё какие-то более подробные посты в будущем, если это будет актуально.
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #data #useful
Помимо того, что разработчики должны уметь писать сам код, было бы неплохо уметь автоматизировать его публикацию и все попутные процессы, что с этим связаны — тестирование, сборка…
Для этого есть CI/CD — набор практик, который позволяет автоматизировать практически всё, кроме написания самого кода.
Основное отличие от ручного способа заключается лишь в том, что все эти процессы выполняются не на компьютерах разработчиков, а где-то там далеко на серверах GitHub или типа того, всё зависит от архитектуры вашей системы контроля версий.
Если поверхностно, CI/CD — это именно об этом. Думаю, что сделаю ещё какие-то более подробные посты в будущем, если это будет актуально.
Если коротко:
CI — процессы, связанные с интеграцией кода в репозиторий
CD — процессы, связанные с доставкой готовой сборки на окружение
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #data #useful
Please open Telegram to view this post
VIEW IN TELEGRAM
❤28👍10🐳4🔥1👀1
Как отменить уже отправленный HTTP запрос?
Для отмены уже отправленного запроса нам пригодится встроенный в JavsScript объект —
Этот объект позволяет отменять уже запущенные асинхронные операции,
Нужно это много где, я приведу самый очевидный пример с реактом:
Представим, что пользователь открывает страницу. На странице в
Использование🌚
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #javascript #code #data
Для отмены уже отправленного запроса нам пригодится встроенный в JavsScript объект —
AbortController
Этот объект позволяет отменять уже запущенные асинхронные операции,
fetch
в том числеconst controller = new AbortController()
// отправляем запрос
fetch('https://.../', { signal: controller.signal })
// отменяем его
controller.abort()
Нужно это много где, я приведу самый очевидный пример с реактом:
Представим, что пользователь открывает страницу. На странице в
useEffect
идёт запрос к API, но пользователь, не дожидаясь ответа от сервера, переходит на другую страницу. Запрос есть, трафик занят, есть риск нарушения жизненного цикла компонента, а результаты этого запроса уже и вовсе не нужны. Вот так это решается:useEffect(() => {
const controller = new AbortController()
// делаем запрос на маунт компонента
fetch('https://.../', { signal: controller.signal })
// отменяем запрос на анмаунт компонента
return () => controller.abort()
}, [])
Использование
AbortController'a
помогает избежать потенциальных утечек памяти и гарантирует, что запросы не будут выполняться после того, как компонент был размонтирован. Полезно это при любых запросах, так что можно смело сделать свой хук обёртку. Или просто использовать @tanstack/react-query
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #javascript #code #data
Please open Telegram to view this post
VIEW IN TELEGRAM
👍32❤11🔥3🐳2🤯1🤩1
Разница между CommonJS и ES Modules
Если по простому, то CommonJS и ES (ECMAScript) Modules — это два способа импорта и экспорта чего либо из файлов в JavaScript
CommonJS — относительно старый API, который был разработан для NodeJS. Выглядит он следующим образом:
ES Modules — это подход, который в язык принес ECMAScript 2015 (ES6). Он задумывался как замена устаревшему CommonJS и выглядит так:
ИМХО, в современной разработке от CommonJS можно отказаться как от рудимента. Я стараюсь использовать модули по максимуму
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #javascript #code
Если по простому, то CommonJS и ES (ECMAScript) Modules — это два способа импорта и экспорта чего либо из файлов в JavaScript
CommonJS — относительно старый API, который был разработан для NodeJS. Выглядит он следующим образом:
// Экспорт
module.exports = function() {
console.log(...);
};
// Импорт
const module = require('./module');
module();
Особенностью CommonJS является синхронная загрузка модулей. Это означает, что когда один модуль требует другой модуль, выполнение кода приостанавливается до тех пор, пока требуемый модуль не будет загружен и выполнен
Для браузера, синхронная загрузка — крайне неудачный подход из-за блокировки интерфейса в момент загрузки. Поэтому в браузере использовать CommonJS — моветон, лучше использовать ES Modules
ES Modules — это подход, который в язык принес ECMAScript 2015 (ES6). Он задумывался как замена устаревшему CommonJS и выглядит так:
// Экспорт
export function foo() {
console.log(...)
}
// Импорт
import { foo } from './module.js';
foo();
ES Modules поддерживают асинхронную загрузку модулей и лучше умеют в статический анализ, что лучше как со стороны пользователя, так и разработчика.
Также ES Modules могут использоваться не только в браузере, а и в NodeJS, начиная аж с 12 версии. Как же давно это было🥲
ИМХО, в современной разработке от CommonJS можно отказаться как от рудимента. Я стараюсь использовать модули по максимуму
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #javascript #code
👍30❤11🐳6🔥5
Как убрать стили на под-дереве — мини-задача с реального проекта
Недавно был следующий кейс: в долгоживущий проект интегрировали
То есть мы приходим к ситуации, когда у нас есть некоторые глобальные стили, которые нужны везде по проекту, кроме каких-то под-деревьев исключений. Самый дешевый вариант решить эту проблему — обнулить стили на под-дереве
Обнулить все стили на под-дереве можно с помощью CSS свойства
Свойство
Далее полученный класс
Конечно же, можно всё и с нуля переписать, или даже указать все необходимые стили для каждого тега вручную, но какой-то необходимости в этом нет. Всё можно решить буквально в одну строчку
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #web #code
Недавно был следующий кейс: в долгоживущий проект интегрировали
tailwind
со своими обнуляющими стилями. Эти стили очень нужны проекту, но на одной из страничек есть Rich-текст, приходящий с апишки, который, к сожалению, частично завязан на браузерные стили, и, после добавления обнуляющих стилей tailwind
, весь поплылОбнуляющие стили — это когда все заголовки, списки и прочие HTML теги сбрасывают свои стандартные браузерные стили, чтобы тег нёс за собой только семантику
То есть мы приходим к ситуации, когда у нас есть некоторые глобальные стили, которые нужны везде по проекту, кроме каких-то под-деревьев исключений. Самый дешевый вариант решить эту проблему — обнулить стили на под-дереве
Обнулить все стили на под-дереве можно с помощью CSS свойства
all
. Выглядеть это может так:.tailwind-reset-styles * {
all: revert;
}
Свойство
all
может сбросить все CSS свойства до их начального или унаследованного значения, что конкретно в моём случае полностью решало все проблемыДалее полученный класс
.tailwind-reset-styles
вешаем на родительский тег, все под-дерево которого уже будет со сброшенными ненаследуемыми стилями. Это, наверное, самое элегантное и быстрое решение, что можно придумать в этой ситуацииКонечно же, можно всё и с нуля переписать, или даже указать все необходимые стили для каждого тега вручную, но какой-то необходимости в этом нет. Всё можно решить буквально в одну строчку
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #web #code
👍29❤6🔥5🐳5