
Web-технологии
Cloudflare tunnel, как ngrock только Cloudflare
Не так давно я прикупил себе неттоп dell optiplex 3070 micro на авито и решил поставить его у себя на работе, что бы захостить на нем все свои пет проекты.
Если посчитать сумму которую я плачу за хостинг, то этот неттоп окупается за год, но по производительности на порядки мощнее всех vds за которые я плачу.
Проблема только в том, что на работе у меня нет белого ip и пробрасывать порты мне ни кто не будет, вот я и решил воспользоваться cloudflare tunnel.
Для начала необходимо создать аккаунт в cloudflare и привязать домен.
Моя структура папок.
~/docker
mysql
docker-compose.yml - compose файл
cloudflare
_conf - конфиги cloudflare
docker-compose.yml - compose файл
Авторизация
cd ~/docker/cloudflare
mkdir _conf
chmod 0777 _conf
docker run -v ./_conf/:/home/nonroot/.cloudflared/ cloudflare/cloudflared:latest tunnel login
Создание
docker run -v ./_conf/:/home/nonroot/.cloudflared/ cloudflare/cloudflared:latest tunnel create mytunnelname
Список
docker run -v ./_conf/:/home/nonroot/.cloudflared/ cloudflare/cloudflared:latest tunnel list
Создаем конфиг файл _conf/config.yml
url: http://phpmyadmin
tunnel: <Tunnel-UUID>
credentials-file: /root/.cloudflared/<Tunnel-UUID>.json
Добавление записи DNS
docker run -v ./_conf/:/home/nonroot/.cloudflared/ cloudflare/cloudflared:latest tunnel route dns mytunnelname mytunnelname.topsicretdomain.ru
Для тестирования запуска я создам контейнер с phpMyAdmin ~/docker/mysql/docker-compose.yml
version: '3.9'
services:
mysql:
container_name: "mysql"
image: "mysql:8-debian"
restart: unless-stopped
volumes:
- ./data:/var/lib/mysql
- ./sql:/app
environment:
- MYSQL_ROOT_PASSWORD=root
- TZ=Europe/Moscow
phpmyadmin:
image: phpmyadmin
restart: unless-stopped
environment:
- PMA_HOST=mysql
ports:
- "8080:80"
networks:
default:
name: web
Запуск phpMyAdmin
cd ~/docker/mysql/
docker compose up -d
Теперь можно запустить наш compose файл для cloudflare tunnel
version: '3.9'
services:
tunnel:
image: cloudflare/cloudflared:latest
container_name: cloudflare_tunnel
restart: unless-stopped
command: tunnel run mytunnelname
volumes:
- ./conf/:/home/nonroot/.cloudflared/
extra_hosts:
- "parent:host-gateway"
networks:
default:
name: web
cd ~/docker/cloudflare
docker compose up -d
Готово.
Важно. Что бы все корректно работало необходимо запускать phpMyAdmin и cloudflared в одной docker сети
networks:
default:
name: web
Плавное погружение в SvelteKit на примере создания сайта знакомств
Скринкаст вылил на рутуб, что бы не тратить трафик на сервисах для доступа к youtube 🤫. Смотреть строго на 2x.
Содержание первой части:
Инициализация проекта
Подключение tailwind css
Реализация регистрации, авторизации и выхода
Настройка adapter static
Очень жду первых 10 подписчиков и рейтинг 1000, что бы организовать сбор на женщину с низкой социальной ответственностью для неистового совокупления.
Source-map-explorer
На прошлой неделе анализировал размер главного бандла мобильной версии нашего приложения.
В спешке мы накосячили с импортами и бандл раздулся.
🤔 Как анализировать?
Для анализа использовал утилиту source-map-explorer.
При запуске, утилита генирирует древовидную карту, с помощью которой можно увидеть, какие именно файлы попадают в бандл.
К сожалению, почему именно это что-то попало в бандл утилита не говорит.
👉 В чём была проблема?
Иногда мы ленимся и в файле компонента кладём какую-нибудь утилитную функцию, enum или константу, а потом где-то в другом месте импортируем их.
Так вот, когда мы их импортируем, то в бандл “засасывает” не только импортируемую функцию, но и весь компонент, из-за чего размер бандла и увеличивается.
P.S. А какими инструментами пользуетесь вы?
Чек аут)
как же я люблю злить вас бездельников :--)
Курьезные ошибки в веб-дизайне: самые смешные и странные примеры
Веб-дизайн может быть источником множества курьезных ошибок, которые вызывают у пользователей недоумение, хуже того – мешают нормально взаимодействовать с сайтами. Некоторые компании оставляют все как есть, не обновляя интернет-представительства с 90-х годов, другие – игнорируют проблемы. Рассмотрим странные и смешные примеры веб-дизайна:
Pacific Northwest X-Ray Inc.
Компания предлагает портативные рентгеновские аппараты, очки, перчатки, фартуки и другие сопутствующие товары. Ее сайт известен своим неуклюжим и устаревшим дизайном, напоминающим стандарты 2000-х годов.
Доступен по ссылке: PNWX
Yale School of Art
Сайт Йельской школы искусств выделяется необычным и аляповатым дизайном, сложным для восприятия. Он включает множество элементов, которые перекрывают друг друга и остаются плохо различимыми на ярком фоне.
Доступен по ссылке: Yale School of Art
LingsCars.com
Сайт LingsCars.com – образец того, как делать не нужно. Компоновка разнообразия оттенков, много анимации и перегруженность информацией существенно усложняют восприятие. Правда, проект позиционируется в качестве «самого сумасшедшего сайта по лизингу автомобилей» – так оно и есть.
Доступен по ссылке: LingsCars
Arngren.net
Arngren.net – классический пример сайта с чрезмерным количеством информации на одной странице. Пользователю трудно ориентироваться из-за перегруженности различными элементами и предложениями.
Доступен по ссылке: Arngren.net
Suzanne Collins Books
Официальный сайт писательницы Сьюзен Коллинз, автора трилогии «Голодные игры» и экранизированного в прошлом году приквела «Баллада о змеях и певчих птицах», имеет совершенно несовременный дизайн. Здесь неудобные навигация и расположение основных элементов, незапоминающаяся цветовая гамма и изображения низкого качества. Такое ощущение, что он был создан в начале 2000-х.
Доступен по ссылке: Suzanne Collins Books
Эти примеры демонстрируют, как ошибки, некорректная реализация и отказ от обновлений делают сайты неудобными для обычных пользователей.
Мемоизация селекторов в Zustand
Если вы используете Zustand, то знаете, что computed значения реализуются с помощью селекторов.
const userPrs = useChartsStore((state) => {
return state.pullRequests.filter(pr => pr.author.id === state.user.id);
});
В примере выше:
- при каждом обновлении стейта значение селектора будет вычисляться заново
- это приведёт к ре-рендеру компонента, так как каждый раз мы постоянно возвращает новый массив по ссылке, а по-умолчанию используется строгое сравнение (old === new).
Чтобы решить эту проблему в Zustand есть хук useShallow , который сделает “поверхностное” сравнение предыдущего и нового значения. Если они равны — ре-рендер не произойдёт.
const userPrs = useChartsStore(useShallow((state) => {
return state.pullRequests.filter(pr => pr.author.id === state.user.id);
}));
Но при этом селектор всё равно выполнится, и в большинстве случаев нам не нужно об этом заботиться. Проблема появляется если выполнение селектора занимает много времени или же он вызывается много раз в различных компонентах или других селекторах.
Автор Zustand упоминает, что можно нарушить согласованность данных и просто положить вычисляемые данные в стейт (но в этом случае нужно вручную следить за их актуальностью).
Также он отмечает, что для этих целей можно использовать метод memoize из его библиотеки proxy-memoize (для redux есть reselect).
Аналогично immer’у proxy-memoize работает на основе Proxy. memoize запоминает предыдущий параметр функции и свойства к которым обращались в селекторе (для этого и нужен Proxy). При следующем выполнении функции, он проверит изменились ли используемые свойства, если нет — вернёт значение, вычисленное в прошлый раз.
const authorSelector = memoize((state) => state.pullRequests.filter(pr => pr.author.id === state.user.id));
const userPrs = useChartsStore(authorSelector);
Конечно, нужно помнить, что мемоизировать можно только “чистую” функцию — если она возвращает одни и те же значения в ответ на одни и те же аргументы
Так, обернув пару селекторов в memoize, я ускорил фильтрацию пул-реквестов в более чем 20 раз (900мс ⇒ 40мс).