На выходных обновил персональную страницу.
Во-первых, недавно я купил домен egor.sh. Да, 16к рублей на reg.ru в год и 83$ - 30% по нагугленной скидке за 5 минут на godaddy за 2 года.
Во-вторых, обновил основной фреймворк
В новой версии завезли
Из коробки доступна оптимизация изображений,
Ну и вишенка на торте это облачный сервис от создателей фреймворка -
В общем, да, я в восторге от того как фреймворк и сервис развивается.
Ну и по-мелочи еще перевел стили на
Посмотреть вживую egor.sh или в коде https://github.com/egorshar/homepage
Во-первых, недавно я купил домен egor.sh. Да, 16к рублей на reg.ru в год и 83$ - 30% по нагугленной скидке за 5 минут на godaddy за 2 года.
Во-вторых, обновил основной фреймворк
nextjs до 13 версии. Мне всегда он нравился как с точки зрения DX, так и фокуса на производительности работы. Вам не нужно ковыряться в конфигах, чтобы все само собиралось как в прод, так и в дев с оптимальными настройками.В новой версии завезли
React Server Components, по-моему первые из всех разработчиков фреймворков. Новую файловую структуру, мидлвэры для модификации запроса до того как он будет обработан. Например, у меня из запроса получается заголовок Accept-Language и по нему показывается английская версия, если предпочтительный язык браузера пользователя не русский.Из коробки доступна оптимизация изображений,
nextjs за вас сожмет картинку на лету и пользователь загрузит ее в минимальном обьеме для его устройства.Ну и вишенка на торте это облачный сервис от создателей фреймворка -
Vercel. Во-первых, интеграция с гитхабом через OAuth и все, что нужно потом сделать для деплоя приложения это пуш в мастер. Так же доступны тестовые стенды, env-переменные и все-все-все, что необходимо нормальному сервису. Во-вторых, сам фреймворк отлично интегрирован в эту систему и сжатие изображений, про которое я говорил выше, кеширует результаты на их же CDN. Так же в CDN можно закешировать результаты работы API-запросов, если требуется, и делается это минимальным количеством телодвижений в коде.В общем, да, я в восторге от того как фреймворк и сервис развивается.
Ну и по-мелочи еще перевел стили на
tailwindcss с поддержкой темной темы, попробовал в 3d с react-three-fiber (текстура для шара там мегабайт весит, поэтому грузится долго - пока было лень придумывать что-то с заглушкой, а с пол тычка не получилось).Посмотреть вживую egor.sh или в коде https://github.com/egorshar/homepage
👍6
Tinkoff оказывается "пробует" в open-source, наткнулся на их github-аккаунт.
Прикольно, что описывают какие-то части внутренней кухни и инфу для подготовки к интервью, про то, как происходит рост сотрудника внутри компании (понятно, что вряд ли это реально так работает, но для hr-стратегии бренда такие статьи полезны и это скорее надо взять на вооружение, если есть потребность в найме готовых разработчиков). В целом на самом деле, по части социальной активности на тему разработки у них все красиво, тут не о чем спорить.
Забавно другое, это, собственно, их тот самый open-source. Бегло глянув репы, выглядит это как сборничек своих велосипедов, зачем-то вынесенный в паблик. Похоже, что основа кодовой базы или когда-то была, или до сих пор написана на
Прикольно, что описывают какие-то части внутренней кухни и инфу для подготовки к интервью, про то, как происходит рост сотрудника внутри компании (понятно, что вряд ли это реально так работает, но для hr-стратегии бренда такие статьи полезны и это скорее надо взять на вооружение, если есть потребность в найме готовых разработчиков). В целом на самом деле, по части социальной активности на тему разработки у них все красиво, тут не о чем спорить.
Забавно другое, это, собственно, их тот самый open-source. Бегло глянув репы, выглядит это как сборничек своих велосипедов, зачем-то вынесенный в паблик. Похоже, что основа кодовой базы или когда-то была, или до сих пор написана на
Angular и решения оттуда так близки команде, что они пытаются перетащить их на рельсы других библиотек, это я про tramvai.Или набор утилит
Самый главный минус всех этих велосипедных библиотек, что, во-первых, на старте вместо того чтобы разработчик уже имел опыт работы с тем же
Выше у меня был пост про самое начало amoCRM и выбор в пользу
utils.js с обязательным бенчмарком, что оно быстрее и тоньше lodash, только самым первым почему то сравнивается импорт полной библиотеки lodash, но это ладно, так положено во всех бенчмарках, лол.Самый главный минус всех этих велосипедных библиотек, что, во-первых, на старте вместо того чтобы разработчик уже имел опыт работы с тем же
lodash - ему придется разобраться с синтаксисом вашего велосипеда и хорошо если есть документация. Ну и, во-вторых, (хоть нас как команду это и меньше интересует) это не дает плюсов самому разработчику - опыт работы с вашим велосипедом не будет котироваться на рынке в дальнейшем.Выше у меня был пост про самое начало amoCRM и выбор в пользу
requirejs вместо своего модульного загрузчика (это вопрос 2014 года, если что), вот с тех пор я стараюсь по-максимуму использовать готовые решения вместо своих велосипедов, а уж тем более если они признаны сообществом как стандарты.Хороший пример организации большого и сложного приложения на
nextjs 13 (написано на typescript). Причем это не стартер, а прям прилага, которую можно изучать как пример того, как выглядит современное веб-приложение с использованием данного фреймворка. Тут и новый роутинг, и серверные компоненты, и остальные новые фичи. Ну и темная тема в комплекте, конечно 🫡GitHub
GitHub - shadcn-ui/taxonomy: An open source application built using the new router, server components and everything new in Next.js…
An open source application built using the new router, server components and everything new in Next.js 13. - shadcn-ui/taxonomy
Million.js
Бывают моменты, когда важна производительность. И нет, это не те моменты, когда на ревью ты видишь какую-нибудь работу с плейн-объектами с экономией на спичках, а потом человек обращения к DOM-дереву не кеширует.
Когда-то в мир пришел React и все начали повторять как мантру, что он очень быстрый из-за своего механизма virtual-DOM. Кто-то может даже слышал мем
Если коротко, то virtual-DOM это всегда оверхед, потому что для синхронизации состояния приложения с реальным DOM-ом (так называемой “реконсиляции”) будет всегда происходить дополнительная работа браузера.
И вот тут на сцену в белом выходит Million.js (если что у них на сайте прикольная демка, можете поиграться).
Суть его работы в статическом анализе, с помощью которого динамические части виртуального DOM выделяются в некую мапу
Подытожим, либа не является каким-то общим решением всех бед производительности. Если эти проблемы у вас появились, то начните с профилирования приложения, нет ли лишних ререндеров (если в контексте реакта, начните с wdyr). Нет ли долгих синхронных операций, которые блокируют main-тред. И только если вы точно локализовали проблему и она действительно находится в конкретном месте, которое поддается такому пути решения, то используйте. Тем более вес самой библиотеки меньше 4KB.
Бывают моменты, когда важна производительность. И нет, это не те моменты, когда на ревью ты видишь какую-нибудь работу с плейн-объектами с экономией на спичках, а потом человек обращения к DOM-дереву не кеширует.
Когда-то в мир пришел React и все начали повторять как мантру, что он очень быстрый из-за своего механизма virtual-DOM. Кто-то может даже слышал мем
'the virtual DOM is fast', often said to mean that it's faster than the *real* DOM. Пошло это с конфы 2013 года с кор разрабом React, который это сказал. Правда потом он поправился в духе, что “вы можете написать что-то на ассемблере и превзойти компилятор C, так же как вы можете руками манипулировать с DOM и сделать что-то быстрее, чем React, но с React вы можете разрабатывать не задумываясь о производительности, а приложение будет по умолчанию быстрым”. Если хотите почитайте первоисточник из блога svelte.Если коротко, то virtual-DOM это всегда оверхед, потому что для синхронизации состояния приложения с реальным DOM-ом (так называемой “реконсиляции”) будет всегда происходить дополнительная работа браузера.
И вот тут на сцену в белом выходит Million.js (если что у них на сайте прикольная демка, можете поиграться).
Суть его работы в статическом анализе, с помощью которого динамические части виртуального DOM выделяются в некую мапу
EditMap, в этой мапе грубо говоря хранятся инструкции для редактирования реального DOM-дерева и при изменении состояния компонента реальный DOM обновляется напрямую через этот EditMap. Однако, хоть они и заявляют, что “just wrap your React components” - у всего на свете есть своя цена. Поэтому есть куча ограничений, например, нельзя в conditional return или вывод дочернего JSX. Вот например, что нельзя из доки (а мы ведь это все часто используем):function IllegalComponent({ name, initial }) { const [count, setCount] = useState(initial.count); const greeting = `Hello ${name}!`; if (count > 10) { return <div>Too many clicks!</div>; // ❌ don't use conditionals } return ( <div> {greeting} <button onClick={() => setCount(count + 1)}> {<div>{count}</div> /* ❌ don't pass JSX */} </button> </div> );}Подытожим, либа не является каким-то общим решением всех бед производительности. Если эти проблемы у вас появились, то начните с профилирования приложения, нет ли лишних ререндеров (если в контексте реакта, начните с wdyr). Нет ли долгих синхронных операций, которые блокируют main-тред. И только если вы точно локализовали проблему и она действительно находится в конкретном месте, которое поддается такому пути решения, то используйте. Тем более вес самой библиотеки меньше 4KB.
GitHub
GitHub - aidenybai/million: Optimizing compiler for React
Optimizing compiler for React. Contribute to aidenybai/million development by creating an account on GitHub.
Не все про веб, попалась тут репа какого-то китайского PhD Candidate и знаете - пора, как в эпоху короновируса закупались защитным масками, закупаться фольгой, чтобы делать шапочки. На самом деле github используется только как площадка для публикации научной статьи, поэтому вот сайт, там статья и еще немного картинок.
Короче, эти умельцы научились по сигналам из аппарата МРТ с помощью модели Stable Diffusion генерировать видео “что сейчас видит человек, который подключен к аппарату”. На картинке коты сверху это видео, которое показывается человеку, коты снизу это сгенерированные нейросетью кадры на основе сигналов, считанных из головного мозга.
WAT?
Да, пока для того, чтобы залезть к вам в мозг нужен этот огромный шкаф для МРТ, но с такими разработками мыслепреступления в недалеком будущем не такой уж и антиутопией кажутся.
Короче, эти умельцы научились по сигналам из аппарата МРТ с помощью модели Stable Diffusion генерировать видео “что сейчас видит человек, который подключен к аппарату”. На картинке коты сверху это видео, которое показывается человеку, коты снизу это сгенерированные нейросетью кадры на основе сигналов, считанных из головного мозга.
WAT?
Да, пока для того, чтобы залезть к вам в мозг нужен этот огромный шкаф для МРТ, но с такими разработками мыслепреступления в недалеком будущем не такой уж и антиутопией кажутся.
❤1
Нашел тут интересный пост про анимацию курсора в многопользовательских приложениях. И как всегда задача, которая с первого взгляда не кажется такой уж сложной, под капотом скрывает много всего интересного и отвечает на вопрос зачем у вас в универе была высшая математика (или нет, если вы гуманитарий).
Во-первых, если тупо раз в, к примеру, 120 мс обновлять позицию курсора, то уже анимация получается рваной, так плюс, что в реальной жизни к такому тротлингу надо прибавить еще от 5 до 15 мс. Итог в реальном приложении с сетевыми лагами будет еще хуже.
Первое, что приходит на ум -
Следующий вариант решения - это
И финально есть еще более крутой вариант это использование кубического сплайна (
Как всегда в первоисточнике все более точно и с крутыми демками, поэтому почитайте и потестите, если интересно.
Во-первых, если тупо раз в, к примеру, 120 мс обновлять позицию курсора, то уже анимация получается рваной, так плюс, что в реальной жизни к такому тротлингу надо прибавить еще от 5 до 15 мс. Итог в реальном приложении с сетевыми лагами будет еще хуже.
Первое, что приходит на ум -
transitions, но тут проблема, что путь анимации от одной точки до другой в случае css transition - всегда прямая линия. То есть если юзер водит курсор по кругу, то чем больше будет сетевая задержка - тем менее анимация курсора будет похожа на то, что делает реальный пользователь.Следующий вариант решения - это
spring animations. Тут отличие от обычной transition-анимации в том, что используются не только координаты до и после, но и текущий импульс. За счет этого анимация получается более плавной.И финально есть еще более крутой вариант это использование кубического сплайна (
Spline Interpolation). Это метод, когда новые точки строятся относительно набора уже известных точек и между ними рисуется параболическая кривая. Из-за того, что нам нужно накопить немного точек, чтобы знать как построить кривую между ними, получается небольшая задержка перед рендерингом, но это небольшая цена за практически близкий к реальному путь движения курсора на экране.Как всегда в первоисточнике все более точно и с крутыми демками, поэтому почитайте и потестите, если интересно.
liveblocks.io
How to animate multiplayer cursors | Liveblocks blog
Smoothly rendering live cursors is more difficult than it sounds when real‑world conditions are taken into account—here's a quick introduction to a few different methods, plus some React snippets.
Ну, лучшего описания адаптивного дизайна, наверное, уже не придумать
Такс, почти неделю ничего не писал, исправляюсь.
Когда мы говорим про
Каково же было мое удивление, когда я смотрел документацию по
Однако, глянув на него попристальней, сказать, что я был удивлен - это мягко сказать. Во-первых, очень простой синтаксис - стор это хук.
Дальше не надо оборачивать ничего в провайдеры, для использования внутри компонентов мы просто используем наш хук
Либа небольшая по размеру, имеет 30к звезд на гитхабе, решает многие дефолтные проблемы гонок, потери контекста и тд. Ну и посмотрите какой параллакс из 2013 у них на сайте.
Когда мы говорим про
React и стейт-менеджмент почти всегда мы думаем про Redux и это не значит, что других нет, просто это уже такой стандарт и все им пользуются (и не всегда оправданно), что я как-то и не следил, что нового в этой теме появляется.Каково же было мое удивление, когда я смотрел документацию по
liveblocks (библиотеки для простого внедрения многопользовательских реал-тайм сценариев в свое приложение), что среди адаптеров к их продукту был какой-то zustand.Однако, глянув на него попристальней, сказать, что я был удивлен - это мягко сказать. Во-первых, очень простой синтаксис - стор это хук.
import { create } from 'zustand'const useBearStore = create((set) => ({ bears: 0, increasePopulation: () => set((state) => ({ bears: state.bears + 1 })), removeAllBears: () => set({ bears: 0 }),}))Дальше не надо оборачивать ничего в провайдеры, для использования внутри компонентов мы просто используем наш хук
useBearStore и плюс можем подписаться на изменение конкретного свойства стора, чтобы не ререндерить компонент при изменении не относящихся к этому компоненту свойств, в отличии от контекста.function BearCounter() { const bears = useBearStore((state) => state.bears) return <h1>{bears} around here ...</h1>}Либа небольшая по размеру, имеет 30к звезд на гитхабе, решает многие дефолтные проблемы гонок, потери контекста и тд. Ну и посмотрите какой параллакс из 2013 у них на сайте.
zustand-demo.pmnd.rs
🐻 Bear necessities for state management in React
👍4❤1
Когда в начале 2022 года после всем известных событий на vc всплывали посты об импортозамещении
Принес вам ссылку на пост кофаундера и CTO фигмы, где в 2015 году он рассказывает, что фигма это как бы уже тогда и не совсем веб-приложение. Да, вы запускаете его через браузер, но что там под капотом?
Реализовано это счастье на C++ с использованием в 2015
– на стороне C++ они полностью управляют памятью без использования JavaScript
– html и svg дают много оверхеда и для задач фигмы чаще всего намного более медленные, чем 2D Canvas;
– всякие эффекты типа блюра, blend modes и масок, актуальные для графических приложений, реализованы по-разному между браузерами;
– также как и рендеринг текстов, который отличается между браузерами и операционными системами, в этом мы и сами (как любители пиксель-перфекта) не раз убеждались в своей практике, но там есть пара ссылок, где можно почитать подробнее (ссылки старые, но заверяю, что ничего за эти годы не поменялось);
– собственно, сами браузеры тоже проблема - каждый реализует разный набор возможностей, где-то что-то поддерживается, где-то что-то нет, в статье говорится про кастомные курсоры, которые в каждом браузере работают через разные форматы (SVG for Firefox, -webkit-image-set for Chrome and WebKit, and the ancient .cur format for IE).
И все это значит, что нельзя обучить чела на курсе по
Figma ничего кроме улыбки у меня это не вызывало и все вот почему.Принес вам ссылку на пост кофаундера и CTO фигмы, где в 2015 году он рассказывает, что фигма это как бы уже тогда и не совсем веб-приложение. Да, вы запускаете его через браузер, но что там под капотом?
Реализовано это счастье на C++ с использованием в 2015
asm.js, а в 2017 WebAssembly. Если у вас вопрос почему, то в тексте есть все ответы, но вот несколько важных поинтов:– на стороне C++ они полностью управляют памятью без использования JavaScript
Garbage Collector, который тоже конкурирует за ресурсы в main треде приложения и влияет на отзывчивость интерфейса, и в целом такой подход с использованием прекомпилированного кода на C++ позволяет иметь от 2x увеличения производительности в том числе, что браузер не занимается работой по интерпретации его в рантайме;– html и svg дают много оверхеда и для задач фигмы чаще всего намного более медленные, чем 2D Canvas;
– всякие эффекты типа блюра, blend modes и масок, актуальные для графических приложений, реализованы по-разному между браузерами;
– также как и рендеринг текстов, который отличается между браузерами и операционными системами, в этом мы и сами (как любители пиксель-перфекта) не раз убеждались в своей практике, но там есть пара ссылок, где можно почитать подробнее (ссылки старые, но заверяю, что ничего за эти годы не поменялось);
– собственно, сами браузеры тоже проблема - каждый реализует разный набор возможностей, где-то что-то поддерживается, где-то что-то нет, в статье говорится про кастомные курсоры, которые в каждом браузере работают через разные форматы (SVG for Firefox, -webkit-image-set for Chrome and WebKit, and the ancient .cur format for IE).
И все это значит, что нельзя обучить чела на курсе по
React-разработке за пару месяцев и пустить его пилить фичи в продукт. Поэтому и в никакое импортозамещение таких сложных продуктов я не верю, тем более что из-за сложности в опенсорсе ничего похожего не найти. Это все-таки не Rocket.Chat форкнуть, налепить свой логотип и сказать, что мы запустили аналог Slack.🤯1🙈1
Scroll anchoring
Короче, погрузился я тут в одну тему и решил, что можно про нее даже написать сюда.
Когда мы делаем какие-то chat-подобные приложения, когда при подгрузке контента надо актуализировать позицию скролла мы это обычно делаем так:
– получаем
– производим манипуляции по изменению;
– получаем
– считаем дельту и на эту дельту смещаем скролл.
Тем самым при увеличении высоты контента мы внимание юзера оставим в той же точке, где оно было до изменения. Однако, делать это нужно только в случае если изменение произошло выше вьюпорта, так как все, что произошло ниже вьюпорта скролл не аффектит.
Но даже зная эти вводные у меня все равно происходили скачки скролла не в то место, где он должен был оказываться. Кейсов, где надо было подскроллить после изменения контента было довольно много и чтобы это более-менее адекватно работало эмпирически было определено, что где-то надо было высчитывать дельту изменения, а где-то нет. При этом, в Safari работало все хорошо и на него даже был отдельный костыль, что там нужно тупо всегда высчитывать дельту.
В этот раз мне надоело бегать с бубном вокруг этой штуки и я нагуглил такое. В общем получается во всех браузерах кроме Safari они по-умолчанию сами пытаются восстановить позицию скролла после изменения контента в некоторых случаях, по моим наблюдениям как минимум это связано с загрузкой изображений (если, например, в момент изменения контента скролла была вставлена картинка и она загрузилась, то браузер сам подскроллит на дельту этой картинки). Отсюда и конфликты с нашей собственной реализацией подскролла.
Поэтому если вы делаете чат приложение и сами управляете скроллом после загрузки данных или других манипуляциях с контентом внутри скроллируемой области, то добавляйте это свойство:
И будет вам одинаковое поведение для всех браузеров без танцев с бубном.
Короче, погрузился я тут в одну тему и решил, что можно про нее даже написать сюда.
Когда мы делаем какие-то chat-подобные приложения, когда при подгрузке контента надо актуализировать позицию скролла мы это обычно делаем так:
– получаем
scrollHeight до изменения контента;– производим манипуляции по изменению;
– получаем
scrollHeight после изменений;– считаем дельту и на эту дельту смещаем скролл.
Тем самым при увеличении высоты контента мы внимание юзера оставим в той же точке, где оно было до изменения. Однако, делать это нужно только в случае если изменение произошло выше вьюпорта, так как все, что произошло ниже вьюпорта скролл не аффектит.
Но даже зная эти вводные у меня все равно происходили скачки скролла не в то место, где он должен был оказываться. Кейсов, где надо было подскроллить после изменения контента было довольно много и чтобы это более-менее адекватно работало эмпирически было определено, что где-то надо было высчитывать дельту изменения, а где-то нет. При этом, в Safari работало все хорошо и на него даже был отдельный костыль, что там нужно тупо всегда высчитывать дельту.
В этот раз мне надоело бегать с бубном вокруг этой штуки и я нагуглил такое. В общем получается во всех браузерах кроме Safari они по-умолчанию сами пытаются восстановить позицию скролла после изменения контента в некоторых случаях, по моим наблюдениям как минимум это связано с загрузкой изображений (если, например, в момент изменения контента скролла была вставлена картинка и она загрузилась, то браузер сам подскроллит на дельту этой картинки). Отсюда и конфликты с нашей собственной реализацией подскролла.
Поэтому если вы делаете чат приложение и сами управляете скроллом после загрузки данных или других манипуляциях с контентом внутри скроллируемой области, то добавляйте это свойство:
.scroller { overflow-anchor: none;}И будет вам одинаковое поведение для всех браузеров без танцев с бубном.
MDN Web Docs
Overview of scroll anchoring - CSS | MDN
As a user of the web, you are probably familiar with the problem that scroll anchoring solves. You browse to a long page on a slow connection and begin to scroll to read the content; while you are busy reading, the part of the page you are looking at suddenly…
🔥5👍1🤯1
webpack в amoCRM
Есть у меня статья двухлетней давности, про начало сборки фронта в amoCRM. Можно найти по тегу #amocrmbundling, а можно и долистать вверх, я не сказать, что очень много написал за эти два года, а сейчас будет пост на целых 2 сообщения 😅
В общем в итоге я выбрал
В дальнейшем на базе
Так вот в какой-то момент я начал задумываться о переходе на
Вот с переходом на
1. Мы не могли для каждого разработчика держать демон вебпака на дев-сервере, так как там не такая мощная тачка, чтобы крутить все дев-окружение проекта и еще вывезти довольно прожорливый по ресурсам вебпак в количестве десятков экземпляров.
2. У нас оставалась система виджетов, которая работает на require.js и использует наши модули в рандомном количестве, поэтому надо было оставить возможность использования наших модулей для виджетов.
По итогу при первом подходе к этой задаче оба вопроса остались нерешенными, начался очередной релиз и я замариновал ветку до лучших времен. И да, прикольно потом, когда актуализируешь такую ветку после релиза - прилетает что-то около 5000 коммитов из гита, сразу думаешь сколько же мы там накодили за несколько месяцев?
Есть у меня статья двухлетней давности, про начало сборки фронта в amoCRM. Можно найти по тегу #amocrmbundling, а можно и долистать вверх, я не сказать, что очень много написал за эти два года, а сейчас будет пост на целых 2 сообщения 😅
В общем в итоге я выбрал
require.js. Изначально, исходя из ее популярности на тот момент, и что она покрывала наши собственные потребности. Она позволяла в дев режиме собирать фронт в рантайме, подгружая файлики по сети, а в продакшене подгружать уже собранные чанки, чтобы количество запросов на статику в продакшене не было таким диким. Плюс разработка у нас построена через дев-сервер, на котором крутятся все сервисы и фронт загружался тоже с хоста разработчика. Сейчас уже смешно, а когда мы в Сан-Франциско проводили конфу и мне надо было оттуда прогать конструктор ботов - было не смешно, когда пинг оттуда до дев-сервера, находящегося в Мск доходил до 2 секунд на статичный файл. Приходилось один раз загружать фронт, выключать disable cache в хроме и вручную прописывать пути файлов, которые я редактировал, и которым при загрузке надо подставить рандомный хеш, чтобы именно для них кеш сбросился, иначе загрузку страницы можно было ждать пару минут.В дальнейшем на базе
require.js построилась система загрузки виджетов, которая с одной стороны дала гибкость для доработки продукта сторонними разработчиками, с другой, до сих пор вставляет палки в колеса при различных рефакторингах и переделках внутренних компонентов. Тут можно сказать, что сами виноваты, что не предоставляем описанный SDK, только по которому можно было бы разрешать работать с модулями системы, но имеем то, что от нас требуется всегда думать об обратной совместимости всех переделок, так как любая из них может рандомно выстрелить в одном из виджетов.Так вот в какой-то момент я начал задумываться о переходе на
webpack и есть у меня такая особенность, что я могу на год оставить какие-то правки лежать в ветке год, потому что не получается, а потом спустя год вернуться к ним и придумать решение.Вот с переходом на
webpack получилась ровно такая история. Первый раз не получилось потому что у меня не было решения как встроить сборку webpack в наш монолит, я сконвертил конфиг require.js в конфиг webpack, довел до плюс/минус заводимого состояния, но дальше было две проблемы:1. Мы не могли для каждого разработчика держать демон вебпака на дев-сервере, так как там не такая мощная тачка, чтобы крутить все дев-окружение проекта и еще вывезти довольно прожорливый по ресурсам вебпак в количестве десятков экземпляров.
2. У нас оставалась система виджетов, которая работает на require.js и использует наши модули в рандомном количестве, поэтому надо было оставить возможность использования наших модулей для виджетов.
По итогу при первом подходе к этой задаче оба вопроса остались нерешенными, начался очередной релиз и я замариновал ветку до лучших времен. И да, прикольно потом, когда актуализируешь такую ветку после релиза - прилетает что-то около 5000 коммитов из гита, сразу думаешь сколько же мы там накодили за несколько месяцев?
Продолжение поста выше... #amocrmbundling
Как в итоге решились оба вопроса?
Во-первых, я завел куку для дев-окружения, что-то типа
Во-вторых, написал плагин для webpack, который при сборке продакшен билда для каждого модуля, который нужно экспортировать, добавляет строки вида:
Таким образом если необходимый модуль для виджета был загружен с рантаймом страницы, на которой загрузился пользователь, то для этого модуля не будет вызван никакой дополнительный запрос в сеть, мы зарегистрировали экзепляр от
Если модуль не был загружен, то
Наверное, были еще какие-то проблемы, которые менее существенны и их получилось решить быстрее, но эти две мне показались самыми интересными и про них можно было написать. Так мы перешли на
Дальше был такой же долгий процесс перехода на
Как в итоге решились оба вопроса?
Во-первых, я завел куку для дев-окружения, что-то типа
use-localhost со значением Number, с помощью которого можно указать порт, на котором крутится webpack-dev-server. При получении запроса бекенд смотрит, если мы в дев-окружении и есть эта кука, то хост статики выставляется localhost с номером порта из значения куки. Таким образом теперь фронт грузится с локальной машины, проблемы Сан-Франциско теперь быть не может.Во-вторых, написал плагин для webpack, который при сборке продакшен билда для каждого модуля, который нужно экспортировать, добавляет строки вида:
window.define('${requirejsModuleName}', function(){ return module.exports;});window.require(['${requirejsModuleName}']);Таким образом если необходимый модуль для виджета был загружен с рантаймом страницы, на которой загрузился пользователь, то для этого модуля не будет вызван никакой дополнительный запрос в сеть, мы зарегистрировали экзепляр от
webpack в регистре модулей require.js.Если модуль не был загружен, то
require.js сходит за ним в сеть на наш сервер, так как конфиг и структура файловой системы для require.js не изменились. Проблема была только с вендорными либами, которые лежат в папке node_modules, которая в свою очередь на продакшен не деплоится, но для этих модулей я прописал в конфиге пути на cdnjs. Поэтому если какая-то вендорная либа, которую захочет подгрузить виджет не загружена в рантайме, то виджет подгрузит ее с cdnjs.Наверное, были еще какие-то проблемы, которые менее существенны и их получилось решить быстрее, но эти две мне показались самыми интересными и про них можно было написать. Так мы перешли на
webpack, стали быстрее собирать фронт, сильно быстрее работать в дев-режиме, не зааффектив при этом производительность итак не самого быстрого дев-сервера.Дальше был такой же долгий процесс перехода на
es6, но это уже, как говорится, другая история.😎2
Всем привет, начало будет странным, но потом все будет понятно.
Надо было мне в Турции купить солнцезащитный крем, в отеле цена была каких-то конских 44 евро за обычную нивею. В итоге в городе в аптеке нашлась такая за 500 лир, я переводил это все в рубли с помощью конвертера валют, которым уже давно пользуюсь (когда живешь на 2 страны очень нужный инструмент) и меня триггернуло.
Вроде простая штука и деньги за такие приложения никто старается не брать, но как бомжи с табличками "дайте на жизнь" суют свою сраную рекламу, кто-то просто плашку внизу, а отдельные рвачи попапы на весь экран с таймером до закрытия, как будто я фильм собираюсь смотреть, а не цифру из одной валюты в другую перевести.
В общем так в отпуске родился мой небольшой пэт-проект, который я решил сделать полностью бесплатным без какой-либо рекламы и опен-сорсным. Пока готова версия для iOS, но скоро приедет и андроид.
Ссылка на AppStore.
P. S. Если под постом наберется какое-то количество реакций, то запилю пост о том, как оно работает.
Надо было мне в Турции купить солнцезащитный крем, в отеле цена была каких-то конских 44 евро за обычную нивею. В итоге в городе в аптеке нашлась такая за 500 лир, я переводил это все в рубли с помощью конвертера валют, которым уже давно пользуюсь (когда живешь на 2 страны очень нужный инструмент) и меня триггернуло.
Вроде простая штука и деньги за такие приложения никто старается не брать, но как бомжи с табличками "дайте на жизнь" суют свою сраную рекламу, кто-то просто плашку внизу, а отдельные рвачи попапы на весь экран с таймером до закрытия, как будто я фильм собираюсь смотреть, а не цифру из одной валюты в другую перевести.
В общем так в отпуске родился мой небольшой пэт-проект, который я решил сделать полностью бесплатным без какой-либо рекламы и опен-сорсным. Пока готова версия для iOS, но скоро приедет и андроид.
Ссылка на AppStore.
P. S. Если под постом наберется какое-то количество реакций, то запилю пост о том, как оно работает.
👍15🔥8👏2
Как и обещал пишу о том, что под капотом у How Much In. Начнем с не менее важной части, чем само приложение - откуда данные?
Изначально я начал смотреть какие есть апишки на тему курсов валют. Их на самом деле вагон и маленькая тележка. Я не сильно прям сравнивал все возможные, но плюс минус все имеют ограничение в 1000 запросов в месяц на бесплатном тарифе.
Поэтому первым решением было сделать кеширующую API-прослойку. Если посчитать, что обновление мы будем делать раз в час, то
Какой-то хороший человек делает выгрузки курсов раз в день и кладет результаты в свой публичный репозиторий. А дальше красиво, не многие знают, но есть такой публичный CDN - JSDelivr. Он кроме хостинга всяких публичных библиотек занимается зеркалированием публичных GitHub-репозиториев размер которых до 50 МБ. Сам я нашел это когда мы делали сайт-визитку в amoCRM и оказалось, что Taplink, например, использует такой подход для раздачи статики на своем продакшене. Просто деплоят фронт в публичную репу на гитхабе, а в продакшене ссылки на статику ведут на эту репу через jsdelivr.
Короче, я решил использовать эту апишку, единственное о чем подумал - это все-таки не использовать ее напрямую, а завести через свой домен на случай если она вдруг станет недоступна. Чтобы можно было восстановить отдачу данных с тем же самым форматом уже из другого источника и с собственного сервера без перезаливки приложения в сторы.
Это было просто, пришел на помощь Yandex.Cloud с их API Gateway и решилось все одним YAML файлом примерно следующего содержания:
Таким образом мой эндпоинт сейчас просто проксирует запрос на jsdelivr и эту публичную апишку: https://api.how-much.in/currency-api@1/latest/currencies
Вопросы? Откуда берутся данные? Честно - сам толком не понял, в issues чувак не отвечает, но вроде плюс/минус курс совпадает. Обновление раз в день? Да, но цель была не потухнуть на этапе разработки бекенда, а выпустить приложение, поэтому пока пусть будет так - для ознакомительных целей, чтобы примерно перевести сумму в другую валюту достаточно - эталонной точности нет, но и не надо пока. Если интерес останется, то сделаю
На этом пока все, итак вроде много получилось, про интерфейс и react-native в следующих сериях.
Изначально я начал смотреть какие есть апишки на тему курсов валют. Их на самом деле вагон и маленькая тележка. Я не сильно прям сравнивал все возможные, но плюс минус все имеют ограничение в 1000 запросов в месяц на бесплатном тарифе.
Поэтому первым решением было сделать кеширующую API-прослойку. Если посчитать, что обновление мы будем делать раз в час, то
24 * 30 = 720. То есть даже укладываемся в бесплатный лимит, но все-таки я больше про интерфейсы, чем пилить какую-то апишку. Конечно, лезть в весь этот бекенд мне не хотелось, поэтому, еще немного поискав, я нашел вот эту репу https://github.com/fawazahmed0/currency-apiКакой-то хороший человек делает выгрузки курсов раз в день и кладет результаты в свой публичный репозиторий. А дальше красиво, не многие знают, но есть такой публичный CDN - JSDelivr. Он кроме хостинга всяких публичных библиотек занимается зеркалированием публичных GitHub-репозиториев размер которых до 50 МБ. Сам я нашел это когда мы делали сайт-визитку в amoCRM и оказалось, что Taplink, например, использует такой подход для раздачи статики на своем продакшене. Просто деплоят фронт в публичную репу на гитхабе, а в продакшене ссылки на статику ведут на эту репу через jsdelivr.
Короче, я решил использовать эту апишку, единственное о чем подумал - это все-таки не использовать ее напрямую, а завести через свой домен на случай если она вдруг станет недоступна. Чтобы можно было восстановить отдачу данных с тем же самым форматом уже из другого источника и с собственного сервера без перезаливки приложения в сторы.
Это было просто, пришел на помощь Yandex.Cloud с их API Gateway и решилось все одним YAML файлом примерно следующего содержания:
paths: /{path+}: get: parameters: - name: path in: path required: false schema: type: string responses: '200': description: API endpoint content: 'application/json': schema: type: "string" x-yc-apigateway-integration: type: http url: https://cdn.jsdelivr.net/gh/fawazahmed0/{path}.min.jsonТаким образом мой эндпоинт сейчас просто проксирует запрос на jsdelivr и эту публичную апишку: https://api.how-much.in/currency-api@1/latest/currencies
Вопросы? Откуда берутся данные? Честно - сам толком не понял, в issues чувак не отвечает, но вроде плюс/минус курс совпадает. Обновление раз в день? Да, но цель была не потухнуть на этапе разработки бекенда, а выпустить приложение, поэтому пока пусть будет так - для ознакомительных целей, чтобы примерно перевести сумму в другую валюту достаточно - эталонной точности нет, но и не надо пока. Если интерес останется, то сделаю
currency-api@2 и оно будет обновляться чаще и показывать более точно.На этом пока все, итак вроде много получилось, про интерфейс и react-native в следующих сериях.
GitHub
GitHub - fawazahmed0/currency-api: Free Currency Exchange Rates API with 150+ Currencies & No Rate Limits
Free Currency Exchange Rates API with 150+ Currencies & No Rate Limits - fawazahmed0/currency-api
👍9
Ура! Гугл наконец-то промодерировали андроид-версию спустя неделю!
Поэтому новый пост и немного деталей про реализацию. Хоть прила и совсем крошечная, но даже тут пришлось приложить подорожник к реакт-нейтиву, так как он не вывозил.
Часто приложения для конвертации валют выглядят как калькулятор и переводить можно одну валюту в другую. Такой подход неудобен, если мне надо иметь под рукой несколько валют. К примеру, когда есть две национальные и плюс какие-то расчеты все равно делаются в долларах или евро. Постоянно переключать то на одну, то на другую - так себе. Поэтому оптимальный вариант выводить сразу список валют, где при редактировании одной, переводим сразу во все остальные. Признаюсь, это не я придумал, но подход CurrencyApp, например, мне не нравится отдельным экраном ввода суммы. Им-то понятно зачем это надо, чтобы как можно больше рекламы прокрутить, но у меня такой задачи нет, поэтому хорошо сразу достать клавиатуру и налету пересчитывать для всех выбранных валют.
Итак, в приложении используется
У нас есть оберточный
Следующая оптимизация начинается, когда мы вводим значение. Если мы сразу пересчитаем значение для всех валют (а их может быть выведено более 150), то опять же получим дерганье как в эпилептическом припадке, а не ощущение летающего нативного приложения. Поэтому в коде выше
Подводя итог, да, на react-native достаточно легко писать приложения сразу под обе мобильные платформы, но если вы правда хотите ощущения нативности, то на каждом шагу вам нужно будет продумывать вот такие нестандартные решения часто стандартных вопросов, либо идти на компромисы.
Поэтому новый пост и немного деталей про реализацию. Хоть прила и совсем крошечная, но даже тут пришлось приложить подорожник к реакт-нейтиву, так как он не вывозил.
Часто приложения для конвертации валют выглядят как калькулятор и переводить можно одну валюту в другую. Такой подход неудобен, если мне надо иметь под рукой несколько валют. К примеру, когда есть две национальные и плюс какие-то расчеты все равно делаются в долларах или евро. Постоянно переключать то на одну, то на другую - так себе. Поэтому оптимальный вариант выводить сразу список валют, где при редактировании одной, переводим сразу во все остальные. Признаюсь, это не я придумал, но подход CurrencyApp, например, мне не нравится отдельным экраном ввода суммы. Им-то понятно зачем это надо, чтобы как можно больше рекламы прокрутить, но у меня такой задачи нет, поэтому хорошо сразу достать клавиатуру и налету пересчитывать для всех выбранных валют.
Итак, в приложении используется
FlatList для вывода списка валют. Каждая валюта под названием имеет фиолетовый прямоугольник, который является и выводом значения и полем ввода одновременно. При выводе значения в текст число форматируется в соответствии с локалью пользователя через ReactIntl, отбивает тысячные, десятичные доли и тд. При этом инпут ввода - стандарный TextInput. Если мы заводим стейт и перерисовываем по клику то текст, то инпут - уже здесь у react-native начинаются затупы, подлагивания при появлении клавиатуры и ты чувствуешь, что что-то не то. React может и чувствуется, а вот native как-то не очень. Поэтому делаем хитро.<View style={tw`relative`}> <TextInput ref={inputRef} defaultValue={valueRef.current} style={tw`opacity-0`} onChangeText={v => { setValues(currency, parseFloat(v)); }} onFocus={() => { inputRef.current?.setNativeProps({ style: { opacity: 1, zIndex: 1 }, }); }} onBlur={() => { inputRef.current?.setNativeProps({ style: { opacity: 0, zIndex: -1 }, }); }} onEndEditing={e => { const v = e.nativeEvent.text; if (initialValueRef.current !== v) { setTimeout( () => setValues(currency, parseFloat(v), true), 500, ); } }} /> <View pointerEvents="none" style={tw`absolute`} > <Text> <FormattedNumber value={value} style="currency" currency={currency.toUpperCase()} /> </Text> </View></View>У нас есть оберточный
View, внутри которого с абсолютным позиционированием лежит Text с отформатированным значением, для его родителя указан pointerEvents="none", то есть клик по нему не обрабатывается. Под ним лежит прозрачный TextInput и когда мы кликаем на сумму валюты мы на самом деле ставим курсор в инпут, который на фокус становится непрозрачным и начинает нормально отображаться, а по блюру, соответственно, скрывается. Такой подход позволяет иметь полностью нативное ощущение при постановке курсора в инпут в списке неограниченного размера.Следующая оптимизация начинается, когда мы вводим значение. Если мы сразу пересчитаем значение для всех валют (а их может быть выведено более 150), то опять же получим дерганье как в эпилептическом припадке, а не ощущение летающего нативного приложения. Поэтому в коде выше
setValues вызывается 2 раза. Первый раз на onChangeText и тут мы берем индекс изменяемой валюты и пересчитываем только 10 сверху и снизу, чтобы перерисовка по мере ввода требовалась только 20 элементам списка максимум (тем, которые точно видит пользователь). Так мы получаем близкую к идеальной работу пересчета по мере ввода. А уже на onEditingEnd пересчитываем для всех и там добавим небольшой таймаут 500мс, чтобы клавиатура скрылась без тормозов.Подводя итог, да, на react-native достаточно легко писать приложения сразу под обе мобильные платформы, но если вы правда хотите ощущения нативности, то на каждом шагу вам нужно будет продумывать вот такие нестандартные решения часто стандартных вопросов, либо идти на компромисы.
Google Play
How Much In - Apps on Google Play
Currency converter without ads
👍2✍1🔥1
Сегодня утром я за один час сделал лендинг для прилы How Much In. Пока это самый крутой экспириенс по no-code запускам, что я пробовал. И это Framer.
Для начала тебя просят ввести словесное описание того, что ты хочешь наклепать. Мой финальный вариант был:
Да, пришлось в конце принудительно сказать, что не нужна секция с ценами, так как несмотря на то, что в описании было, что приложение бесплатное генератор все равно выдает секцию с тарифами.
Сгенерив несколько вариантов, я получил практически то, что финально вы видите на лендосе. Был немного другой фиолетовый, я руками поправил на цвета из моей иконки. Изначально был выбран другой шрифт заголовков, это можно тоже менять руками. Эта штука сгенерила булщит тексты, которые я частично самостоятельно скорректировал через ChatGPT, частично оставил прям то, что сгенерил AI Framer'а.
Помимо этих приятных AI-плюшек, конечно, имеется годный интерфейс, который генерит довольно неплохую верстку на flex-ах или гридах. И если вы знаете как работает такая верстка, то работать с этим инструментом одно удовольствие.
Довольно кусачая цена в 5 долларов в месяц при годовой оплате и отсутствие экспорта проекта, на что я надеялся, когда туда полез, но деньги зарабатывать тоже как-то надо ребятам.
Для начала тебя просят ввести словесное описание того, что ты хочешь наклепать. Мой финальный вариант был:
landing page about free currency converter mobile app even without ads that called "How Much In" in white/violet color scheme without pricing sectionДа, пришлось в конце принудительно сказать, что не нужна секция с ценами, так как несмотря на то, что в описании было, что приложение бесплатное генератор все равно выдает секцию с тарифами.
Сгенерив несколько вариантов, я получил практически то, что финально вы видите на лендосе. Был немного другой фиолетовый, я руками поправил на цвета из моей иконки. Изначально был выбран другой шрифт заголовков, это можно тоже менять руками. Эта штука сгенерила булщит тексты, которые я частично самостоятельно скорректировал через ChatGPT, частично оставил прям то, что сгенерил AI Framer'а.
Помимо этих приятных AI-плюшек, конечно, имеется годный интерфейс, который генерит довольно неплохую верстку на flex-ах или гридах. И если вы знаете как работает такая верстка, то работать с этим инструментом одно удовольствие.
Довольно кусачая цена в 5 долларов в месяц при годовой оплате и отсутствие экспорта проекта, на что я надеялся, когда туда полез, но деньги зарабатывать тоже как-то надо ребятам.
www.how-much.in
How Much In
Completely free currency converter app
🔥5❤2👍1
Впервые пробую запустить кампанию на Product Hunt для How Much In. Если не сложно поставьте плюсик.
На этом скорее всего посты про приложение закончатся, программа максимум для этого пэт-проекта выполнена. Поздравляю, вы прошли игру.
На этом скорее всего посты про приложение закончатся, программа максимум для этого пэт-проекта выполнена. Поздравляю, вы прошли игру.
Product Hunt
How Much In - Product Information, Latest Updates, and Reviews 2024 | Product Hunt
Introducing How Much In, a currency conversion app developed with a focus on providing fast and efficient performance that's entirely free and features no annoying ads. Bid farewell unanticipated pop-ups. Built with React-Native.
🔥3