<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>Nikolay Ivanushkin</title><subtitle>CTO of Teletype</subtitle><author><name>Nikolay Ivanushkin</name></author><id>https://teletype.in/atom/nick-iv</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/nick-iv?offset=0"></link><link rel="alternate" type="text/html" href="https://blog.nick-iv.me/?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=nick-iv"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/nick-iv?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-04-07T09:55:43.317Z</updated><entry><id>nick-iv:HJWmIxraZ</id><link rel="alternate" type="text/html" href="https://blog.nick-iv.me/HJWmIxraZ?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=nick-iv"></link><title>Работа с изображениями в Teletype</title><published>2020-01-29T09:20:00.941Z</published><updated>2022-01-12T18:24:50.725Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://teletype.in/files/1b/1b3b2ec6-065c-4bde-9922-336a55468a7d.jpg"></media:thumbnail><category term="teletype" label="Teletype"></category><summary type="html">&lt;img src=&quot;https://teletype.in/files/1b/1b3b2ec6-065c-4bde-9922-336a55468a7d.jpg&quot;&gt;Недавно Телетайп получил большое обновление. Мы переработали дизайн, добавили приятных фишек, вроде выключения ката, скрытия участников блога, цветовых схем и всякого look and feel. Внутри тоже произошли некоторые интересные изменения.</summary><content type="html">
  &lt;p id=&quot;lrTD&quot;&gt;Недавно Телетайп получил большое обновление. Мы переработали дизайн, добавили приятных фишек, вроде выключения ката, скрытия участников блога, цветовых схем и всякого look and feel. Внутри тоже произошли некоторые интересные изменения.&lt;/p&gt;
  &lt;p id=&quot;H9zF&quot;&gt;Мне кажется, некоторые решения достаточно очевидны, но возможно не всем. Этой статьей я открываю небольшой цикл статей о технологиях и решениях, которые мы используем в Телетайпе.&lt;/p&gt;
  &lt;h2 id=&quot;DjqE&quot;&gt;Вводные данные&lt;/h2&gt;
  &lt;p id=&quot;OnvF&quot;&gt;Телетайп работает целиком на Node.js, и использует базу данных PostgreSQL. Все сервисы (кроме БД) мы оборачиваем в Docker-контейнеры, и балансируем через nginx. При этом сервисы общаются через Docker Network.&lt;/p&gt;
  &lt;h2 id=&quot;bMul&quot;&gt;Генерируем картинки для шаринга в социальных сетях&lt;/h2&gt;
  &lt;p id=&quot;Ogy5&quot;&gt;Телетайп поддерживает формат Open Graph. Нам очень хотелось, чтобы для каждой статьи и страницы блога генерировались красивые картинки для шаринга.&lt;/p&gt;
  &lt;figure id=&quot;KM5d&quot; class=&quot;m_custom&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/1b/1b3b2ec6-065c-4bde-9922-336a55468a7d.jpg&quot; width=&quot;375&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;2n6h&quot;&gt;Поскольку мы используем JavaScript, нам нет никаких проблем сделать такие картинки обычной HTML версткой. Всё что нам нужно, просто отрендерить на стороне сервера и сохранить картинку в PNG. Это очень упрощает жизнь, т.к. нет проблем сверстать это. А рендерингом занять &lt;a href=&quot;https://phantomjs.org/&quot; target=&quot;_blank&quot;&gt;PhantomJS&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;rYvs&quot;&gt;Весь сервис работы с картинками был вынесен из главного бекенда. По этому, когда статья обновляется, для нее на основном бекенде генерируется HTML, и отправляется на рендеринг в сервис работы с картинками. В ответ мы получаем уже адрес сохраненной картинки. Всё что нам нужно — просто обновить его в базе.&lt;/p&gt;
  &lt;h2 id=&quot;c8Mg&quot;&gt;Загружаем картинки&lt;/h2&gt;
  &lt;p id=&quot;Z7NV&quot;&gt;Телетайп поддерживает загрузку картинок до 5Мб. Если вы не злобный хакер, и не будете пытаться слать напрямую картинки через API, то картинки большего размера отсечет еще клиентское приложение, и время а отправку в сеть не будет потрачено. Но даже 5Мб могут серьезно нагрузить основной бекенд. По этому сервис работы с тяжелыми файлами был вынесен в дополнительный бекенд сервис. И теперь если кто-то грузит картинку, то на читающих статьи пользователях это никак не скажется.&lt;/p&gt;
  &lt;p id=&quot;sRzG&quot;&gt;&lt;strong&gt;Что можно бы еще оптимизировать?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;h672&quot;&gt;Во первых мы не удаляем картинки с сервера. Это сложно, не полезно для дисков, и медленно для редактора. Удобно же при редактировании поста просто удалить картинку, и не ждать, когда она удалиться.&lt;/p&gt;
  &lt;p id=&quot;kvmn&quot;&gt;Во вторых, вполне нормальный пользовательский кейс, когда вы добавили картинку в статью, удалили, передумали и снова добавили. Значит мы загрузим две одинаковые картинки? Бесплатно? Ну нет.&lt;/p&gt;
  &lt;p id=&quot;Lgha&quot;&gt;Можно генерировать хеш-сумму. Например SHA1. Просто храним ее для каждой сохраненной картинки, аватарки пользователя и картинки для шаринга в соцсетях. Есть небольшой нюанс. SHA1 считается уже слабым алгоритмом. Есть &lt;a href=&quot;https://shattered.it/&quot; target=&quot;_blank&quot;&gt;вероятность коллизии&lt;/a&gt;. Никому не захочется загрузить одну картинку, а получить чью-то чужую.&lt;/p&gt;
  &lt;p id=&quot;W2Ga&quot;&gt;По этому, для картинки мы генерируем 2 хеш-суммы — SHA1 и SHA256. Это очень сильно про запас, но накладные расходы по сравнению с сохранением картинки на диск минимальны.&lt;/p&gt;
  &lt;p id=&quot;wrqm&quot;&gt;Теперь перед загрузкой картинки, мы просто на клиенте берем 2 хеш-суммы, и делаем проверку одним запросом. Если такая картинка уже загружена — сервер вернет нам ее адрес. Все картинки обезличиваются, и сохраняются с UUID в имени: &lt;code&gt;https://teletype.in/files/be/bec30fa9-8338-4790-bc49-be1f1be49768.jpg&lt;/code&gt;, как-то так. На всякий случай, при загрузке картинки, сервер сам сверит хеш-суммы с имеющимися в базе. Хранящиеся хеши в таблицах базы могут должны быть уникальными.&lt;/p&gt;
  &lt;h2 id=&quot;zoFQ&quot;&gt;Обрабатываем картинки&lt;/h2&gt;
  &lt;p id=&quot;K2Jx&quot;&gt;Не так давно, нам пожаловался пользователь. Он загрузил фотографии с телефона в статью, а они неправильно повернулись.&lt;/p&gt;
  &lt;p id=&quot;dFmz&quot;&gt;Всё дело в EXIF. Изначально картинка повернута как попало, а правильная ориентация выставляется из EXIF данных с параметром &lt;em&gt;orientation&lt;/em&gt;. Всего типов ориентации картинки может быть 8.&lt;/p&gt;
  &lt;p id=&quot;TYiO&quot;&gt;Итого, нужно было повернуть картинку. Вырезать весь EXIF (и сэкономить немного памяти дискам), ну и в случае с аватарками привести их к нужным нам размерам.&lt;/p&gt;
  &lt;p id=&quot;flwh&quot;&gt;Всё это можно было сделать с помощью ImageMagic. Но поскольку один из разработчиков Телетайпа большой любитель JS, да и человеко-понятность ImageMagic убывающе мала, мы нашли модуль для Node.js – &lt;a href=&quot;https://www.npmjs.com/package/lwip&quot; target=&quot;_blank&quot;&gt;lwip&lt;/a&gt;. Он умеет вполне достаточно: повернуть картинку, зеркально отразить, обрезать, поменять размеры, и сохранить всё с минимальным набором параметров. За одно, при сохранении добавили дополнительную оптимизацию картинок (85% качества для JPEG мало кто заметит, ведь да?).&lt;/p&gt;
  &lt;h2 id=&quot;KPSm&quot;&gt;В следующих сериях&lt;/h2&gt;
  &lt;ol id=&quot;uiM9&quot;&gt;
    &lt;li id=&quot;drVK&quot;&gt;&lt;strong&gt;Работа с изображениями&lt;/strong&gt;&lt;/li&gt;
    &lt;li id=&quot;aTin&quot;&gt;Домены блогов. Как работает привязка&lt;/li&gt;
    &lt;li id=&quot;CzFv&quot;&gt;Домены блогов. Как работают домены&lt;/li&gt;
    &lt;li id=&quot;mfN6&quot;&gt;Домены блогов. Как работает HTTPS для доменов&lt;/li&gt;
    &lt;li id=&quot;gHbh&quot;&gt;Изоморфный Телетайп без React и Virtual DOM&lt;/li&gt;
    &lt;li id=&quot;oQF1&quot;&gt;Проблемы визуальных редакторов текста&lt;/li&gt;
  &lt;/ol&gt;

</content></entry><entry><id>nick-iv:SyKefU69x</id><link rel="alternate" type="text/html" href="https://blog.nick-iv.me/SyKefU69x?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=nick-iv"></link><title>Firefox 52 поддержал CSS Grid Layout</title><published>2020-01-29T09:19:48.145Z</published><updated>2021-05-27T15:03:57.343Z</updated><category term="development" label="Development"></category><summary type="html">Новый Firefox 52 вышедший 7 марта поддержал CSS Grid Layout. До этого поддержка была только у Internet Explorer и Edge, и то с префиксами и по драфтовой спецификации (кто их просил делать по драфту, привет Flex Box).</summary><content type="html">
  &lt;figure class=&quot;m_column&quot;&gt;
    &lt;iframe src=&quot;https://codepen.io/nim579/embed/VVpWdo?default-tab=result&quot;&gt;&lt;/iframe&gt;
  &lt;/figure&gt;
  &lt;p&gt;Новый Firefox 52 вышедший 7 марта поддержал &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout&quot; target=&quot;_blank&quot;&gt;CSS Grid Layout&lt;/a&gt;. До этого поддержка была только у Internet Explorer и Edge, и то с префиксами и по драфтовой спецификации (кто их просил делать по драфту, привет &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout&quot; target=&quot;_blank&quot;&gt;Flex Box&lt;/a&gt;).&lt;/p&gt;
  &lt;p&gt;Возможно это будет одна из самых революционных фич за последнее время. Сеточки очень сильно облегчат жизнь, и дадут новый повод верстальщикам заставлять дизайнеров следовать сеткам. Кроме того, &lt;a href=&quot;https://getbootstrap.com/&quot; target=&quot;_blank&quot;&gt;Bootstrap&lt;/a&gt; тоже сможет избавиться от костылей вроде &lt;code&gt;clear: both;&lt;/code&gt;.&lt;/p&gt;
  &lt;p&gt;Теперь осталось дождаться только Хром (думаю уже скоро), и Сафари (вот тут неизвестно когда). Кроме того, поддержка пока не заявлена мобильными браузерами. Но никто не запрещает делать фолбеки, к тому же для мобильных браузеров самое милое дело.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p&gt;В общем, ура! Ждем пол-года и внедряем 🤗🎉&lt;/p&gt;

</content></entry></feed>