Как открыть ссылку в новом окне или вкладке
Чтобы ссылка открывалась в новом окне или вкладке, достаточно добавить к тегу
Атрибут
Накидайте побольше китов 🐳 на пост и, если это будет актуально, сделаю отдельный пост с разбором
Если же вы сомневаетесь, ставить их или нет — ставьте всегда
Спасибо за прочтение, это важно для меня ❤️
@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
Что такое SWC и немного о Rust
SWC — это аббревиатура, которая всё чаще появляется в мире фронтенда. Расшифровывается это как Speedy Web Compiler и полностью оправдывает своё название, ведь SWC — это ультрабыстрый компилятор и пакетный обработчик, написанный на Rust. Он предназначен для преобразования современного JavaScript и TypeScript кода в код, который будет поддерживаться большинством браузеров. Возможно это во многом из-за полифилов, о которых я писал в этом посте
Уже сейчас SWC используется в продуктах Vercel (в Next.js и Turbopack в том числе), Tencent, Shopify и других компаний, а также ложится в основу Vite начиная ещё с 4 версии (сейчас 5), так что с нами он плюс минус на долго
Да и больше про SWC сказать обзорно особо нечего. Мне во всём этом очень занимательно наблюдать за тем, какой огромный фокус на скорость появляется в фронтенде. Rust постепенно захватывает тулинг фронтенда: сборщики, компиляторы, линтеры и так далее — уже почти в каждой части тулинга есть решение на Rust и это, очевидно, не просто так
Ну и также не стоит забывать, что Rust уже давно имеет полную поддержку WebAssembly и является одним из основных языков этой технологии. Лично мне очень интересно понаблюдать, куда это всё приведёт. Накидывайте китов , сделаю отдельный пост по WebAssembly
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #web #code
SWC — это аббревиатура, которая всё чаще появляется в мире фронтенда. Расшифровывается это как Speedy Web Compiler и полностью оправдывает своё название, ведь SWC — это ультрабыстрый компилятор и пакетный обработчик, написанный на Rust. Он предназначен для преобразования современного JavaScript и TypeScript кода в код, который будет поддерживаться большинством браузеров. Возможно это во многом из-за полифилов, о которых я писал в этом посте
Если ещё проще, то SWC выполняет все функции Babel, только делает это в более чем 20 раз быстрее на одном ядре, и более чем в 70 раз быстрее на 4 ядрах.
Снова Rust всех победил🤷♂️ 🤷♂️ 🤷♂️
Уже сейчас SWC используется в продуктах Vercel (в Next.js и Turbopack в том числе), Tencent, Shopify и других компаний, а также ложится в основу Vite начиная ещё с 4 версии (сейчас 5), так что с нами он плюс минус на долго
Да и больше про SWC сказать обзорно особо нечего. Мне во всём этом очень занимательно наблюдать за тем, какой огромный фокус на скорость появляется в фронтенде. Rust постепенно захватывает тулинг фронтенда: сборщики, компиляторы, линтеры и так далее — уже почти в каждой части тулинга есть решение на Rust и это, очевидно, не просто так
Ну и также не стоит забывать, что Rust уже давно имеет полную поддержку WebAssembly и является одним из основных языков этой технологии. Лично мне очень интересно понаблюдать, куда это всё приведёт. Накидывайте китов , сделаю отдельный пост по WebAssembly
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #web #code
Please open Telegram to view this post
VIEW IN TELEGRAM
🐳39❤7👍3🔥2
Про платные курсы и менторинг
Довольно часто звучит вопрос, в том числе и от моей аудитории в личке, который выглядит примерно так:
Отвечаю на этот вопрос постом: никакие
Курсы — далеко не волшебная таблетка. Особенно сейчас. Я регулярно натыкаюсь на рекламу разных курсов, кажется, даже чаще, чем раз в день. И для меня провалиться в курс и посмотреть его описание, затрагиваемые темы, примерный план — профессиональный интерес
Я и сам занимаюсь своего рода "образовательным", прости господи, контентом, поэтому посмотреть такое бывает и правда занятно
И ничего невероятного там, как очевидно, я не увидел ни разу
Также, думаю, ни для кого не секрет, что у составителей курсов нет никакой секретной информации или методики обучения. Вас никогда не сделают джуном за месяц или мидлом за 3. Такие фразы в рекламе — самый красный флаг из всех возможных. По сути, всё уникальное торговое предложение о покупке курса заключается в следующих пунктах:
— качественная структуризация информации, что особенно актуально для новичков в сфере, которые не знаю как и с чего начать
— адекватная обратная связь при ревью домашних заданий и прохождении контрольных точек (есть только в очень хороших курсах на рынке)
— помощь с трудоустройством (есть только в топовых курсах на рынке, но без каких либо гарантий)
— дополнительная мотивация завершить начатое, ведь вы уже заплатили значимую сумму
По сути, основное преимущество курсов — это структуризация информации и обратная связь. Остальные фичи — посредственны и представляют собой не более чем маркетинговый ход
И, к счастью, особенно front-end сообщество активно делится своим опытом с новичками и делает это совершенно бесплатно. Можно использовать даже тот же roadmap.sh, где, на самом-то деле, реально неплохая структура, которой можно следовать до определенного уровня
Я всё это к тому, что при покупке курса стоит держать в голове, что вы покупаете не информацию. Вы покупаете способ её получения, который, скорее всего, ничем не превосходит бесплатные курсы
Чего у платных курсов не отнять — помощь с трудоустройством и обратную связь. Но, если честно, слишком много денег они за это просят
Я бы советовал каждому пользоваться бесплатными курсами или обратиться к частному ментору, который сделает с вами проект, поможет собрать хорошее резюме, провести или разобрать собеседование, провести ревью кода или рассказать что-то из своего опыта, в общем, помочь всем, чем может
Чаще всего, частный менторинг — это не просто годнота с индивидуальным подходом, это ещё и сильно дешевле курсов
У меня у самого был ментор, я сам был ментором — я знаю, что это такое
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #blog #useful
Довольно часто звучит вопрос, в том числе и от моей аудитории в личке, который выглядит примерно так:
Какие курсы посоветуешь купить?
Отвечаю на этот вопрос постом: никакие
Курсы — далеко не волшебная таблетка. Особенно сейчас. Я регулярно натыкаюсь на рекламу разных курсов, кажется, даже чаще, чем раз в день. И для меня провалиться в курс и посмотреть его описание, затрагиваемые темы, примерный план — профессиональный интерес
Я и сам занимаюсь своего рода "образовательным", прости господи, контентом, поэтому посмотреть такое бывает и правда занятно
И ничего невероятного там, как очевидно, я не увидел ни разу
ИМХО, важно держать в голове мысль, что конечная цель производителей курсов — продать курс. Это, всё таки, рынок, а деньги не пахнут. Грустно, но ничего с этим не сделаешь
Также, думаю, ни для кого не секрет, что у составителей курсов нет никакой секретной информации или методики обучения. Вас никогда не сделают джуном за месяц или мидлом за 3. Такие фразы в рекламе — самый красный флаг из всех возможных. По сути, всё уникальное торговое предложение о покупке курса заключается в следующих пунктах:
— качественная структуризация информации, что особенно актуально для новичков в сфере, которые не знаю как и с чего начать
— адекватная обратная связь при ревью домашних заданий и прохождении контрольных точек (есть только в очень хороших курсах на рынке)
— помощь с трудоустройством (есть только в топовых курсах на рынке, но без каких либо гарантий)
— дополнительная мотивация завершить начатое, ведь вы уже заплатили значимую сумму
По сути, основное преимущество курсов — это структуризация информации и обратная связь. Остальные фичи — посредственны и представляют собой не более чем маркетинговый ход
И, к счастью, особенно front-end сообщество активно делится своим опытом с новичками и делает это совершенно бесплатно. Можно использовать даже тот же roadmap.sh, где, на самом-то деле, реально неплохая структура, которой можно следовать до определенного уровня
Даже этот канал — на мой вкус, сборник реально крутой информации. Я в него душу вкладываю, а в замен прошу лишь эмоцию кита 🐳 под пост. В канале практически нет рекламы, он совершенно не окупается для меня, хотя требует вложения как денег, так и времени. И мой канал — далеко не единственный такой пример
Я всё это к тому, что при покупке курса стоит держать в голове, что вы покупаете не информацию. Вы покупаете способ её получения, который, скорее всего, ничем не превосходит бесплатные курсы
Чего у платных курсов не отнять — помощь с трудоустройством и обратную связь. Но, если честно, слишком много денег они за это просят
Я бы советовал каждому пользоваться бесплатными курсами или обратиться к частному ментору, который сделает с вами проект, поможет собрать хорошее резюме, провести или разобрать собеседование, провести ревью кода или рассказать что-то из своего опыта, в общем, помочь всем, чем может
Чаще всего, частный менторинг — это не просто годнота с индивидуальным подходом, это ещё и сильно дешевле курсов
У меня у самого был ментор, я сам был ментором — я знаю, что это такое
Сейчас менторингом я не занимаюсь, но, думаю, что в перспективе я бы вернулся к нему, мне это интересно. Такой менторинг будет платный. Если я скажу, что собираюсь заниматься им бесплатно, то мне не хватит времени работать
Если вам это как-то интересно, поставьте эмоцию кита 🐳 на пост или напишите в личку, мне интересен спрос и ваше виденье ситуации
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #blog #useful
🐳48❤11👍10😐1
Что такое виртуализация?
Это крайне популярная техника оптимизации, которая позволяет эффективно управлять отображением большого количества элементов на странице. Особенно она полезна при отображении большого массива данных в списках, таблицах и прочих подобных элементах
Если объяснять на пальцах как это работает, то я бы сказал так:
Мы можем представить, что хотим послушать музыку. Открываем что-то типа Тындыкс.Музыки и видим 10.000 разных треков — это 10.000 строк огромного списка
Так вот, зачем отображать все 10.000 сразу, если на экране в лучшем случае поместиться треков 20-30? Давайте рисовать только первые, например, 50 треков, а дальше следить за тем что видит пользователь — за его скроллом. Если пользователь прокрутит ещё на 20 строк вниз, то мы нарисуем следующие 20 строк, а первые 20 удалим из вёрстки
Под коробкой все виртуализаторы как раз этим и занимаются:
1. Определяют какие элементы видны пользователю сейчас
2. Определяют сколько элементов скрыто над и под окном просмотра
Чаще всего это реализуют через события
Виртуализация может пригодиться в огромном срезе приложений, поэтому очень советую с ней ознакомиться заранее, если вы ещё не успели
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #javascript #code #react
Это крайне популярная техника оптимизации, которая позволяет эффективно управлять отображением большого количества элементов на странице. Особенно она полезна при отображении большого массива данных в списках, таблицах и прочих подобных элементах
Я очень рекомендую TanStack Virtual для этой задачи. Мне уже удалось применить его на нескольких проектах и никаких проблем он не вызывал
Если объяснять на пальцах как это работает, то я бы сказал так:
Мы можем представить, что хотим послушать музыку. Открываем что-то типа Тындыкс.Музыки и видим 10.000 разных треков — это 10.000 строк огромного списка
Так вот, зачем отображать все 10.000 сразу, если на экране в лучшем случае поместиться треков 20-30? Давайте рисовать только первые, например, 50 треков, а дальше следить за тем что видит пользователь — за его скроллом. Если пользователь прокрутит ещё на 20 строк вниз, то мы нарисуем следующие 20 строк, а первые 20 удалим из вёрстки
Под коробкой все виртуализаторы как раз этим и занимаются:
1. Определяют какие элементы видны пользователю сейчас
2. Определяют сколько элементов скрыто над и под окном просмотра
Чаще всего это реализуют через события
scroll
на контейнере или через IntersectionObserver
, подробности реализации для особо любопытных всегда доступны в сорсах библиотек (в TanStack Virtual можете начать с функции observeElementRect)Виртуализация может пригодиться в огромном срезе приложений, поэтому очень советую с ней ознакомиться заранее, если вы ещё не успели
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #javascript #code #react
🐳26👍9❤5🔥4
Как браузер понимает, что нужно закешировать?
Частый вопрос с собесов, который, к тому же, часто может пригодиться и на практике
Некоторые современные браузеры стараются кешировать файлы опираясь на частоту их использования и изменения. То есть, чтобы кеширование хоть как-то начало работать, браузеру необходимо собрать некоторую историю ваших посещений и загрузок ресурсов для открытия сайтов. Сам по себе этот способ не очень надежный, про него мало кто знает и рассчитывают на него достаточно редко
Самый простой способ контролировать кеширование в браузере — это напрямую сказать браузеру что можно кешировать и как долго это можно сделать. Реализуют это обычно через специальные HTTP заголовки
—
—
—
Также есть ещё один заголовок —
Обычно
Если нужно кешировать ресурс по времени, то обычно используют
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #web #data
Частый вопрос с собесов, который, к тому же, часто может пригодиться и на практике
Кеширование — это способ оптимизации загрузки через хранение копий файлов на вашем устройстве, чтобы ускорить доступ к ним в будущем. Это могут быть HTML, CSS, JS файлы, изображения, шрифты и всё остальное
Некоторые современные браузеры стараются кешировать файлы опираясь на частоту их использования и изменения. То есть, чтобы кеширование хоть как-то начало работать, браузеру необходимо собрать некоторую историю ваших посещений и загрузок ресурсов для открытия сайтов. Сам по себе этот способ не очень надежный, про него мало кто знает и рассчитывают на него достаточно редко
Самый простой способ контролировать кеширование в браузере — это напрямую сказать браузеру что можно кешировать и как долго это можно сделать. Реализуют это обычно через специальные HTTP заголовки
Cache-Control
и Expires
:Cache-Control
заголовок может иметь несколько значений:—
no-cache
— браузер проверяет актуальность ресурса на сервере при каждом запросеЭто значение не означает, что браузер вообще не должен кешировать ресурс, как это может показаться на первый взгляд.
На самом деле, ресурс все равно может быть сохранен в кеше, но с этим заголовком браузер обязан каждый раз перед его использованием обращаться к серверу, чтобы проверить, не изменилась ли версия ресурса.
Чаще всего это значение используют с ресурсами, что изменяются часто
—
no-store
— полностью запрещает хранить ресурс в кеше. Особенно полезно для чувствительных данных, типа истории переводов в банке—
public, max-age=31536000
— пример агрессивного кеширования, где ресурс можно хранить в кеше до одного года (максимальное время max-age указывается в секундах). Например, это может быть применено к логотипу компании, который редко меняетсяТакже есть ещё один заголовок —
Expires
. Он указывает точную дату и время, до которого ресурс считается актуальным и может быть использован из кеша без проверки на сервере:Expires: Wed, 21 Oct 2024 07:28:00 GMT
Этот заголовок говорит браузеру, что ресурс может использоваться
из кеша до 21 октября 2024 года 07:28:00 по времени GMT
Обычно
Expires
используется реже из-за того, что он работает именно с абсолютными датами. Если ваши серверные часы или время на устройстве пользователя настроены неправильно, это может привести к некорректному кешированиюЕсли нужно кешировать ресурс по времени, то обычно используют
Cache-Control
и его параметр max-age
, так как в этом случае дата окончания кеширования рассчитывается относительно настроек времени на устройстве пользователяКратко:
Чаще всего браузер понимает что кешировать через специальный заголовок Cache-Control
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #web #data
👍40🐳10🔥8❤3
Как менять состояние вкладки по интервалу
Полезная фича для демонстрации, например, уведомлений, которая может пригодиться на очень большом количестве сайтов
Для реализации нам необходимо создать состояния, между которыми мы хотим перемещаться:
Далее необходимо завести состояние, которое будет определять на каком этапе из списка состояний мы сейчас находимся. Это состояние можно будет менять через обычный интервал:
И в зависимости от текущего состояния изменяем параметры вкладки:
Очевидно, что в таком исполнении решение выглядит не очень красиво. Можно создать кастомный хук и вынести всю логику туда, например, или воспользоваться нативными контекстами. В общем, сделать из этого решения либу, которую можно будет легко перенести из проекта в проект
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #code #web #theory #javascript #react
Полезная фича для демонстрации, например, уведомлений, которая может пригодиться на очень большом количестве сайтов
Для реализации нам необходимо создать состояния, между которыми мы хотим перемещаться:
const states = [
{ title: "Мессенджер", icon: Favicon1 },
{ title: "Новое сообщение", icon: Favicon2 },
]
Далее необходимо завести состояние, которое будет определять на каком этапе из списка состояний мы сейчас находимся. Это состояние можно будет менять через обычный интервал:
const [stateIndex, setStateIndex] = useState(0);
// раз в секунду переходим на следующее состояние
useEffect(() => {
const intervalId = setInterval(() => {
setStateIndex((prevIndex) => (prevIndex + 1) % states.length);
}, 1000);
return () => clearInterval(intervalId);
}, []);
И в зависимости от текущего состояния изменяем параметры вкладки:
useEffect(() => {
const link = document.querySelector("link[rel~='icon']");
const title = document.querySelector("head title");
if (link) {
link.href = states[stateIndex].icon;
title.textContent = states[stateIndex].title;
}
}, [stateIndex]);
Очевидно, что в таком исполнении решение выглядит не очень красиво. Можно создать кастомный хук и вынести всю логику туда, например, или воспользоваться нативными контекстами. В общем, сделать из этого решения либу, которую можно будет легко перенести из проекта в проект
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #code #web #theory #javascript #react
🐳22😐8👍5❤4🔥2
progway — программирование, IT
Как менять состояние вкладки по интервалу Полезная фича для демонстрации, например, уведомлений, которая может пригодиться на очень большом количестве сайтов Для реализации нам необходимо создать состояния, между которыми мы хотим перемещаться: const states…
This media is not supported in your browser
VIEW IN TELEGRAM
Примерно вот так это может в итоге выглядеть
🐳18🗿1
Как определить, активна ли вкладка у пользователя?
Если вам нужно узнать, активна ли вкладка в браузере у пользователя, существует несколько простых методов для этого
Во-первых, у объекта
Это может быть полезно для определения состояния в моменте, хотя пригождается достаточно редко
Чаще всего используется второй способ, а именно отслеживание события
Тут мы отслеживанием фокус вкладки и выполняем какие-то действия на уже при изменении состояния. Особенно полезен такой способ будет где нибудь в React и прочих либах
Зачем это можно использовать? Да абсолютное множество применений:
— дополнительно сохранять данные на закрытие вкладки
— выключать аудио/видео при скрытии вкладки
— сбор аналитики
— и куча всего ещё
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #code #web #theory #javascript
Если вам нужно узнать, активна ли вкладка в браузере у пользователя, существует несколько простых методов для этого
Во-первых, у объекта
document
есть свойство hidden
, которое указывает открыта ли вкладка на экране пользователя в конкретный момент времени:// если true, значит вкладка работает в фоне
document.hidden // true
// вкладка открыта на весь экран
document.hidden // false
Это может быть полезно для определения состояния в моменте, хотя пригождается достаточно редко
Чаще всего используется второй способ, а именно отслеживание события
visibilitychange
:document.addEventListener("visibilitychange", function() {
if (document.hidden) {
console.log("Вкладка неактивна")
} else {
console.log("Вкладка активна")
}
})
Тут мы отслеживанием фокус вкладки и выполняем какие-то действия на уже при изменении состояния. Особенно полезен такой способ будет где нибудь в React и прочих либах
Зачем это можно использовать? Да абсолютное множество применений:
— дополнительно сохранять данные на закрытие вкладки
— выключать аудио/видео при скрытии вкладки
— сбор аналитики
— и куча всего ещё
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #code #web #theory #javascript
👍23🔥5🐳3❤2
"Тяжёлые" анимации
На самом деле, на производительность сайта может влиять очень много что — и CSS в том числе. Есть множество свойств, которые даются браузеру для обработки сложнее прочих: о таких свойствах как раз в этом посте
И для того, чтобы разобраться в нюансах, стоит помнить, что отрисовка контента страницы происходит в несколько этапов, таких как получение ресурсов, парсинг HTML и CSS, создание Render Tree и так далее. Более подробно можно прочитать в отличной статье на доке
Мы же сконцентрируемся на Layout и Paint фазах, их я кратко напомню:
Также помним, что Paint без Layout не бывает, а если вызывается пересчёт Layout, то и в фазу Paint мы обязательно попадём, причём с нуля
Так вот, к чему это я: анимация любого свойства, которое так или иначе влияет на расположение элементов на странице будет вызывать Layout и Paint на каждый фрейм анимации, а сам по себе процесс отрисовки — это далеко не дёшево
Часто можно столкнуться с анимацией, когда какой-то элемент на странице (изображение, текст или ещё что-то) плавают по странице в зависимости от положения курсора. Там анимация беспрерывна, и если реализовать подобную анимацию через свойства
Решается это просто — на помощь приходит Compositing
Браузеры умеют применять это и самостоятельно, но у нас и у самих есть возможность вынести элемент на отдельный слой: использовать
Анимацию плавающего элемента нужно переделать с
Обычно для анимаций рекомендуют использовать
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #web #theory
На самом деле, на производительность сайта может влиять очень много что — и CSS в том числе. Есть множество свойств, которые даются браузеру для обработки сложнее прочих: о таких свойствах как раз в этом посте
И для того, чтобы разобраться в нюансах, стоит помнить, что отрисовка контента страницы происходит в несколько этапов, таких как получение ресурсов, парсинг HTML и CSS, создание Render Tree и так далее. Более подробно можно прочитать в отличной статье на доке
Мы же сконцентрируемся на Layout и Paint фазах, их я кратко напомню:
- Layout — фаза отрисовки, в которой браузер рекурсивно проходится по заранее полученному Render Tree и рассчитывает позиции и размеры элементов относительно друг друга для их корректного расположения внутри вьюпорта
- Paint — по полученным позициям и размерам браузер рисует конкретные пиксели конкретных цветов
Также помним, что Paint без Layout не бывает, а если вызывается пересчёт Layout, то и в фазу Paint мы обязательно попадём, причём с нуля
Так вот, к чему это я: анимация любого свойства, которое так или иначе влияет на расположение элементов на странице будет вызывать Layout и Paint на каждый фрейм анимации, а сам по себе процесс отрисовки — это далеко не дёшево
Часто можно столкнуться с анимацией, когда какой-то элемент на странице (изображение, текст или ещё что-то) плавают по странице в зависимости от положения курсора. Там анимация беспрерывна, и если реализовать подобную анимацию через свойства
top
и left
, например, то фазы Layout и Paint будут крутиться каждый раз, когда вы двигаете курсором, и из-за долгих рассчётов вся анимация будет дёрганнойРешается это просто — на помощь приходит Compositing
Compositing — это способ вынести все вычисления для рендера в отдельное ядро
Страница разбивается на слои и каждый слой считается асинхронно и независимо, из-за чего изменение элемента в одном слое не затрагивает элементы из других слоёв, и перерисовывать их становится не нужно
Браузеры умеют применять это и самостоятельно, но у нас и у самих есть возможность вынести элемент на отдельный слой: использовать
transform
Анимацию плавающего элемента нужно переделать с
top
и left
на transform
, и вот почему:top
и left
триггерят Layout и Paint для всего потока, а может и всей страницы. transform
выносит элемент в отдельный поток, что уменьшает объём вычислений и делает страницу более отзывчивойТаким образом, к тяжёлым свойствам можно отнести все, что триггерят Reflow (повторный вызов Layout фазы) и Repaint:
Reflow триггерят анимации: width, height, top, left, font-size, border-width, margin, padding и так далее — все свойства, что могут влиять на расстановку элементов на странице
Repaint триггерят анимации: color, background-color, outline, visibility — все свойства, что влияют на отображение, но не на позицию элемента
Обычно для анимаций рекомендуют использовать
transform
и opacity
. Это не значит, что нельзя использовать других свойств, но эти — самые оптимизированные для браузераСпасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #web #theory
👍37❤16🐳5🔥3
Немного о __proto__ и prototype в JavaScript
В чём разница?
Если рассмотреть в коде, то получим следующее:
То есть, по факту, свойство
В примере выше, мы при помощи
Зачем всё это нужно? Для корректной работы прототипного наследования, конечно же. Рассмотрим ещё один пример кода:
Вообще, вся эта теория скорее всего не нужна рядовому разработчику. Это что-то из разряда теории ядра JavaScript, которая вроде есть, но не понятно зачем она нужна в таком приложении в реальной разработке
Если моё объяснение не очень понятно, то есть отличный видос у камасутры на эту тему, где всё разжёвано максимально понятно, советую
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #web #javascript #theory #code
__proto__
— это внутреннее свойство любого объекта или примитива в JavaScript, которое ссылается на объект, от которого он наследует свойства и методыprototype
— это свойство функций-конструкторов (или классов), которое используется для определения объектов, которые будут выступать в роли прототипов для всех экземпляров, созданных этим конструкторомВ чём разница?
__proto__
есть у каждого объекта и ссылается на прототип, из которого этот объект черпает свои свойства и методыprototype
есть только у функций-конструкторов (и классов) и используется для задания свойств и методов, которые будут доступны всем экземплярам, созданным с помощью этого конструктораЕсли рассмотреть в коде, то получим следующее:
const name = "Denis"
const surname = "Putnov"
name.__proto__ === String.prototype // true
name.prototype // undefined
name.__proto__ === surname.__proto__ // true
const age = 23
age.__proto__ === Number.prototype // true
age.prototype // undefined
То есть, по факту, свойство
__proto__
можно назвать некоторым костылём языка, благодаря которому мы можем понять с помощью чего конкретно был создан наш новый объект__proto__
всегда ссылается на какой-то прототип, на основе которого был создан новый объект В примере выше, мы при помощи
__proto__
можем увидеть, что name
в итоге создан при помощи прототипа String
Зачем всё это нужно? Для корректной работы прототипного наследования, конечно же. Рассмотрим ещё один пример кода:
const channel = {
name: "progway"
}
channel.toString()
// как же javascript'у понять, откуда взять метод?
// под капотом вызывается это вот так:
(channel.__proto__).toString()
// а мы знаем, что channel.__proto__ === Object.ptototype
// поэтому выглядеть вызов будет примерно вот так
Object.prototype.toString.call(channel)
Вообще, вся эта теория скорее всего не нужна рядовому разработчику. Это что-то из разряда теории ядра JavaScript, которая вроде есть, но не понятно зачем она нужна в таком приложении в реальной разработке
Зато вопросы о механизме прототипного наследования часто встречаются на собеседованиях, так что это может быть полезно как минимум там
Если моё объяснение не очень понятно, то есть отличный видос у камасутры на эту тему, где всё разжёвано максимально понятно, советую
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #web #javascript #theory #code
👍35🐳4🔥3❤1
Как я использую шину событий
Шина событий — это паттерн, который используется для взаимодействия различных компонентов системы не напрямую, а через некоторый посредник — саму шину
Главным преимуществом шины событий я бы назвал ослабленную связность между компонентами системы. Благодаря этому, компоненты могут взаимодействовать через события, не зная о существовании друг друга и не дожидаясь ответной реакции
Это позволяет легко расширять или изменять систему без необходимости изменения остальной части приложения, что улучшает гибкость, масштабируемость и существенно упрощяет интеграцию нового модуля
Главным минусамом я бы назвал некоторую непрозрачность: порой бывает сложно отследить куда и как протекают данные, особенно в больших приложениях, но ИМХО это относительно легко решается базовой организацией кода
Лично мне уже не раз доводилось использовать шину в проде. Нравится она мне своей простотой и тем, что позволяет легко соединять несоединяемое. В связке с реактом, можно легко избавиться от лишних ререндеров или, например, от prop-drilling'a
Также мне не нравится иметь какую-то "глобальную" шину на весь проект. Мне больше нравится создавать специфичные каналы событий, потому что это разгружает саму шину и позволяет более просто отслеживать потоки данных. В моей реализации всё решение выглядит примерно так:
Я создаю отдельный файл для инициализации канала
И далее использую экспортируемые сущности примерно так:
Конечно же, реагировать на событие в шине можно не только в компонентах: можно вообще где угодно. Для этого в
Вся "магия" тут заложена внутри функции
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #web #javascript #theory #code
Шина событий — это паттерн, который используется для взаимодействия различных компонентов системы не напрямую, а через некоторый посредник — саму шину
Шина может принимать в себя публикацию событий, а далее оповещать о произошедшем всех своих подписчиков. Такая слабая связанность позволяет сделать систему более модульной и гибкой
Главным преимуществом шины событий я бы назвал ослабленную связность между компонентами системы. Благодаря этому, компоненты могут взаимодействовать через события, не зная о существовании друг друга и не дожидаясь ответной реакции
Это позволяет легко расширять или изменять систему без необходимости изменения остальной части приложения, что улучшает гибкость, масштабируемость и существенно упрощяет интеграцию нового модуля
Также с помощью шины можно существенно улучшать перфоманс приложения, более подробно об этом сказано в отличном видео синяка
Главным минусамом я бы назвал некоторую непрозрачность: порой бывает сложно отследить куда и как протекают данные, особенно в больших приложениях, но ИМХО это относительно легко решается базовой организацией кода
Лично мне уже не раз доводилось использовать шину в проде. Нравится она мне своей простотой и тем, что позволяет легко соединять несоединяемое. В связке с реактом, можно легко избавиться от лишних ререндеров или, например, от prop-drilling'a
Также мне не нравится иметь какую-то "глобальную" шину на весь проект. Мне больше нравится создавать специфичные каналы событий, потому что это разгружает саму шину и позволяет более просто отслеживать потоки данных. В моей реализации всё решение выглядит примерно так:
Я создаю отдельный файл для инициализации канала
export const {useEvent: useSpecificEvent, ...specificEventChannel} = createEventChannel<{
event: (options: Foo) => void;
}>()
И далее использую экспортируемые сущности примерно так:
// где угодно: публикация события в шину
specificEventChannel.emit('event', options)
// в react-компоненте: реакция на событие
useSpecificEvent('event', (options) => {
...
})
Конечно же, реагировать на событие в шине можно не только в компонентах: можно вообще где угодно. Для этого в
specificEventChannel
есть дополнительные функции on
, off
и once
для подписки, отписки и единоразовой реакции соответственноВся "магия" тут заложена внутри функции
createEventChannel
. Сама по себе шина там достаточно типовая, что-то невероятное придумать сложно, однако код всё равно достаточно занятный, полный код можно найти в этом гистеСпасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #web #javascript #theory #code
❤23🐳7👍6🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
Pattern matching
Pattern matching — это крутой концепт, который позволяет делать что либо в зависимости от совпадения с тем или иным шаблоном
Самой примитивной реализацией концепта в JavaScript можно считать объекты или конструкцию
Примерно то же самое можно реализовать и со
Есть такая библиотечка — ts-pattern. Она же позволяет отойти от примитивных примеров и использовать полноценный pattern matching, включая анализ вложенных структур и более сложные условия
На главной странице библиотечки есть очень наглядная гифка. Я предлагаю посмотреть на неё повнимательнее, описывать что-то дополнительно не вижу смысла
Скажу лишь то, что мне доводилось пользоваться этой библиотечкой и, как по мне, работает она шикарно. У меня остался исключительно положительный опыт)
Сам по себе концепт невероятно полезен для упрощения кода. Такой код проще читать, изменять и поддерживать. А в совокупности с
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #web #javascript #theory #code
Pattern matching — это крутой концепт, который позволяет делать что либо в зависимости от совпадения с тем или иным шаблоном
В качестве шаблона может выступать какая-то константа или предикат
Самой примитивной реализацией концепта в JavaScript можно считать объекты или конструкцию
switch-case
:const statusIcon = {
warning: <WarningIcon />,
success: <SuccessIcon />,
error: <ErrorIcon />,
loading: <Spinner />
}
const status = "error"
const matched = statusIcon[status]
Примерно то же самое можно реализовать и со
switch-case
, но всё это не так интересноЕсть такая библиотечка — ts-pattern. Она же позволяет отойти от примитивных примеров и использовать полноценный pattern matching, включая анализ вложенных структур и более сложные условия
На главной странице библиотечки есть очень наглядная гифка. Я предлагаю посмотреть на неё повнимательнее, описывать что-то дополнительно не вижу смысла
Скажу лишь то, что мне доводилось пользоваться этой библиотечкой и, как по мне, работает она шикарно. У меня остался исключительно положительный опыт)
Сам по себе концепт невероятно полезен для упрощения кода. Такой код проще читать, изменять и поддерживать. А в совокупности с
ts-pattern
, решение будет ещё и типобезопасно, что также неоспоримый плюсСпасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #web #javascript #theory #code
🔥24👍7❤3🐳3🤔1
Порталы в React
Сталкивались когда-нибудь с проблемой, когда нужно рендерить элемент за пределами текущей DOM-иерархии?
Для таких задач React предлагает решение — порталы
В документации реакта приведён такой код:
Работает этот код проще простого: элемент, переданный в функцию
Такой код будет работать, но он не очень удобен, поэтому многие компонентные библиотеки максимально упрощают порталы для разработчиков и делают подобные компоненты — они есть в Chakra UI, Material UI, Semantic UI и других либах
Если максимально упростить, то можно прийти к такому варианту:
Тут стоит уточнить две детали:
1. Мы создаём новый
Если мы будем рендерить контент сразу в
2. В
Тоже полезно, чтобы лишний раз не задумываться о том, как живёт портал и не создавать ненужных элементов в вёрстке
Да и всё. Тут компонент на 10 строчек буквально, ничего сверхъестественного. Если вам нужны порталы, то задумайтесь — скорее всего вам хватит такой простой реализации
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #web #javascript #theory #code
Сталкивались когда-нибудь с проблемой, когда нужно рендерить элемент за пределами текущей DOM-иерархии?
Например, модальные окна, которые не должны быть вложены в основное дерево из-за проблем с позиционированием или всплывающие подсказки, которые всегда должны быть на переднем плане
Для таких задач React предлагает решение — порталы
В документации реакта приведён такой код:
import { createPortal } from 'react-dom';
<div>
<p>Текст расположен в родительском диве</p>
{createPortal(
<p>Текст расположен в document.body </p>,
document.body
)}
</div>
Работает этот код проще простого: элемент, переданный в функцию
createPortal
, будет маунтиться реактом не в родительский див, а в document.body
. Работать это будет с деревом любой вложенностиТакой код будет работать, но он не очень удобен, поэтому многие компонентные библиотеки максимально упрощают порталы для разработчиков и делают подобные компоненты — они есть в Chakra UI, Material UI, Semantic UI и других либах
Но, на самом деле, там нет ничего сложного
Если максимально упростить, то можно прийти к такому варианту:
const Portal = ({ children }: PropsWithChildren) => {
const [container] = useState(() => document.createElement('div'));
useLayoutEffect(() => {
document.body.appendChild(container);
return () => {
document.body.removeChild(container);
};
}, [container]);
return createPortal(children, container);
}
// ...
<Portal>
<p>Текст внутри портала</p>
</Portal>
Тут стоит уточнить две детали:
1. Мы создаём новый
div
внутри useState
, чтобы проще было контролировать порталЕсли мы будем рендерить контент сразу в
document.body
, то можно словить много проблем со стилями и отслеживанием самого порталаИспользуем мы именно useState, чтобы создавать элемент единожды и гарантировано на первый рендер компонента. Элемент создается внутри колбека инициализации состояния — он всегда вызывается единожды на маунт компонента
Как альтернатива, можно обойтись и рефом
2. В
useLayoutEffect
мы привязываем жизненный цикл тега-обёртки к циклу компонента порталаТоже полезно, чтобы лишний раз не задумываться о том, как живёт портал и не создавать ненужных элементов в вёрстке
useLayoutEffect используется вместо useEffect, чтобы обрабатывать портал без лишних мерцаний и более плавно
Вообще, тема разных эффектов и где какой использовать — это отдельная крупная тема, возможно сделаю об этом пост в будущем
Да и всё. Тут компонент на 10 строчек буквально, ничего сверхъестественного. Если вам нужны порталы, то задумайтесь — скорее всего вам хватит такой простой реализации
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #web #javascript #theory #code
❤21👍11🐳3🔥1👏1