Павел Лосев

Павел Лосев

Темы
Неделя
Aug 24, 2020 → Aug 30, 2020

Архив недели @v1rtlize

Понедельник


Всем привет! Я Павел Лосев (@v1rtlize), мне 16 лет, я веб-разработчик, занимаюсь Open Source. Также веду довольно популярный канал по JavaScript (t.me/we_use_js). На неделе буду рассказывать про Native ESM, мультитрединг в Node.js, React + 3D и проблемы легаси в JS.

Из опенсорса на данный момент пишу свой веб-фреймворк - tinyhttp - более быстрый и современный аналог Express, и участвую в разработке react-postprocessing - React обёртки вокруг postprocessing (JS либы для пост-обработки в 3D).

ссылки: tinyhttp: github.com/talentlessguy/… react-postprocessing: github.com/react-spring/r…

Помимо опенсорса работаю над закрытыми проектами для клиентов из России (и США). Делал простые сайты для российских заказчиков и лендинги для американских. Сейчас вот клепаю фронт для интернет-магазина цветов для клиента из Уфы.

Так как я в силу своего возраста нигде оффициально пока не работал, мне очень редко приходилось сталкиваться с легаси, поэтому в течении недели будет много о новых и экспериментальных штуках.

Опечаточка, мой профиль: @v1rtl

🔥Тред (Павел Лосев)

Вторник


Первой темой будут системы модулей в JavaScript. На данный момент самые популярные - это ECMAScript Modules (ESM), CommonJS и UMD. Узнаем кто такие эти ваши модули, почему у JS аж 3 (и более, если считать легаси) модульные системы, и как там у ESM в Node.

Самое простое определение: модуль — это переиспользуемый кусок кода, который содержит реализацию API. Обычно это кусок кода, который экспортирует функционал, чтобы позже его мог импортировать другой кусок кода. Вроде разобрались, теперь немного истории.

Давным давно, ещё до существования Node.js и ES6, в JavaScript не было никакого другого способа разделять JavaScript, как добавлять глобальную переменную, указывающую на библиотеку.

Таким образом работает IIFE (Immediately Invoked Function Expression) - он сразу же вызывает ф-цию с обёрнутым модулём и создаёт глобальную переменную, которая содержит весь функционал либы. Включить такую библиотеку было довольно легко, всего лишь надо подключить <script>.

У такого подхода очевидно было много проблем - неудобство управления зависимостями и загрязнение глобального пространства.

Были вспомогательные модульные системы по типу System.js и AMD (Async Module Definition), но это не было стандартом, т.к. всё это требовало загрузки ещё одного скрипта самой модульной системы.

В 2009 появилась такая штука как Node.js. И у неё тоже появилась своя модульная система, которая называется CommonJS (это который require). Очень активно используется до сих пор, и появилась она опять же ввиду того, что не было стандарта модулей. Пришлось изобретать своё.

Помимо уже трёх самых популярных IIFE, AMD и CommonJS появилась ещё одна система, которая объединяет в себе сразу все 3 - UMD (Universal Module Definition). До сих пор очень популярный сегодня формат. Нашёл статью с примером того, как выглядит UMD внутри: syntaxsuccess.com/viewarticle/ii….

И вот наступает 2015... выходит ES6, в которой наконец-то появились модули. Теперь вместо поддержки 4х систем модулей можно будет использовать одну, но нет!

Из-за того что модули вошли в язык как стандарт довольно поздно, до сих пор абсолютное большинство JavaScript кода в конечном счётё использует либо UMD (в основном на фронте, но и на бэке тоже), либо CommonJS (на бэке).

Вернёмся к ESM. Благодаря тому, что в ESM существуют именованные импорты, сборщикам гораздо проще делать tree-shaking - включение в бандл только того, что импортировалось.

Это касается только сборщиков, насколько я знаю в Node.js рантайме никакого tree-shaking нет, но им можно воспользоваться при помощи сборщиков (Rollup).

А что там у ноды? В Node.js (без флагов) ESM появился только лишь в 2019 году в версии 13.2.0. Чтобы запустить файл с ESM, нужно поменять расширение на .mjs, или добавить "type": "module" в package.json и продолжать юзать .js. И тогда для CJS модулей использовать .cjs.

В чём смысл Node ESM? Во-первых, это следование стандарту (и унификация BE и FE кода). Во-вторых, именованные импорты, то есть вместо экспорта объекта в CJS (module.exports = { a, b }), можно экспортировать их сразу, без всяких объектов (export const fn = () ⇒ { ... }).

Однако, не всё так просто с ESM. Большинство модулей всё ещё CJS-only. Т.к. CommonJS не умеет в именованные экспорты, импортировать CJS модули приходится через import mod from 'mod'. Node.js их спокойно хавает из импортирует внутри вашего ESM кода.

Ещё есть один важный момент - в относительных путях всегда надо указывать расширение файла, иначе будет Cannot find module. Ещё и вдобавок это не будет работать с CommonJS (если попытаться импортировать ESM в CJS). Для решения этих проблем в Node.js было добавлено поле "exports".

Это поле позволяет инкапсулировать модуль, и экспортировать только определённые файлы, без всяких расширений. Причём можно везде прописывать фоллбеки на CommonJS, чтобы ваш модуль работал как и в старых, так и в новых версиях Node.js.

Пример заполнения такого поля: github.com/talentlessguy/…

Теперь надо подумать, как это всё собирать, чтобы не писать параллельно несколько файлов для CJS и ESM? Существует море сборщиков, которые могут облегчить это дело, генерируя сразу 2 версии из одного исходника.

Из самых популярных можно взять Rollup. esbuild также поддерживает как CJS так и ESM. Лично я использую обёртку над esbuild - tsup. Там легче указывать флаги, и ещё можно генерить типы после компиляции (esbuild пока не поддерживает .d.ts генерацию).


ещё вспомнил - microbundle: github.com/developit/micr…

Я сейчас коллекционирую модули с Node ESM поддержкой, если кому интересно (добавить свой / посмотреть), то вот ссылка: github.com/talentlessguy/… Не очень густо, т.к. как я говорил ранее, 90% модулей только на CommonJS

Вспомнил ещё один приём, чтобы не собирать две версии отдельно, можно импортировать CJS в ESM и потом прописать именованные экспорты nodejs.org/api/esm.html#e… Довольно годный вариант, чтобы ничего не собирать Но это только для JavaScript библиотек, у TS легче dual bundling

@jsunderhood Ещё одно дополнение (zanuda mode on). CommonJS как инициатива по разработке унифицированных API (не только модулей) появилась до Node.js. Node.js взял оттуда только модульную систему. Вся инициатива сошла на нет, и CommonJS стал означать только модульную систему
Поправочка, CommonJS существовал до Node.js twitter.com/myshov/status/…

@jsunderhood Может я не понимаю слово «вспомогательные», но в своё время AMD очень мощно конкурировал с CommonJS, и никогда себя не позиционировал как служебный формат модулей (в отличие от System.js)
Тут ошибка, AMD можно было собирать бандлером (через r.js), а не только через лоадер twitter.com/myshov/status/…

🔥Тред (Павел Лосев)

Среда


Второй темой будет многопоточность в Node.js. Как известно, изначально рантайм работает в одном потоке, используя только одно ядро процессора. В 90% случаев одного ядра хватает, но когда у вас хайлоад API, и ~45K req/s не хватает, то можно использовать мультитрединг.

Из встроенных модулей самым подходящим для веб приложений будет cluster. Суть cluster в том, что он позволяет запускать программу на JavaScript в нескольких процессах, работая на более чем одном ядре процессора.

Внутри себя использует child_process.fork() для создания форк-процессов и работает по алгоритму Round Robin (это когда есть очередь процессов, где каждый процесс запускается и находится в очереди пока не выполнится). Ссылка на реализацию внутри самой ноды: github.com/nodejs/node/bl…

В backend приложениях без БД, cluster легко интегрировать, нужно сделать проверку на то, что процесс является мастером - и если да, то сделать форк-процесс N раз (где N это число ядер), а если это не мастер то запускать это самое приложение. Но у тредов есть подводные камни...

Один из самых известных - синхронизация. Проблема в том, что потоки работают ассинхронно, а доступ к значениям происходит синхронно. Или несколько потоков могут сделать одно и тоже, например дважды сделать запись в БД. Из-за этого ваше приложение становится непредсказуемым.

Одно из решений - mutex. Они блокируют поток в критическом месте, и позже разблокируют его, чтобы ничего не поломать. В C++ например, есть std::mutex, а в JavaScript есть огромное количество npm пакетов, которые по-разному mutex реализуют: Mutexify, Async Mutex

ссылки: Mutexify: npmjs.com/package/mutexi…, Async Mutex: github.com/DirtyHairy/asy…

Дело в том, что mutex'ы полезны только когда у процессов есть общая память. Общая память у процессов в другом модуле - в worker_threads. В cluster'е у каждого своя собственная, поэтому нужно использовать что-то более глобальное.

Т.к. в cluster у каждого процесса своя память, то нужно использовать распределённое блокирование (distributed lock). Если вкратце, то распределенная блокировка - это механизм, который обеспечивает управление потоком в контексте, в котором действуют более чем один процесс.

Необязательно это должен быть многопоточный сервер, ещё один юзкейс это когда у вас много инстансов бэка запущены на разных машинах, но используют одну и ту же БД. Пример реализации distributed lock на Mongoose: github.com/coyotte508/mon….

Из простых решений для кластеризации Node.js приложений (без использования cluster в коде, и не учитывая БД) можно использовать менеджеры процессов, например pm2 (pm2.io). Он использует cluster под капотом. Ещё недавно узнал про forever (github.com/foreversd/fore…).

Мультитрединг - довольно обширная тема, в которой у меня есть небольшие знания. Недавно я был в IT лагере (goto.msk.ru) (я там был, дважды), у нас был курс по lowlevel, и там ещё был мультитрединг на C/C++. Часть этих полученных знаний я применил в этом треде.

Я мог перепутать термины - речь в треде идёт об использовании потоков (форк-процессов (надеюсь я хотя бы это правильно назвал)) в Node.js, и как их синхронизировать в бекенд приложениях Если я где-то ещё перепутал - киньте в реплаи правку и я сделаю ретвит

@jsunderhood В результате вызова cluster.fork() создаётся процесс, а не поток. Отличие в том, что процессы друг от друга изолированы. Cluster с воркерами и несколько отдельных серверов за nginx - принципиально одно и то же: воркеры не делят память, обмениваются между собой через IPC.
В самом первом твите ошибка - то что описывается ниже это не мультитрединг. Это процессная многозадачность (поправьте если ещё раз ошибся) - в cluster спавнятся не потоки, а отдельные процессы со своей памятью. Общая память в worker_threads twitter.com/maxatwork/stat…

(сделал ретвит правки с моим комментарием если вдруг кто не так понял)

@jsunderhood У worker_threads не общая память, а возможность работать с shared memory для коммуникации. Фактически же это те же самые отдельные копии node.js процессов, живущие каждый в своём изолированном мире.
ещё одна ошибка прямо в этом твите))) в worker_threads не общая память, а shared memory twitter.com/amel_true/stat…

Поправка - не общая память, а память, которой можно обмениваться через SharedArrayBuffer

🔥Тред (Павел Лосев)

Четверг


Сегодня будет тред про legacy (англ. наследие) в мире JavaScript. Под легаси я имею ввиду старые фреймворки, модули и библиотеки, которые до сих пор очень активно используются, несмотря на то, что 80% API уже есть в языке / рантайме.

Думаю, что тред получится довольно субъективным (т.к. для многих это не проблема вовсе), но постараюсь опираться на факты.

Сначала подумаем, почему вообще возникает легаси. По моему мнению, оно появляется ввиду того, что JavaScript очень быстро развивается, как экосистема, так и сам язык.

Логично, что более старые фреймворки (например jQuery для фронта, или Express для бэка) будут популярнее новых, просто ввиду того что у них было больше времени на развитие и рост популярности.

В то время, когда появлялись эти библиотеки, JavaScript был не настолько развит, или просто хотелось использовать какой-то метод из спеки (или даже не из спеки, но потом там появилось), который ещё не поддерживался рантаймом / браузерами.

К примеру, возьмём Object.setPrototypeOf. Метод был добавлен в ECMAScript в 2015 году, а ES2015 стал полностью поддерживаться только с версии Node.js 0.12.18, но нужно было поддерживать ещё более старую версию ноды...

Такой случай у Express, он включает в себя этот полифилл, но зато поддерживает 0.10 версию. Как видим, у setprototypeof 22M скачиваний в неделю...

И поэтому приходилось добавлять полифиллы – фичи языка, которые ещё не добавлены в спеку ECMAScript (или в Node.js), но которые можно вручную воссоздать и использовать.

С полифиллами есть одна большая проблема. Большинство полифиллов рано или поздно становятся ненужными, потому что JS очень быстро развивается, и большинство часто используемых методов либо уже были добавлены, либо будут добавлены в ближайшем будущем.

Ещё одна проблема – бессмысленная поддержка старых версий браузеров и ноды. Некоторые фреймворки стараются работать даже на древних версиях (Express работает на Node 0.10), при это используя огромное кол-во зависимостей, несмотря на то, что эти фичи уже как несколько лет в ноде.

В браузерах похожая ситуация, бандлеры целятся на поддержку ES6 (и ранее), запихивая бесполезные полифиллы в бандл. ES6 это стандарт 2015. На момент написания треда 2020. То много фичей от 2015 до 2020 заменяются полифиллами (или просто подгружаются в случае если таковых нет).

Не имеет особого практического смысла целиться на версии браузеров 5-ти летней давности. Но сборщики и компиляторы при этом до сих пор ориентируются на них. В следствие чего, имеем кучу мусора в бандле, которого могло и не быть.

Конечно, это всё можно настроить, но дефолтные настройки @babel/preset-env не так часто меняют. Теперь подумаем, что можно сделать с этим "наследием", на обоих концах (фронт и бэк).

На фронте можно попытаться избавиться от легаси несколькими способами. Во-первых, не использовать старые фреймворки, а ориентироваться на то что актуально сейчас. jQuery до сих кладёт в сборку $.each, хотя уже как 5+ лет существует Array.forEach (github.com/jquery/jquery/…).

Вместо жиквери можно либо переключиться на современные ремейки (например cash.js), либо использовать популярные UI библиотеки по типу Preact (preactjs.com/about/browser-…), который активно развивается до сих пор, и не ориентируется на совсем устаревшие браузеры.

Также, как было упомянуто раньше, желательно целиться на новые браузеры версий прошлого или позапрошлого года, в случае если ваши пользователи это люди, например Firefox 65, Safari 12.1 и Chrome 64. Может помочь сэкономить несколько десятков (или сотен) байтов.

На бэке размер кода не так важен, потому что он влияет только на parse time. Я не знаю каких-то особых способов избавления от легаси, как просто поменять фреймворк / библиотеку на современный аналог. Обычно на gh есть несколько аналогов популярным библиотекам.

Среди веб-фреймворков, относительно современные это Koa, Fastify, Polka. Если вам не хочется расставаться с API Express'а, можно попробовать мой фреймворк - tinyhttp. Он пытается быть ближе к Express, не делая кардинальных изменений снаружи (как например это сделала Koa).

ссылка на фреймворк: github.com/talentlessguy/…

тут кусок текста съехал, вот правильный вариант: "Обычно много фичей от 2015 до 2020 заменяются полифиллами (или просто подгружаются рядом в случае если API уже есть в браузере)."


и Koa, и Fastify, имеют большое комьюнити (tinyhttp пока таким не обладает :D) так что не нужно бояться что вам никто не поможет с переходом на новые фреймворки

(под проблемой имеется ввиду что куча ненужного кода идёт в рантайм / бандл в зависимости от среды)

завтра про него будет подробный тред с историей создания, зачем, и как начать пользоваться уже начал рисовать черновик

*писать а не рисовать )))

🔥Тред (Павел Лосев)

Пятница


В продолжение вчерашнего треда, хочу рассказать о том как я пишу свой веб-фреймворк - tinyhttp. Опишу зачем я решил его делать, с чего начал его писать, как настроил тесты, CI и покрытие. Покажу как начать им пользоваться.

Ссылка на фреймворк, если кто не читал прошлый тред: github.com/talentlessguy/…

Начну с проблемы. Вчера в треде про легаси я написал, что несмотря на то, что Express стар, он всё ещё самый популярный фреймворк для Node.js. До сих пор Express использует довольно много устаревших модулей, чтобы поддерживать Node 0.10

Из проблем, не связанных с легаси, можно выделить отсутствие типов в самой либе (нужно ставить @types/express), отсутсвие поддержки ассинхронных обработчиков, и нету ESM экспортов.

Ещё одна субъективная проблема - код самого Express очень огромен и стар, в нём тяжело копаться. По крайней мере для меня, смотреть как работает next() в Express внутри было довольно тяжело. Возможно я просто плохо читаю чужой код ¯(ツ)/¯

Так вот, я захотел написать свой фреймворк, который был бы такой же как Express, но с поддержкой TypeScript, async / await и ESM. Т.к. у меня до этого не было опыта написания BE фреймворков, я начал изучать внутренности Express.

Читать было довольно тяжело, т.к. кода было очень много. Я решил поискать какие-то клоны Express с более простым кодом, и наткнулся на Polka. Polka это маленький веб-фреймворк, у которого промежуточные обработчики как в Express, и к тому же он ещё и сильно быстрее Express.


Для инструментов разработки решил взять pnpm, Rollup и changesets. pnpm - это пакетный менеджер, который переиспользует зависимости, очень хорош для монорепозиториев. Хотя я его использую сейчас везде, чтобы не тратить диск на мусорный node_modules.

Rollup для сборки модулей в ESM и CommonJS, changesets для автоматического апргейда версий, и зависимых модулей. Позже я заменил Rollup на tsup, чтобы быстрее собиралось. Для changesets я написал npm скрипт чтобы всё собиралось, апгрейдились версии и генерился Changelog.

Ссылки: tsup - github.com/egoist/tsup changesets - github.com/atlassian/chan…

Для CI я выбрал Github Actions, для тестов Jest и покрытия - Codecov. Мб это я такой криворукий, но он у меня не раз глючил, зависал на 5 часов билд, хотя все тесты были прогнаны, и при реране тестов всё становилось нормально.

При всём этом, пока что планирую юзать их, чтобы оставаться внутри экосистемы GitHub. На днях ещё попробовал настроить кэширование, и смог закэшировать node_modules, чтобы pnpm быстрее ставил пакеты. Не было прямо огромной разницы, вроде как там на несколько секунд стало меньше.

Ссылка на конфиг GH Actions: github.com/talentlessguy/…

Базовую рабочую версию tinyhttp я набросал довольно быстро. Только у этой версии не было поддержки next(). Сначала я попытался переписать алгоритм применения обработчиков, сделав его через рекурсию (app.handle вызывал самого себя) - получилось не очень.

Не из-за того что там рекурсия, а потому что в обработчик применялся дважды, и next() всё ещё неправильно работал.

Немного подустав, я подумал что лучше посмотреть как это делают другие фреймворки (реализуют next() и применяют обработчики) и начал читать код Polka. Там алгоритм проще чем в Express, и легче его понимать.

Решил взять его за основу, который тоже использует рекурсию, но внутри app.handle, а не сам app.handle.

Реализация в Polka: github.com/lukeed/polka/b… Реализация в tinyhttp: github.com/talentlessguy/…

Параллельно с написанием нормального применения обработчиков, я начал фигачить расширения для req и res , котрые есть в Express. Некоторые простенькие я написал сам, некоторые более сложные (типа res.send) я подсмотрел в коде Express, чтобы не наделать всяких ошибок.

Частично фреймворк был готов, не ломался при запуске, теперь надо было подумать где размещать доку. И я начал делать сайт для tinyhttp. Ещё где-то ранее зафигачил логотип. На главной странице я набросал то, как начать пользоваться tinyhttp, и перечислил фичи.

Ещё я начал делать документацию со всеми описания методов и свойств App, Request и Response. Также начал писать Learn Guide, но до сих пор не закончил. Фигачил сайт конечно же на tinyhttp. Вместо шаблонизаторов временно юзаются Transform Streams для замены внутри HTML.

Для раздачи статики сначала был использован самописный @tinyhttp/static, но оказалось что у него есть несколько багов (которые я в будущем исправлю), и поэтому перешёл на serve-handler. Недавно заменил его на sirv, у него и типы есть, и он поменьше будет.

Сайт всё ещё в процессе создания, потому что нужно поправить некоторые моменты в доке, и дописать гайд. Сейчас можно использовать как референс, хоть он и неполный пока что.

Теперь перейдём к тому, как начать им пользоваться. Если вы хотите использовать ESM синтаксис, то в корне проекта нужно добавить поле "type": "module" и импортировать через import { App from '@tinyhttp/app' }. Если нужен CommonJS, то const { App } = require('@tinyhttp/app').

В остальном, работает идентично Express, за исключеним того, что настройки указываются в конструкторе App: tinyhttp.v1rtl.site/docs#settings

Большинство обработчиков Express будут работать без ошибок в tinyhttp, но для того чтобы не использовать обработчики с легаси зависимостями, в репе tinyhttp имеется набор обработчиков. Среди них логгер, JWT , CORS, и т.д. Полный список тут: tinyhttp.v1rtl.site/mw

Ещё рекомендую прочесть вот эту маленькую статью, если нужно пошаговое введение (а ещё там показано как правильно ошибки обрабатывать внутри async / await): dev.to/talentlessguy/…

Из планов на будущее, нужно написать ещё больше тестов (хотя уже 72% покрытия на момент написания статьи), дописать доку, наделать промежуточных обработчиков и ещё наклепать примеров.

Примеры кстати есть, вот с MongoDB: github.com/talentlessguy/…, вот с GraphQL: github.com/talentlessguy/…. Есть список какие примеры будут добавлены в будущем: github.com/talentlessguy/…

tinyhttp открыт для контрибьютинга, можно предлагать свои идеи и правки, или работать над существующими issues. Самый простой способ внести вклад - это написать пример из списка. Не требует особых знаний, кроме как знаний технологии с которой делается пример, и Express/tinyhttp.

🔥Тред (Павел Лосев)

Суббота


Сегодня будет довольно весёлая и интересная тема - 3D в вебе. Тема довольно популярная, но сложная. Начнём с того, что такое OpenGL, GLSL, THREE.js, и закончим тем, как писать 3D в React и вообще зачем 3D в браузере.

OpenGL - это спецификация frontend-а API для создания 2D и 3D графики. У этой спеки есть несколько реализаций - например Mesa (для Intel в Linux). Роль бекенда здесь играет драйвер GPU, с помощью которого видеокарта вычисляет графику.

CPU отсылает данные по которым должен происходить рендеринг графики (Rendering data), и затем GPU производит рендеринг (через Rendering pipeline). Я тут могу ошибаться, поэтому ниже будет ссылка на статью.

Вот детальная статья с разбором того как графика отрисовывается на компьютере, начиная с OpenGL, заканчивая рендером на видеокарте: haroldserrano.com/blog/how-to-de…

WebGL - это тоже особый стандарт, основанный на WebGL ES (Embedded Systems) 2, который предназачен специально для браузеров, и использующий JavaScript. Для написания программ на WebGL, существует язык GLSL (OpenGL ES Shading Language), который по синтаксису похож на C/C++.

Управление памятью происходит в JavaScript. GLSL выполняется на GPU, используя драйвер видеокарты, как и OpenGL ES 2 реализация (с небольшими различиями). Более подробный разбор того как работает WebGL: webglfundamentals.org/webgl/lessons/…

Если подытожить, то чтобы делать 3D в вебе, нужно писать программы на GLSL и JavaScript. Писать шейдеры не зная того как работает OpenGL, Clang (близкий к GLSL), и не понимая того как работает графика довольно тяжело. Поэтому появились либы для упрощения 3D в браузере.

Самая популярная библиотека - THREE.js. В ней всё разбито на классы, текстуры, объекты, геометрии, освещение и т.д. На ней очень легко и весело писать 3D. Я сам начал погружение в 3D с этой либы: threejs.org

Помимо THREE.js существуют другие менее популярные абстракции над WebGL - Babylon.js (github.com/BabylonJS/Baby…) - JS фреймворк, основанный на WebGL, который включает в себя рендерер и игровой движок, и OGL (github.com/oframe/ogl) - минималистичная WebGL либа, похожая на THREE.

Несмотря на то, что THREE.js сильно упрощает работу с WebGL, всё ещё получается очень много кода. К тому же, его довольно тяжело внедрить в сайты, которые используют UI фреймворки по типу React.

Для решения этих проблем появился react-three-fiber, React рендерер для THREE.js. С помощью react-three-fiber можно создавать декларативные (благодаря React) THREE.js сцены, легко внедрять их в React приложения, и интегрировать состояние (например React Context) с ними.

react-three-fiber ничего не заменяет и не добавляет в THREE.js, а трансформиует JSX в THREE.js код. Любой код на THREE.js можно перенести в react-three-fiber ссылка на библиотеку: github.com/react-spring/r…, там в ридми есть довольно впечатляющие демо

С r3f код выглядит гораздо чище, и на нём ещё проще писать 3D, которое легко потом внедрить в React и смешать с DOM. На основе react-three-fiber появилось несколько библиотек, которые оборачивают библиотеки для THREE.js. Среди них use-cannon, react-postprocessing и react-xr.

use-cannon - это r3f либа с хуками и компонентами для добавления физики в 3D, с помощью библиотеки Cannon.js. Работает в отдельном воркере, поэтому очень производительна, и очень проста в использовании, по сравнению с чистым THREE.js + Cannon.js. Ссылка - github.com/react-spring/u…

react-postprocessing - ещё одна r3f библиотека, которая оборачивает эффекты из либы postprocessing (vanruesc.github.io/postprocessing/) в React компоненты. Как и в случае с use-cannon, сильно упрощает код, и прячет сложные аспекты под капот, оставляя только компоненты, например <Glitch />.

Сейчас демки обновляются, и проводятся работы над оптимизацией, но библиотеку можно использовать уже сейчас. Уже есть довольно впечатляющие демо (делал их не я, но они используют компоненты которые написал я): 3r6l2.csb.app

Ну и напоследок react-xr - ещё один набор хуков и компонентов для создания VR/AR приложений в вебе, при помощи r3f и WebXR. Демки получится посмотреть только с VR шлемом, но если у кого-то есть, то вот одна: v4uet.csb.app

Для чего всё это? 3D имеет несколько юзкейсов по визуализации, например CAD редакторы (SketchUp), презентация товаров или движки для онлайн игр (Unity3D). Но в большинстве случаев 3D используется для искусства. Много дизайн студий используют 3D для лендингов.

Сейчас ещё разрабатывается react-three-flex - <Flex /> компонент для THREE.js будет ещё проще смешивать с DOM, и делать адаптивные сайты в 3D (сейчас с этим туго) либа в разработке, так что пока ловите демо от @giuliozausa:
notion image

🔥Тред (Павел Лосев)

Воскресенье


Вот и закончилась моя неделя в @jsunderhood. Подведу итоги того что рассказывал, подытожу каждый тред, подумаю в чём у меня пробелы и где надо закрепить знания.

На этой неделе как и планировалось, были треды по модульные системы, многопроцессность, легаси, tinyhttp и 3D в вебе. Вроде как каждую тему (за исключением многопроцессности) раскрыл нормально, почти без ошибок и подкрепил всё ссылками.

С многопроцессностью произошёл провал. Я сильно плавал в теме, и у меня в голове смешались знания, не связанные между собой. Я немного знал о потоках в C++ и форк-процессах в C, но оказалось что в Node не треды а процессы, и доку ноды я неправильно понял из-за этого.

Благодарю @amel_true и других, за то что поправили во всех местах в том треде, теперь у меня больше нет путаницы в голове.

Ещё было пару мелких ошибок в треде по модулям, но они произошли из-за того, что меня в то время не было в IT (я начал прогать в 2017), и я таскал инфу по старым статьям из 2013ого. И поэтому часть инфы пропустил. Спасибо @myshov за поправления по поводу AMD и CJS)

Тред по легаси получился довольно субъективным, но в целом вышло норм. Фактических ошибок не было, были только высказаны альтернативные мнения. Я постарался на всё ответить и защитить свой поинт, когда возникали вопросы к моей позиции в вопросе, и выслушать мнения других.

С 3D было проще всего. Большинство определений было легко достать из статей и StackOverflow вопросов (чтобы не допустить фактических ошибок), из остального я просто скидывал ссылки на либы без отстаивания какой-то позиции.

Спасибо всем, кто читал мои треды, и я особенно благодарен тем, кто поправлял)

Я думаю, что мне надо будет углубиться в тему многопроцессности и хайлоада, и прокачать свои знания по бекенду. Пока что они немного хуже знаний по фронту. Но мне ЕГЭ сдавать в этом году.... так что хз когда сяду за бэк углублённо

если кому-то захочется связаться, то я в телеге: t.me/talentless_guy

ещё вот мой github: github.com/talentlessguy

🔥Тред (Павел Лосев)

Ссылки