Вот правда, дизайн Server Push ставил в тупик с первого дня, однако дотащили же до прода. Зачем, кто это форсил — непонятно.
https://news.1rj.ru/str/daily_geek_news/197
https://news.1rj.ru/str/daily_geek_news/197
Telegram
Daily Geek News
Начиная с хрома версии 106 в браузере будет выключен HTTP/2 server push, который продавали как важную причину для перехода на новую версию HTTP. При этом, конечно, ни браузеры ни серверы толком не поддерживали нормально эту идею, мы с Умпутуном ещё тогда…
По поводу того, как же мы будем жить без
Что тут важно: если вы можете ответить быстро, то ничего городить не нужно. Присылайте
Upd
Когда написал пост, внезапно осознал ещё один важный кейс: edge-прокси. Собственно, для чего Cloudflare одними из первых и внедрили экспериментальную поддержку. Работает это так, что на проксирующем сервере, расположенном близко к клиенту, доклеивается заголовок
Server Push (словно кто-то с ним жил, ха). Начиная с Chrome 103 (и только Chrome) на всех пользователей раскатали поддержку стандарта 103 Early Hints который заключается в такой простой идее: если ваш сервер очень тугодумный и не может мгновенно выплюнуть на запрос ответ 200 с HTML, то вы можете использовать время ожидания с пользой, ответить сначала статусом 103, в тело положить Link со ссылками на важные ресурсы, браузер побежит их качать, а тут и 200 долетит с основным телом ответа.
HTTP/1.1 103 Early Hints
Link: </style.css>; rel="preload"; as="style"
Link: <https://cdn.test>; rel="preconnect"
HTTP/1.1 200 OK
Link: </style.css>; rel="preload"; as="style"
Link: <https://cdn.test>; rel="preconnect"
Content-Type: text/html; charset=utf-8
<!DOCTYPE html>
...
Что тут важно: если вы можете ответить быстро, то ничего городить не нужно. Присылайте
200 и на важные ресурсы пропишите link rel=preload и link rel=preconnect. Браузер сам решит, как дальше оптимизировать загрузку. Т.е. Early Hints это такой костылик для случаев когда у вас удивительно медленный серверный рендер и за время тугодумия сервера браузер может что-то полезное скачать.Upd
Когда написал пост, внезапно осознал ещё один важный кейс: edge-прокси. Собственно, для чего Cloudflare одними из первых и внедрили экспериментальную поддержку. Работает это так, что на проксирующем сервере, расположенном близко к клиенту, доклеивается заголовок
103, выплёвывается ответ, а дальше запрос бежит на ваш далеко расположенный сервер.
👍12❤1
Где бы монорепа точно пригодилась
В webpack module federation есть такая штука как shared dependencies. Мы указываем в головном приложении, что у нас есть один экземпляр
Вот как-то так
Теперь каждый подключаемый модуль не будет тащить свою версию реакта, а использовать общую. Красиво, но есть проблема обновлений зависимостей.
Во-первых, само по себе обновление может стать болезненным, если в мажоре библиотеки сломают API (привет react-router) так, что старый код не сможет работать с новым API. Т.е. ставим условный react 19 и наш подключаемый модуль ломается, нам нужно переписать и релизнуть новые версии микрофронтов максимально быстро вслед за хостом (что для многих проектов просто недопустимо).
Во-вторых, весьма болезненно ходить по полирепе, останавливать релизы, вносить правки в зависимости и код каждого отдельного микрофронта, а после массово релизить.
В монорепозитории очевидно можно протащить это за один PR.
В webpack module federation есть такая штука как shared dependencies. Мы указываем в головном приложении, что у нас есть один экземпляр
react, один
react-dom, один
react-router-domи что эти синглтоны шарятся между всеми модулями.
Вот как-то так
new ModuleFederationPlugin({
name: 'host',
shared: {
react: { singleton: true, requiredVersion: dependencies.react, eager: true },
'react-dom': { singleton: true, requiredVersion: dependencies['react-dom'], eager: true },
'react-router-dom': {
singleton: true,
requiredVersion: dependencies['react-router-dom'],
eager: true,
}
},
Теперь каждый подключаемый модуль не будет тащить свою версию реакта, а использовать общую. Красиво, но есть проблема обновлений зависимостей.
Во-первых, само по себе обновление может стать болезненным, если в мажоре библиотеки сломают API (привет react-router) так, что старый код не сможет работать с новым API. Т.е. ставим условный react 19 и наш подключаемый модуль ломается, нам нужно переписать и релизнуть новые версии микрофронтов максимально быстро вслед за хостом (что для многих проектов просто недопустимо).
Во-вторых, весьма болезненно ходить по полирепе, останавливать релизы, вносить правки в зависимости и код каждого отдельного микрофронта, а после массово релизить.
В монорепозитории очевидно можно протащить это за один PR.
🤔3👍2
Где монорепа в целом бесполезна
Иногда возникает желание сложить микрофронт и BFF для него в одну монорепу фронт-бек. Кажется, что решение убийственно хорошо: разработчик скачивавает один репозиторий и одним скриптом стартует фронт и бэк. Но главной киллер-фичей кажется тут то, что можно переиспользовать тайпскриптовые типы как контракты. Поменял типы ответа на бэке — фронт тут же загорелся красным. Идеально!
Но мы забыли про деплой. Да, релизится такая монорепа одним скриптом, который катит бэк на сервера бэкенда, а фронт на фронтовые сервера (Next, или просто статика в S3, не важно). И вот тут в момент деплоя возникает рассинхрон. То, что там казалось монолитной сущностью во время разработки, оказывается не монолитом в проде. Пользователь заходит на обновлённый фронт, а бэк ещё не готов и отвечает ошибкой. Или наоборот, старый фронт стучится в новый бэк.
Что тут можно сделать? Ну, например, закрывать серверы парами и делать стики-сессии. Но если на канареечном сервере это приемлимо, то в бою стики это странно. Мы хотим распределять нагрузку, раскидывая запросы на разные бэки, а не делать вечные пары фронт-бек. Другая проблема, что пользователь может не обновить фронт в браузере, а бэк уже обновился. Тут и стики не помогут.
Вывод — монорепа здесь даёт ложную надежду на синхронность фронта и бэка. А вот лежал бы код в разных репозиториях, мы бы вынуждены были вынести контракты в третий репозиторий и шарить их уже по настоящему. А тут бы и версионирование API подъехало.
Итого, с моей точки зрения, для разнородных сущностей монорепа малополезна. Можно сложить в монорепу бэкенды. Можно отдельно сложить в другую монорепу фронтенды. В отдельный репозиторий положить контракты. В четвёртый и пятый репозитории лягут iOS и Android-фронты. Для UI-компонентов тоже можно завести свою монорепу. Сложить туда и компоненты и атомы дизайн-системы и что ещё пригодится. Но упаси вас господь паблишить компоненты UI-кита как отдельные пакеты, это дорога в ад.
Иногда возникает желание сложить микрофронт и BFF для него в одну монорепу фронт-бек. Кажется, что решение убийственно хорошо: разработчик скачивавает один репозиторий и одним скриптом стартует фронт и бэк. Но главной киллер-фичей кажется тут то, что можно переиспользовать тайпскриптовые типы как контракты. Поменял типы ответа на бэке — фронт тут же загорелся красным. Идеально!
Но мы забыли про деплой. Да, релизится такая монорепа одним скриптом, который катит бэк на сервера бэкенда, а фронт на фронтовые сервера (Next, или просто статика в S3, не важно). И вот тут в момент деплоя возникает рассинхрон. То, что там казалось монолитной сущностью во время разработки, оказывается не монолитом в проде. Пользователь заходит на обновлённый фронт, а бэк ещё не готов и отвечает ошибкой. Или наоборот, старый фронт стучится в новый бэк.
Что тут можно сделать? Ну, например, закрывать серверы парами и делать стики-сессии. Но если на канареечном сервере это приемлимо, то в бою стики это странно. Мы хотим распределять нагрузку, раскидывая запросы на разные бэки, а не делать вечные пары фронт-бек. Другая проблема, что пользователь может не обновить фронт в браузере, а бэк уже обновился. Тут и стики не помогут.
Вывод — монорепа здесь даёт ложную надежду на синхронность фронта и бэка. А вот лежал бы код в разных репозиториях, мы бы вынуждены были вынести контракты в третий репозиторий и шарить их уже по настоящему. А тут бы и версионирование API подъехало.
Итого, с моей точки зрения, для разнородных сущностей монорепа малополезна. Можно сложить в монорепу бэкенды. Можно отдельно сложить в другую монорепу фронтенды. В отдельный репозиторий положить контракты. В четвёртый и пятый репозитории лягут iOS и Android-фронты. Для UI-компонентов тоже можно завести свою монорепу. Сложить туда и компоненты и атомы дизайн-системы и что ещё пригодится. Но упаси вас господь паблишить компоненты UI-кита как отдельные пакеты, это дорога в ад.
❤7👍4🤔1
В предыдущем посте затронул тему ui-kit. Не раз встречал желение прикрутить к киту условную Лерну и паблишить компоненты как отдельные сущности. Мотивация понятная — мало кто хочет поднимать UI-kit во всём приложении, когда дизайнер принёс страничку с новым элементом. Гораздо проще было бы поставить непосредственно этот элемент (или обновить существующий). Однако, в проектах, где такой подход принят, я вижу сильную неоднородность фронта: на одной странице можно встретить 3-4 разные итерации развития кнопки. Что-то доехало из корня, что-то транзитивно из более сложных сущностей. В итоге, пользователь недоумевает почему дизайн такой лоскутный (тут кнопка круглая, а тут квадратная, тут галочки синие, а тут зелёные, а тут вообще градиент с тенями вылез), а бандл раздут излишними копиями одной и той же сущности разных мажорных и минорных её версий.
Да, обновлять kit во всём приложении сразу сложнее, но делать это необходимо и делать это нужно регулярно, чтобы не столкнуться с ситуацией, когда ради нового аттрибута кнопки нужно прыгнуть через три мажора. А такое я тоже встречал.
Да, обновлять kit во всём приложении сразу сложнее, но делать это необходимо и делать это нужно регулярно, чтобы не столкнуться с ситуацией, когда ради нового аттрибута кнопки нужно прыгнуть через три мажора. А такое я тоже встречал.
🔥7👍4
В воскресенье что-то будет
https://news.1rj.ru/str/backend_megdu_skobkah/7823
https://news.1rj.ru/str/backend_megdu_skobkah/7823
Telegram
{ между скобок } анонсы 📣 in { между скобок }
Всем привет 👋 Хочется напомнить, что сегодня в 19:00 по мск встречаемся в zoom на публичном собеседование по LeetCode. Так же хочется рассказать, что у нас будет в воскресенье.
🗓 28 августа, вс, 20:00 (мск) “CHAPTER 9: Design a web crawler” System Design…
🗓 28 августа, вс, 20:00 (мск) “CHAPTER 9: Design a web crawler” System Design…
🔥5❤3
Неделю назад жаловался на отсутствие иммутабельных структур в JS, а тут вдруг всплыл интересный пропозал по добавленю в JS иммутабельных Record и Tuple (кортежей).
Если кратко, то предлагается добавить в язык два новых «сложных» иммутабельных примитива, собственно
Описываются они так
Мутировать их нельзя, внутри могут лежать только примитивы, никаких ссылок на объекты и функции (но над этим работают, возможно ссылки разрешат). Так как это примитивы, то сравниваются они по значению, а не по ссылкам
Ещё раз — это примитивы
Так как кортежи выглядят как массивы, то очень хотелось бы к ним применять методы из Array.prototype, но проблема в том, что многие методы там мутирующие. Так что вместе с этим пропозалом едет второй пропозал с добавлением иммутабельных методов в Array и TypedArray
И он уже на Stage 3 и приедет к нам прежду всего с новым Safari
Ну и вдогонку доклад https://portal.gitnation.org/contents/record-and-tuple-immutable-data-structures-in-js
Если кратко, то предлагается добавить в язык два новых «сложных» иммутабельных примитива, собственно
Record и Tuple. Описываются они так
const record = #{ a: 1, b: 2 }
const tuple = #[1, 2]Мутировать их нельзя, внутри могут лежать только примитивы, никаких ссылок на объекты и функции (но над этим работают, возможно ссылки разрешат). Так как это примитивы, то сравниваются они по значению, а не по ссылкам
const record1 = #{ a: 1, b: 2 }
const record2 = #{ a: 1, b: 2 }
const record3 = #{ ...record1 }
const record4 = #{ b: 2, a: 1 }
record1 === record2 // true
record1 === record3 // true
record1 === record4 // true ключи сортируются лексическиЕщё раз — это примитивы
typeof #{ a: 1 } === "record"
typeof #[1, 2,3] === "tuple"Так как кортежи выглядят как массивы, то очень хотелось бы к ним применять методы из Array.prototype, но проблема в том, что многие методы там мутирующие. Так что вместе с этим пропозалом едет второй пропозал с добавлением иммутабельных методов в Array и TypedArray
• Array.prototype.toReversed() -> Array
• Array.prototype.toSorted(compareFn) -> Array
• Array.prototype.toSpliced(start, deleteCount, ...items) -> Array
• Array.prototype.with(index, value) -> ArrayИ он уже на Stage 3 и приедет к нам прежду всего с новым Safari
Ну и вдогонку доклад https://portal.gitnation.org/contents/record-and-tuple-immutable-data-structures-in-js
GitHub
GitHub - tc39/proposal-record-tuple: ECMAScript proposal for the Record and Tuple value types. | Stage 2: it will change!
ECMAScript proposal for the Record and Tuple value types. | Stage 2: it will change! - tc39/proposal-record-tuple
❤24🔥9🥰4👍3
Монументальный труд Виктора Хомякова про работу с памятью в JS. Утечки, оптимизации, отличия ноды и браузеров.
https://habr.com/ru/company/yandex/blog/666870/
https://habr.com/ru/company/yandex/blog/666870/
Хабр
Память в браузерах и в Node.js: ограничения, утечки и нестандартные оптимизации
Интро: почему я написал эту статью Меня зовут Виктор, я разрабатываю страницу результатов поиска Яндекса. Несмотря на внешнюю простоту, поисковая выдача — сложная штука: на каждый запрос генерируется...
👍24🔥8
Forwarded from artalog (artalar)
Давно жду этот пропосал и одно из самых интересных нововведений там это доп синтаксис для иммутабельного изменения глубоколежащего свойства.
👍10❤1
Как устроена локализация в крупных проектах
В маленьких проектах всё просто — пишем все тексты в интерфейсах на одном языке и в ус не дуем. Если же проект вырастает и начинает экспансию, то вместе с ней приходит боль. Все тексты нужно заменять на ключи, выносить в файлики и базы данных (такой кортеж из ключа и набора переводов на разные языки) и заменять ключ на перевод по выбору пользователя.
Если говорить о фронтенде, то тут сразу отпадает вариант с динамической подстановкой текстов из загруженной в бандл бд — наборы переводов для всех языков просто раздуют бандл. Это значит, что нам нужно подготовить переведённые бандлы в момент сборки, чтобы пользователь грузил только те тексты, которые нужны в его выбранной локали. А есть же ещё RTL-языки, ох.
Это всё решаемо и это только полбеды.
Вторая половина беды состоит в том, что процесс перевода человеком — это синхронный процесс. В крупном проекте не можете выкатить релиз не переведя его на хотя бы базовый набор языков. Особенно, если ваш основной язык не международный. Фоллбечить немецкий в русский это просто смешно 🙂 Значит, вам нужно чтобы к релизу были готовы два языка — локальный + английский. Очевидно, что за переводы не должен отвечать разработчик или дизайнер, для этого есть ребята, прокачанные в мультиязычном написании текстов.
Для работы с переводчиками используют так называемые translation management systems которые в чём-то похожи на content managment systems. Это специальный UI, где переводчики видят какие свежие ключи приехали, как они лежат в контексте (неплохо, когда вместе с ключами едет подсказка их применения), переводят и аппрувят их.
Процесс выглядит примерно так
1. Разработчик расставляет в коде интерфейса ключи, а не тексты. Рядом заводит файлик, в котором описывает связки ключ -> { дефолтный текст, множестенные формы, подсказки переводчику }
2. В момент билда все ключи загружаются в TMS, находятся изменения и переводчик получает задачу на переводы
3. Билд стоит в ожидании перевода на базовый минимум языков
4. Переводчик в интерфейсе TMS делает свою работу и жмёт аппрув
5. По готовности переводов CI выкачивает их и собирает локализованные бандлы, билд едет на прод. Что не перевели — фоллбечится в английский (скорее всего). Остатки доедут в следующий релиз.
Тут конечно большой минус, что бутылочным горлышком становится переводчик. Потому дальше можно придумать различные варианты ускорения работы, например, что переводчик получает задачу уже в момент тестирования ветки QA и при релизе ветка переводов мерджится в main. Т.е. одна задача не должна блочить своими переводами весь релизный процесс, только себя.
Для примера TMS систем рекомендую посмотреть на Weblate
В маленьких проектах всё просто — пишем все тексты в интерфейсах на одном языке и в ус не дуем. Если же проект вырастает и начинает экспансию, то вместе с ней приходит боль. Все тексты нужно заменять на ключи, выносить в файлики и базы данных (такой кортеж из ключа и набора переводов на разные языки) и заменять ключ на перевод по выбору пользователя.
Если говорить о фронтенде, то тут сразу отпадает вариант с динамической подстановкой текстов из загруженной в бандл бд — наборы переводов для всех языков просто раздуют бандл. Это значит, что нам нужно подготовить переведённые бандлы в момент сборки, чтобы пользователь грузил только те тексты, которые нужны в его выбранной локали. А есть же ещё RTL-языки, ох.
Это всё решаемо и это только полбеды.
Вторая половина беды состоит в том, что процесс перевода человеком — это синхронный процесс. В крупном проекте не можете выкатить релиз не переведя его на хотя бы базовый набор языков. Особенно, если ваш основной язык не международный. Фоллбечить немецкий в русский это просто смешно 🙂 Значит, вам нужно чтобы к релизу были готовы два языка — локальный + английский. Очевидно, что за переводы не должен отвечать разработчик или дизайнер, для этого есть ребята, прокачанные в мультиязычном написании текстов.
Для работы с переводчиками используют так называемые translation management systems которые в чём-то похожи на content managment systems. Это специальный UI, где переводчики видят какие свежие ключи приехали, как они лежат в контексте (неплохо, когда вместе с ключами едет подсказка их применения), переводят и аппрувят их.
Процесс выглядит примерно так
1. Разработчик расставляет в коде интерфейса ключи, а не тексты. Рядом заводит файлик, в котором описывает связки ключ -> { дефолтный текст, множестенные формы, подсказки переводчику }
2. В момент билда все ключи загружаются в TMS, находятся изменения и переводчик получает задачу на переводы
3. Билд стоит в ожидании перевода на базовый минимум языков
4. Переводчик в интерфейсе TMS делает свою работу и жмёт аппрув
5. По готовности переводов CI выкачивает их и собирает локализованные бандлы, билд едет на прод. Что не перевели — фоллбечится в английский (скорее всего). Остатки доедут в следующий релиз.
Тут конечно большой минус, что бутылочным горлышком становится переводчик. Потому дальше можно придумать различные варианты ускорения работы, например, что переводчик получает задачу уже в момент тестирования ветки QA и при релизе ветка переводов мерджится в main. Т.е. одна задача не должна блочить своими переводами весь релизный процесс, только себя.
Для примера TMS систем рекомендую посмотреть на Weblate
👍17🔥7
Божечки кошечки (спасибо @dskrylnikov за наводку)
https://github.com/microsoft/TypeScript/issues/50457
https://github.com/microsoft/TypeScript/issues/50457
🔥10🐳3
Увидел тут в комментах, что не всем понятно, про какие edge-лямбды иногда я говорю. Ок, погнали.
Лямбды можно условно разделить на два вида:
1 Классические лямбды, о которых обычно и говорят. Призваны заменить «обычный» бэкенд, запускаются в тех же датацентрах, где расположены виртуалки, базы данных и т.д. Стоят дороже, умеют больше.
2 Edge-лямбды. Расположены на серверах CDN, их задача быть как можно ближе к пользователю. Стоят дешевле, умеют меньше (зато как быстро!), функциональность наращивается с помощью богатого API от провайдера.
Иначе говоря, после того как люди вытащили статику на CDN и научились отдавать её максимально быстро, стало очень обидно, что иногда прежде чем отдать статику, надо сначала медленно сходить на сервер и что-то мелкое там посчитать/проверить. И тут возникла идея поставить такие маленькие миддлварки перед статикой. Причём сделать это максимально дёшево.
Не сказать, что идея совсем новая, например, популярное решение вытащить часть логики в nginx чтобы она даже не долетала до ноды. Можно вот по наличию определённой куки или заголовка раздавать разный контент (такое вот A/B). Или вернуть редирект. Или проверить авторизацию. А теперь всю эту логику можно положить в JS-код и закинуть в edge-лямбду.
Что можно ещё сделать? Можно запилить прокси, которое будет отдавать браузеру данные с другого бэка, в который иначе не достучаться из-за CORS-политик. Можно сделать умный кэш (Cloudflare даёт доступ к Cache API и даже к Key/Value хранилищу).
Можно ли целиком построить простое приложение на edge-лямбдах и статике используя различные облачные API в качестве бэкенда? Думаю да, возможностей куча. Но это, конечно, не полноценное приложение на node.js, в отличие от классической лямбды. Вот Cloudflare Workers хороший пример — крутятся на V8 с минимальной обвязкой, а для ускорения запуска и удешевления эксплуатации создают пользовательские контексты в V8 изолятах.
Круто, конечно, вот только это совсем уж вендор-лок.
Лямбды можно условно разделить на два вида:
1 Классические лямбды, о которых обычно и говорят. Призваны заменить «обычный» бэкенд, запускаются в тех же датацентрах, где расположены виртуалки, базы данных и т.д. Стоят дороже, умеют больше.
2 Edge-лямбды. Расположены на серверах CDN, их задача быть как можно ближе к пользователю. Стоят дешевле, умеют меньше (зато как быстро!), функциональность наращивается с помощью богатого API от провайдера.
Иначе говоря, после того как люди вытащили статику на CDN и научились отдавать её максимально быстро, стало очень обидно, что иногда прежде чем отдать статику, надо сначала медленно сходить на сервер и что-то мелкое там посчитать/проверить. И тут возникла идея поставить такие маленькие миддлварки перед статикой. Причём сделать это максимально дёшево.
Не сказать, что идея совсем новая, например, популярное решение вытащить часть логики в nginx чтобы она даже не долетала до ноды. Можно вот по наличию определённой куки или заголовка раздавать разный контент (такое вот A/B). Или вернуть редирект. Или проверить авторизацию. А теперь всю эту логику можно положить в JS-код и закинуть в edge-лямбду.
Что можно ещё сделать? Можно запилить прокси, которое будет отдавать браузеру данные с другого бэка, в который иначе не достучаться из-за CORS-политик. Можно сделать умный кэш (Cloudflare даёт доступ к Cache API и даже к Key/Value хранилищу).
Можно ли целиком построить простое приложение на edge-лямбдах и статике используя различные облачные API в качестве бэкенда? Думаю да, возможностей куча. Но это, конечно, не полноценное приложение на node.js, в отличие от классической лямбды. Вот Cloudflare Workers хороший пример — крутятся на V8 с минимальной обвязкой, а для ускорения запуска и удешевления эксплуатации создают пользовательские контексты в V8 изолятах.
Круто, конечно, вот только это совсем уж вендор-лок.
🔥6👍3
На примере предыдущего поста вы можете убедится, что некоторые фуллстеки действительно мифические. Пока ты копаешь в одну сторону, в другой стороне происходит много чего интересного. Вот несмотря на годы в JS, я для себя только-только открываю чудесный мир современных фронтенд-фреймворков. Могу накидать что-то на Реакте правильно работающее, но глубины в знаниях нет совершенно.
С другой стороны, я всё же уже способен удивляться, увидев код, обмазанный в три слоя useCallback и useMemo.
С другой стороны, я всё же уже способен удивляться, увидев код, обмазанный в три слоя useCallback и useMemo.
😁14👍4
Провёл лекцию по технике для онлайн-выступлений. Вот вам саммари
Минимальный уровень (вас слышно)
Либо любой usb-микрофон + любые комфортные наушники
Хороший уровень (вы лучше многих онлайн-спикеров)
Второй монитор
Кликер
Динамический USB-микрофон (samson q2u, Audio-Technica atr2100x, Shure MV7)
Веб-камера 4k (Logitech Brio) либо Full HD (Logitech StreamCam)
Вместе с MacOS Ventura неплохой вариант использовать вместо веб-камеры iPhone
Светодиодный свет (например, кольцевой)
Мега супер пупер (вы великолепны)
Зеркальная или беззеркальная камера через карту захвата (Elgato CamLink)
Питание для камеры (никаких батареек!)
Два светодиодных источника света под 45 градусов каждый (Elgato Key Light)
Цветной LED-источник подкрасить комнату за спиной (Boling BL-P1)
Динамический XLR микрофон (любой, подбирается по личным хотелкам) + интерфейс (Rode AL-1)
Что мы не используем
Airpods и любые другие bluetooth-наушники в качестве микрофонов
Дорогие конденсаторные USB микрофоны, например Blue Yeti
Минимальный уровень (вас слышно)
Проводные наушники с микрофоном на кабелеЛибо любой usb-микрофон + любые комфортные наушники
Хороший уровень (вы лучше многих онлайн-спикеров)
Второй монитор
Кликер
Динамический USB-микрофон (samson q2u, Audio-Technica atr2100x, Shure MV7)
Веб-камера 4k (Logitech Brio) либо Full HD (Logitech StreamCam)
Вместе с MacOS Ventura неплохой вариант использовать вместо веб-камеры iPhone
Светодиодный свет (например, кольцевой)
Мега супер пупер (вы великолепны)
Зеркальная или беззеркальная камера через карту захвата (Elgato CamLink)
Питание для камеры (никаких батареек!)
Два светодиодных источника света под 45 градусов каждый (Elgato Key Light)
Цветной LED-источник подкрасить комнату за спиной (Boling BL-P1)
Динамический XLR микрофон (любой, подбирается по личным хотелкам) + интерфейс (Rode AL-1)
Что мы не используем
Airpods и любые другие bluetooth-наушники в качестве микрофонов
Дорогие конденсаторные USB микрофоны, например Blue Yeti
👍21❤6
А прямо до меня читал лекцию Саша Крайнов, и он дал один важный совет для спикеров, про который я раньше не задумывался специально, но подсознательно пришёл такому на последнем ЯЛФ (отмотав слайды назад).
Не ставьте на последний слайд «Спасибо», «Вопросы?», или свои контакты с QR-кодом. Поставьте вместо этого выжимку главных идей и пусть она висит, пока вы отвечаете на вопросы.
Не ставьте на последний слайд «Спасибо», «Вопросы?», или свои контакты с QR-кодом. Поставьте вместо этого выжимку главных идей и пусть она висит, пока вы отвечаете на вопросы.
👍41
Не забываем правило — поставил пресет eslint от AirBnB, допиши в rules
https://news.1rj.ru/str/msosnovfeed/412
'import/prefer-default-export': 'off',
'import/no-default-export': 'error'https://news.1rj.ru/str/msosnovfeed/412
Telegram
Dev News от Максима Соснова
Default Exports in JavaScript Modules Are Terrible
Ещё одна статья, в которой рассказывается, почему не стоит использовать export default.
В кратце:
- Автокомплит не подсказывает, что у модуля есть export default, если вы начали делать импорт через { }…
Ещё одна статья, в которой рассказывается, почему не стоит использовать export default.
В кратце:
- Автокомплит не подсказывает, что у модуля есть export default, если вы начали делать импорт через { }…
👍26