Так сегодня удалось поймать "гонку" между запросом на получение профиля организации сотрудника и запросом на правила перевозок, этим сотрудником выставленные (последний использует ограничения на доступ к прогнозам, которые даются не только лишь всем)
Так сегодня удалось поймать "гонку" между запросом на получение профиля организации сотрудника и запросом на правила перевозок, этим сотрудником выставленные (последний использует ограничения на доступ к прогнозам, которые даются не только лишь всем)
Потому что есть вариант еще изящнее, реализуемый через - private static и нативный жабоскриптовый Class.
На первом обращении вызывает конструктор класса, а в самом классе отводим приватное статическое поле, куда кидаем созданный инстанс
И потом, если у нас уже есть инстанс, просто тянем из него затребованное поле по ключу
Корневой компонент App.vue и точка монтирования main.ts/index.ts обычно выстреливают последними. Если нужно на самом запуске SPA, еще до авторизации и запроса разных служебных данных (словари, например) получить состояние среды, лучше отвести для этого отдельный модуль, который только и делает, что цепляет из внешнего источника (cookie, get-параметры и т.д) нужные параметры.
И импортить его в тех местах, где эти параметры применяются. (После 9-и часов плодоношения скудоумием до меня дошло, что тут срабатывает такой паттерн
environmentStore = {key1: val1, key2: val2..., isReady: false }
initStore() {
if (environmentStore.isReady) return;
// Вот взяли и откуда надо прочитали параметры любым известным способом
environmentStore.isReady = true;
}
getKey(key) {
if (!environmentStore.isReady) initStore()
return environmentStore[key]
}
Придумать менять id/primary_key сущности после любой операции обновления - это надо еще постараться. Причем как сама операция правки сущности реализована - отдельная песня. Мы не будем просто менять старые поля, заполняя их новыми значениями. Нет, мы создадим новый элемент, скопируем в него поля из старого, затем обновим актуальными значениями, а старый элемент удалим.
Благо, что и до этого момента я вовсю пользовался временными id(которые сам и генерил на клиенте) для склеивания нескольких мутаций GQL в один запрос (там нужно обеспечить уникальность каждой уезжающей пачки исходных данных, как в этом примере). Так вот, теперь эти временные id пригодились для опознания
Еще один вариант реализовать компонентный (a-la React/Vue) подход в чистом нативе.
Зачем - натягивание и кастомизация CMS или готовых сервисов, где слишком многое прибито гвоздями, и развернуть SPA здорового человека не позволят.
Как:
- Пишем <template>-ы с разметкой нужных нам глубоко кастомных элементов, закидываем их в JSON
- В точке монтирования подгружаем через fetch джсон с шаблонами, создаем временный элемент и через него (точнее, через innerHTML) цепляем все эти темплейты в head исходной страницы
- Пишем классы (ну или по-старинке через prototype) функции, которые вытягивают из head шаблоны, насыщают их обработчиками и монтируют в DOM
Это я к тому, что мы уже начали новый проджект с авторизацией через keycloak, а там возможности по визуальной кастомизации достаточно ограниченные. И поскольку каждая стадия авторизации - это отдельная страница со своим url-ом, то SPA тут никак не проканает.
Ну и классы из п3. можно будет потом закатать во вьюшные компоненты, а готовую часть темплейта для SFC скопипастить напрямую из джсона с шаблонами. А еще я понял, что реально соскучился писать код на нативке
Причем нет, не по работе, по сайд-проджекту. И вроде бы сроки ничем не ограничены, но я физически ощущаю это расхождение и не могу отвлечься от него.
А потом удивляюсь, что как-то подустал слегка
Самая основная
function setIntegrator(variation = null) {
const workerData = variation ? {...TEST_DATA, variation } : TEST_DATA
const integrator = new Worker(PHYSICS_PATH, { workerData })
return new Promise(resolve => {
integrator.on('message', (data) => {
resolve(data)
integrator.unref()
})
})
}
async function testRun(variationRange = []) {
const hasVariants = variationRange.length > 0
const integratorPool = variationRange.length ? variationRange.map(v => setIntegrator(v)) : [setIntegrator()]
const res = await Promise.all(integratorPool)
res.forEach((resData, index) => {
const keyPrm = hasVariants ? variationRange[index].key : 'basic'
fs.writeFile(`./result_reentry_${keyPrm}.txt`, resData)
})
}
(еще есть ответная магия в исполняемом воркере, но она скучная)
А это—выдаваемые резалт. Срез по высоте/дальности глиссирования. В самой нижней точке можно представить, как двадцатитонная туша из нержавейки, отсвечивающая по краям тускло-вишневым, с мультяшным звуком "пинг" отскакивает от плотных слоев атмосферы. И да, я бы эти четыре варианта ручками подбирал бы минут 40.

Берем
Вот конкретно сейчас интересно, а на какой высоте чему-то RASCAL-образному нужно выходить на полку, втапливать на полную ручку газа и разгоняться, пока лопатки не поплавятся. Слишком низко - большие расходы воздуха обнулятся возросшим же сопротивлением, придется съесть много горючки, а в более плотном воздухе будут большие тепловые потоки. Слишком высоко - разгон будет идти в час по чайной ложке, потому что тупо не хватит воздуха

Вот понять бы еще, как именно нужно балансировать дерево при движении и возникновении/удалении частиц внутри. Но это уже отдельная история. А пока лучше докрутить интерфейс и выложить в гитхабчег.
P.S.
VS LiveServer очень удобен для поднятия минималистичного локалхоста. Рекомендую там, где есть минимальная структура из mjs, но нет нужды поднимать монстров из node.http или express.
Пример - содержательная и приятная статья про квадрево(Кресты, но я без напряга перевел на родной жабоскрипт)
P.S.
Итоговый переходом от древа к плоскому массиву - это шаг вперед относительно остальных найденных реализаций этой же структуры
А именно - стартап является организацией, которая получает кратковременное преимущество через вынос энтропии в будущее
Например, можно отказаться от документации и очень неплохо выиграть на скорости внедрения фичей, потому что ТЗ на фичи согласуется по мере их реализации
Или отказаться от обсуждения и проектирования архитектуры, заменив ее копипастой компонентов с их минорной доработкой. За счет чего успеть по срокам и вкатиться в IPO. Никто ведь не смотрит под капот.
Но потом начинается долгосрочный период, и с кодом нужно знакомить как новых сотрудников, так и олдам вспоминать, а зачем в функции X прокидывается параметр Y. Причем документация - это не только отчеты (их все равно читают только в самых экстремальных ситуациях). Документацией здорового человека может быть упоминание в коммите номера задачи в таск-трекере или подробный и соответствующий спеке JSDoc.
А копипаст компонентов выстреливает…ну, например, раздуванием базы кода и необходимостью одновременно вносить точечные правки сразу во все связанные модули.
Выводы - а ничего нового. Рефактор неизбежен, люди, утверждающие, что "надо сразу писать годный код" идут фпень, т.к критерии жизнеспособности кода на разных этапах проекта различаются диаметрально, документация нужна, но есть множество способов реализовать ее куда более годно и содержательно, чем писать отчет, который обязательно оценят
К примеру, достаточно plain-text описания над каждым полем интерфейса( тип/енам тоже сойдут) *.ts в комментарии произвольной длины
/** это описание интерфейса */
interface SomeInterface {
/** это описание поля интерфейса */
someInterfaceField1: FieldType
/** это описание еще одного поля интерфейса */
someInterfaceField2: FieldType
}
чтобы они вылезали в подсказках VSCode.
Аналогично работает описание входных параметров и выходов функции в JSDoc, которое тоже переходит в подробную подсказку.
Решил не очень масштабную, но концептуально интересную задачу.
Есть большое SPA-приложение, в нем идет обмен данными под грибамиgraphQL. Проблема - graphQL разросшийся, и без подсветки синтаксиса непонятно, какое поле что значит, откуда берется и какого типа данными запитывается.
Но ладно, пишем под каждую схему конфиг (поначалу хотелось сгрести все двумя регулярками - одну под схемы другую под клиентские описания запросов/фрагментов/мутаций, но VSCode-graphQL начал путаться и просить, чтобы ему явно дали соответствие "схема-описание").
А потом мне вдруг было видение, что этот же конфиг подходит и для недавно восстановленного скрипта автогенерации (через либу graphql-codegen.js) типов и запросов.
Чтобы была уверенность, что одни и те же схемы вытаскиваются из одних и тех же путей, а также есть возможность адресно обновлять не все схемы разом, а прицельно - только одну, по имени.
А концептуально здесь прикольно то, что я написал конфиг(json с маппингом схема→адрес для скачивания схемы→документы для схемы) для конфига graphql.config.json, который генерирует описания типов typeScript(*.d.ts, что тоже конфиг в своем роде ). Потому что нужно увеличивать глубину рекурсии. И делать это рекурсивно.
Одной из первых задачек на новом месте стало восстановление системы оповещений об обновлении нашего ПО для логистов. Принцип прост - на клиенте молотит service-worker, кэширует активные скрипты и ЦСС, при необходимости загружает и кэширует актуальные. Само собой, поскольку у нас все стильно-модно-молодежно, то воркер не самописный, а автосгенеренный через либу vite-plugin-pwa.
Первый этап восстановления был прост и прямолинеен - раскомментировать заглушенный 2 года назад компонент, который показывает приглашение обновиться, затем уточнить конфиг vite и немного изменить вызываемые функции vite-plugin-pwa. Потому что как оказалось в процессе, мы юзали уже давно deprecated-методы.
И поначалу все было хорошо, на тестовых стендах появлялись всплывашки, приложение обновлялось, но когда дело дошло до установки на прод, то начались чудеса. Иногда. Не всегда и не у всех, но плагин начал вести себя (в)с(т)ранно. Где-то он делал вид, что не может вытянуть скрипт или стили с 404 (анализ нетворка показывал, что он пытается загрузить уже неактуальный скрипт из предыдущей версии, который по имени из-за автоподставляемого хэша не соответствовал актуальному), где-то страница просто не перезагружалась после клика по кнопке "обновить" и запуска якобы обновляющей функции, которую предоставляет vite-plugin-pwa.
И "не у всех" и "не всегда". Приложением пользуется ~ 50 человек. Траблы возникали суммарно у ~ 4-5 человек от общего числа. Каждый день - у разных юзеров. На тестовых стендах ошибка тоже ведет себя как "плавающая". Кстати, гипотеза с тем, что проблему вызывает конфликт имени из-за автосгенеренного хэша, тоже не подтвердилась. И я начинаю понимать человека, который закомментировал эту фичу. Возможно, придется в обход писать самописный воркер (благо, вайт-плагин-пва позволяет отказаться от автогенерящегося варианта). Возможно, придется вообще решать эту задачу не через воркер, а через комбинацию localStorage и...ну сопоставление версии, прокидываемой в package.json и той, что у юзера в ЛС сидит.
Проблема всратая, но ведь ради этого мы и работаем, потому что решать не-всратые задачи становится скучно. Думаю, предыдущий кодер был бы рад, если бы узнал, что я примирил
Поскольку для страницы, собранной целиком из статики, всякие node.http и express будут излишними, и городить под капотом полноценный сервер с обработчиками месседжей на порт только ради отладки - неоправданный головняк.
Причастиццо сабжу
Итого:
- получено 3 активных оффера
- актуализированы требования к должности разработчика-фронта на 2к24
- удалось очертить собственный грейд и понять, в кого дальше эволюционировать
- Стало ясно, какие технологии нужно еще осознать (Docker, nodeJs-http (это нативка), nodeJs-express (а это уже либа с улицы), React)
- Асинхронка (воркеры/треды/кластеры) - это действительно важно и востребовано
А теперь мне нужно восстановиться после всего этого нервяка, так что йа начну с музыкальной паузы
Можно уже не страдать по
JSON.parse(JSON.stringify(жертва клонирования))
. Потому что есть structuredClone
, делающий то же самое без лишней возни с преобразованием в строки и обратным парсингом.Но любопытства ради я бы посоветовал написать рекурсивный клонировщик (учтем, что ссылочные данные - не только объекты, но и массивы)
А у меня через полчаса очередной собес
Все-таки Vuex, каким бы чудесным не казался, стал реликтом хотя бы из-за отсутствия поддержки TS "из коробки". Есть способ решить эту проблему закидыванием в рутовую директорию проекта вот такого заклинания под именем vuex.d.ts:
declare module "vuex" {
export * from "vuex/types/index.d.ts";
export * from "vuex/types/helpers.d.ts";
export * from "vuex/types/logger.d.ts";
export * from "vuex/types/vue.d.ts";
}
А еще - тяжеловесность и отсутствие встроенных способов превращения полей стора в реактивные переменные - только явно через ref/computed.