All streams
Search
Write a publication
Pull to refresh
15
0.1
Альберт Базалеев @supercat1337

User

Send message

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

Когда кто-то выбирает мейнстрим технологию, то обычно ссылается на ее авторитетность в глазах международного сообщества, намекая на то, что миллионы разработчиков не могут ошибаться. Чтобы не выглядеть идиотом, предварительно нагугливается какая-нибудь статья о том, как красиво решается подобная проблема. Собственно отсюда и идет вера в стек. А еще это приправляется вопросом: а кто это потом все поддерживать будет? Ответ будет простым: да кто угодно, кто также верит и интересуется этой же технологией. Самое главное, чтобы технология была от какой-то известной компании, а не ноунейма.

А если пойти по-другому: например, отказаться от мейнстрима, думать своей головой, создать что-то свое, пусть даже командой. То тогда очень возникает очень высокий груз ответственности на автора технологии, который сидит в соседнем кабинете. И до него очень легко добраться и высказать свое фи (в лучшем случае). Никаких преград.

Я прекрасно понимаю о чем Вы говорите. Спасибо за развернутый ответ.

Спасибо за публикацию. Вопрос по поддержке типизации, если уместен.

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

Рекомендую все такие операции проводить только в воркерах - они для этого и были придуманы.

Раньше сталкивался с проблемой определения IPad, так как ua врал как мог. Решение на заметку:

/**  @returns {boolean} */
function isIPad() {
    let ua = window.navigator.userAgent.toLowerCase();
    return ua.indexOf('ipad') > -1 || ua.indexOf('macintosh') > -1 && navigator.maxTouchPoints && navigator.maxTouchPoints > 2
        && navigator.platform !== "iPhone";
}

Math.random никто не использует. В любом браузере сейчас можно так:

const array = new Uint32Array(10);
window.crypto.getRandomValues(array);

console.log("Your lucky numbers:");
for (const num of array) {
  console.log(num);
}

Источник тут: https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues

Причем getRandomValues реализована даже в IE11. https://caniuse.com/getrandomvalues

А если у вас таких сервисов десять тысяч, то придётся делать десять тысяч изменений. Вы всего лишь передвинули один модуль (logger), а менять пути импорта придётся в десяти тысячах скриптов, которые этот модуль используют.

Я пытаюсь донести, что если не хотите указывать все зависимости в виде импортов в ваших пакетах, то можно использовать главный (базовый) модуль-контейнер (аля master of packages), в котором и будет все импортировано один раз. Собственно будет внесено исправление один раз.

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

Далее по поводу проблемы имплементации логгера, а есть ли вообще проблема? Это вопрос конфигурирования ваших сервисов с учетом окружения. Это вообще другая тема.

В дополнение к моему ответу выше (https://habr.com/ru/articles/748132/comments/#comment_25753998) могу сказать, что получившийся service.js, который доступен через window.service является как раз таковым контейнером.

Если мы говорим о "пакетах", то внутри папки пакета вполне допустимо и правильно использовать относительные пути.

Если же речь идет о ситуации, когда один пакет использует другой, и вообще нам нужно гарантировать, что все зависимости будут подключены, то и мой пример вполне годится для этого. Потому что при обращении к service.unknown_packet линтер укажет на необходимость подключения пакета к service.

Раскрою мысль.

Каждый подключаемый модуль пройдет в начале через импорт или его аналог (например, прямое внедрение на страницу через тег script). Это часть жизненного цикла. Ибо откуда он сам по себе возьмется? А это означает, что адрес модуля, его физическое расположение любом случае нужно будет учитывать (даже хотя бы один раз).

Причем эта концепция полностью отражена в моем простом коде service.js, где все модули грузятся только всего один раз и будут доступны в неймспейсе модуля service.js.

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

Нужно больше рантайма? Вот новый код service.js:

import config from './config.js';
import logger from './logger.js';

let service = {config, logger};
window.service = service;

export default service;

Теперь вообще можно не использовать js-импорт в модулях. Но рано радоваться, потому что для работы линтера как бы не пришлось в коде без js-импортов каждый раз указывать jsdoc-импорт типа service.

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

/** @typedef {import("./service.js").service} service */

/** @type {service} */
let service = window.service;

Я задаюсь вопросом: а зачем нам вообще нужен этот конструктор при условии, что в js этот механизм уже реализован через ключевое слово export?

Вот код service.js:

import config from './config.js';
import logger from './logger.js';

let service = {config, logger};

export default service;

Код index.html:

<script type="module">
    import service from './service.js';
    service.logger("test");
</script>

По факту в каждый модуль Вы будете проставлять только одну зависимость от service.js.

Я что-то упустил?

Doctor_IT , у меня профессиональный интерес. А Вы можете поделиться ссылками на некоторые ваши особо сложные Google Docs, которые необходимо было конвертировать в статью на vc.ru?

К сожалению, в публикации примеры документов не указаны.

Вообще такая технология есть и ей лет 15-20 - называется IFRAME. Вставляете IFRAME со всеми нужными политиками безопасности на свои страницы. Тот грузит скрипты внутри себя. Далее получаете ссылку на объект window этого iframe (через свойство iframe.contentWindow) И вперед.

А вообще, общий кеш в браузере вряд ли будет, в первую очередь по причине безопасности. Например, с такой технологией подключить к вредоносному сайту банковский скрипт с данными станет легко, даже куки не надо воровать.

Ресурсы, такие как unpkg.com и jsdelivr.com, в некоторой степени помогают уменьшить дублирование, поскольку если несколько сайтов ссылается на один и тот же ресурс на unpkg.com, то все они будут использовать один и тот же объект из кэша браузера.

Как они помогают? Я бы еще могу согласиться в том случае, если бы речь шла о загрузке таких скриптов через IFRAME. Вот в таком случае мы точно с вами могли бы говорить об экономии трафика. А если идет речь об идентичных прямых ссылках на внешний скрипт на различных сайтах, то кэширование будет распространяться на каждый отдельный ресурс. Посещая таких 2 сайта, идентичный файл библиотеки вы скачаете 2 раза.

почему бы не хранить npm‑пакеты (или хотя бы транспилированные значимые объекты кода) прямо в браузере, учитывая версионность и другие свойства, присущие пакету?

Да никто и сейчас Вам не мешает это делать даже без бандлеров и хранить в браузере. Есть прекрасный механизм import maps, который по сути является картой импортов. Эту карту импортов можно и в ручную писать, если есть надобность, а так видел на npm пакет, который конвертирует package.json в карту.

При проектировании кода, в котором задействованы возможности фреймворка, приходится идти на уступки из-за т.н. инверсии управления (к слову, наличие которой является ключевым отличием библиотек от фреймворков). Поэтому та часть проекта, в которой используется фреймворк, с огромной вероятностью, будет использовать архитектуру, навязанную фреймворком. Собственно, если проект целиком и полностью состоит из системы, контролируемой фреймворком, то, что "прокричит" ваш фреймворк, такая архитектура и будет.

Сложилось впечатление, что Автор призывает использовать сервисную модель.

Большое спасибо за подробное разъяснение.

С большим интересом читаю Ваши комментарии. Но я уже сам запутался. Можно как-то доступнее? :)

П.С. Я уже на старте проверять код на массивы и форичи.

Чтобы скачков не было в бесконечных списках обычно используют position: absolute.

Полностью согласен, что упираемся в расчеты, которые не хочется проводить на клиенте. Но и это решаемо, потому что именно разработчик компонента (возможно с поддержкой дизайнера) решает как он должен отображаться. Я к тому что чем больше строгости, тем проще расчеты.

В том числе расчеты могут быть отложенными и незаметными для пользователя. И могут даже корректироваться, переходя от приближенных расчетов высот к более точным ) Потому что нам будет все равно, что условный компонент, который ниже вьюпорта на 5000px на самом деле должен быть 4950px. При скроллинге это незаметно.

Чтобы продемонстрировать что я имею в виду, накидал небольшой сниппет для замены комментариев Хабра теми самыми текстовыми блоками.

let nodes = Array.from(document.querySelectorAll(".tm-comment-thread__comment"));

for (let i=0; i<nodes.length; i++) {
    let node = nodes[i];
    let rect = node.getClientRects()[0];
    let text = node.innerText;
    let div = document.createElement("div");
    div.style.height = `${rect.height}px`;
    div.innerText = text;

    node.replaceWith(div);
}

браузерному поиску это не поможет, ибо он будет не туда, куда надо.

<div style="height: 90px">long text </div>
<div style="height: 120px">long text 2 </div>
...
<div style="height: 20px">needle in a haystack </div>
...
<div style="height: 200px">text </div>

Div мог бы быть в исходном контенте параграфом или таблицей. Это неважно потому что тут главное позиционирование текстовых блоков (следование друг за другом с учетом их размеров).

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

Если же блок получится слишком высоким, то очевидно, что браузер покажет найденный текст не там, где надо. А для небольших, которые вмещаются, например, в четверть экрана, то проблемы особой не вижу.

Кстати, можно не уничтожать невидимый контент, а в невидимых для пользователя частях страницы можно рисовать блок, который будет содержать исключительно текст без украшательств. Что это дает: во-первых не нужно на странице реализовывать свой поиск, и во-вторых очевидно памяти не так много потратится, потому что на каждый блок с известной высотой будет приходиться всего 1 тег.

При прокрутке уже отрисовывать нужную часть страницы так, как она должна выглядеть.

"Текстовые" блоки можно лениво рендерить, чтобы браузер не тормозил.

Решение на файлах - такое себе. Данные можно хранить хоть в json, но масштабируемости не будет. Наверняка потом надо будет учитывать время устаревания ссылки или аналитику провести.

Ну и кстати на ру-хостингах на некоторых тарифах еще любят ограничение делать в 10000 файлов на VPS.

Поэтому я за решение с использованием БД. Адрес короткого урла тоже довольно просто можно сгенерить, например: base62(index) . base62(md5(url)).

Information

Rating
4,195-th
Location
Екатеринбург, Свердловская обл., Россия
Registered
Activity

Specialization

Frontend Developer, Fullstack Developer
JavaScript
HTML
CSS
Node.js
PHP
Database