progway — программирование, IT
2.73K subscribers
25 photos
1 video
246 links
Чат: @prog_way_chat

Разборы вопросов и задач с собеседований, мысли, полезные материалы и просто вещи, что мне интересны из мира IT

Полезности и навигация в закрепе

По всем вопросам: @denisputnov
Download Telegram
Что такое семантика?

Семантика в HTML относится к использованию HTML-тегов, которые ясно и однозначно описывают их содержимое и роль в структуре веб-страницы. Семантические теги помогают как разработчикам, так и браузерам и поисковым системам понять смысл и контекст контента на странице быстрее и точнее.

Семантических тегов множество, однако, самые используемые из них:

<header> - заголовок секции или документа
<nav> - навигационное меню
<article> - независимая часть контента, например, статья, пост...
<section> - определяет раздел конкретного документа, статьи, поста...
<aside> - содержит контент, связанный с основным содержанием страницы, но не являющийся его частью
<footer> - представляет нижний колонтитул секции или документа


Конечно же семантических тегов сильно больше, но рассматривать их все в этом посте я не буду.

Важнее сказать, что семантические теги делятся на 2 категории значимости:
— Первая категория, по сути, имеет те же свойства и вид, что обычный div. Их особенность заключается лишь в том, как эти теги будут обрабатываться парсерами и служат они в основном для SEO.
— Вторая категория — когда тег имеет дополнительные уникальные свойства и поведение, а, возможно, и внешний вид.

Давайте сразу на примере:

<header> - по сути, тот же <div>, но просто парсится иначе

<button> - тоже семантический тег

Но, помимо особой семантической значимости, этот тег также имеет и другие свойства:
- встроенные обработчики событий для взаимодействия с клавиатуры
- иной внешний вид
- верная HTML-роль по умолчанию


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

Давайте соберём под постом как можно больше 🔥 и я сделаю отдельный пост на тему зачем эта семантика нужна. Вопрос, который встречается на каждом втором собесе, наверное.

Да и в целом не забывайте про реакции. Они реально мотивируют меня что-то писать.

Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат#theory #web #useful
Please open Telegram to view this post
VIEW IN TELEGRAM
Управление фокусировкой

Часто на собеседовании могут спросить об управлении состоянием фокуса. Обычно вопрос подаётся в контексте следующей задачи:

Представим, что у нас есть страница авторизации. Как сделать так, чтобы при открытии страницы пользователь сразу же был сфокусирован на поле ввода логина?

Начнем с того, у тега 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
Определяющие тайпгарды

Как я и писал в одном из прошлых постов, тайпгарды есть двух видов: уточняющие и определяющие. Уточняющие попроще, их я разобрал как раз в прошлом посте.

Определяющие тайпгарды — это функции, которые позволяют уточнить тип 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
Что такое Git Flow?

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
Какими способами можно скрыть элемент со страницы?

Для многих каверзный вопрос. В этом посте коротко рассмотрим какие есть варианты

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
Что такое декларативность и императивность?

Императивный подход написания кода фокусируется на том, КАК именно должна быть выполнена задача. В императивном стиле вы указываете шаг за шагом, что должно происходить, ничего не скрывая, например:

// Императивный способ создания списка из элементов массива
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
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Что такое Callback Hell и как с ним бороться?

Частый вопрос с собеса, особенно если идти куда-то повыше стажёра.

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
Как открыть ссылку в новом окне или вкладке

Чтобы ссылка открывалась в новом окне или вкладке, достаточно добавить к тегу <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
Разделение чанков в Vite

Часто может быть так, что не малое приложение с большим количеством зависимостей весит несколько мегабайт. Такое приложение будет грузиться клиенту очень долго, особенно, если у него низкая скорость соединения. Далеко не в любых условиях у пользователей есть возможность загружать наши фронтенды на 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
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
CSS для печати страниц

Несколько лет назад я делал пет-проект — конструктор резюме. Кейс был такой, что хотелось сразу же печатать созданное резюме при нажатии сочетания клавиш 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
Please open Telegram to view this post
VIEW IN TELEGRAM