RussCoder / djvujs

DjVu.js is a program library for working with .djvu files online without any connection with the server. DjVu.js Viewer is a widget that allows viewing .djvu files right in the browser and can be easily embedded into any web page.
https://djvu.js.org/
Other
184 stars 37 forks source link

Установка из npm #87

Closed slavonika closed 1 year ago

slavonika commented 1 year ago

Есть ли возможность установки viewer'а из npm? Хочу использовать в react-приложении на next.js. Там сработала бы оптимизация. Ещё есть вариант затащить исходники в проект.

RussCoder commented 1 year ago

Нет, такой возможности нет. Это никому не было нужно. И если делать по уму, то надо многие зависимости перенести в peerDependencies, да и сам Viewer выделить в React компонент. И желания заниматься этим у меня сейчас нет.

Также для работы нужна библиотека, а она сейчас тоже через <script /> подключается.

Как я понимаю, это все нужно только для оптимизации размера сборки. Однако, это все равно существенно увеличит размер сборки и замедлит загрузку сайта. Для пользователя может быть лучше, если вы подключите Viewer отдельным скриптом, как это и предполагается делать.

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

slavonika commented 1 year ago

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

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

То что не собираетесь сделать React компонент и пакет в npm – жаль, конечно, пригодилось бы.

И огромное спасибо за библиотеку :)

RussCoder commented 1 year ago

Я вам советую начать с подключения сборки через скрипты в head как здесь показано. https://djvu.js.org/downloads

Можно добавить к ним defer, но тогда придется проверять появился ли DjVu.Viewer или нет.

И написать простой компонент Viewer, который будет создавать пустой div, получать его через ref, и создавать DjVuViewer.

Когда компонент удаляется, надо будет вызвать метод .destroy(). Он не указан в документации, но он есть. Его туда стоит добавить.

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

Если проект открытый, то поделитесь ссылкой, пожалуйста. Будет интересно посмотреть.

slavonika commented 1 year ago

Спасибо за ответы.

Сейчас ещё рассматриваю вариант ленивой загрузки Viewer'а (например) или его загрузки по клику на кнопке просмотра документа. Всё-таки не очень нравится идея создавать лишние страницы.

Тут ещё один момент. Мобильная аудитория возросла в разы. Сейчас их 80-90% от общего числа пользователей. А ведь раньше было наоборот. Надо сказать, что Viewer вполне себя хорошо ведет в мобильном браузере. Не хватает разве что масштабирования двумя пальцами.

Наш сайт был создан лет 15 назад, пора переписывать. Пока код в закрытом репозитории, смотреть особо нечего, мы три дня назад начали работу :) Если получится что-то интересное, откроем репозиторий.

r-pankevicius commented 1 year ago

Please take a look at the license. It's kind of GPL. Some years ago I did a separate page for the browsing of djvu documents to match the licensing. So I don't think that mixing-in this library to your commercial web site would play well with licenses. Unless нам по@бать на эту западную ху@ню.

slavonika commented 1 year ago
"use client";

import { useState } from "react";

const DjvuViewer = () => {
  const [areScriptsLoaded, setAreScriptsLoaded] = useState(false);

  const handleLoadScript = () => {
    if (!document.querySelector("script[src='/scripts/djvu.js']")) {
      const djvuLibJs = document.createElement("script");
      djvuLibJs.src = "/scripts/djvu.js";
      djvuLibJs.async = true;
      document.body.appendChild(djvuLibJs);
    }

    if (!document.querySelector("script[src='/scripts/djvu_viewer.js']")) {
      const viewerJs = document.createElement("script");
      viewerJs.src = "/scripts/djvu_viewer.js";
      viewerJs.async = true;
      document.body.appendChild(viewerJs);
    }

    const checkScriptsLoaded = () => {
      if (
        typeof DjVu !== "undefined" &&
        typeof DjVu.Viewer !== "undefined"
      ) {
        // Create a new instance of the DjVu viewer and render it.
        window.ViewerInstance = new DjVu.Viewer();
        window.ViewerInstance.render(document.querySelector("#for_viewer"));

        setAreScriptsLoaded(true);
      } else {
        setTimeout(checkScriptsLoaded, 100);
      }
    };

    checkScriptsLoaded();
  };

  return (
    <>
      <button onClick={handleLoadScript}>Просмотр</button>
      <div id="for_viewer"></div>
    </>
  );
};

export default DjvuViewer;
slavonika commented 1 year ago

Интересно, а можно ли принудительно включить полностраничный режим и выставить масштаб страницы по ширине окна Viewer'а? В конфигурации я такого не нашёл (не понял).

slavonika commented 1 year ago

Подход был правильный, код с некоторыми доработками даёт результат. Но вот в целом юзабилити страницы с кучей вьюверов (или одним внизу страницы) как-то не зашёл. Попробую идею с просмотровщиком на отдельном урле, файл передам через параметры.

RussCoder commented 1 year ago

Включить полностраничный режим должно быть несложно. Нужно создать вот это событие https://github.com/RussCoder/djvujs/blob/master/viewer/src/components/misc/FullPageViewButton.jsx#L22 которое используется в соответствующей кнопке.

Методы DjVuViewer так и работают, инициируя события https://github.com/RussCoder/djvujs/blob/master/viewer/src/DjVuViewer.js#L166

Я бы рекомендовал, запустить проект локально и добавить подобные методы. Если они действительно будут нужны, то можно будет их сохранить в основном репозитории и внести в документацию.

А вот выставить масштаб страницы по ширине окна уже сложнее. Это не было реализовано, поэтому потребует времени.

slavonika commented 1 year ago

В результате решил сделать отдельную страницу с просмотровщиком djvu и передачей пути к файлу через параметры.

С событиями пока не заморачивался, но очень не хватает полностраничного режима прям при открытии.

Масштаб по странице тоже очень нужная функция. На десктопе 100% выглядит очень мелко, на мобилке 100% – очень крупно.

Кроме того заметил, что используемый мной tailwind создает некоторые артефакты на интерфейсе вашего компонента. Видимо, потому что в css у вас не всё прописано, а ведь что-то tailwind из стилей по умолчанию сбрасывает.

Могу я создать соответствующие issue?

RussCoder commented 1 year ago

Да, конечно.

RussCoder commented 1 year ago

issue для масштаба по странице уже есть https://github.com/RussCoder/djvujs/issues/38 Если это то, что вам нужно, просто поставьте +1 туда или комментарий добавьте.

slavonika commented 1 year ago

Спасибо, написал, поставил.

С монтированием скрипта в приложение next.js пришлось немного повозиться. Вот (вроде бы) рабочий вариант:

"use client";

import { useEffect } from "react";

const DjvuViewer = ({ searchParams }) => {
  const viewerConfig = {
    language: "ru",
    uiOptions: {
      changePageOnScroll: true,
    },
  };

  useEffect(() => {
    const checkScriptsLoaded = () => {
      if (!document.querySelector("script[src='/scripts/djvu.js']")) {
        const djvuLibJs = document.createElement("script");
        djvuLibJs.src = "/scripts/djvu.js";
        djvuLibJs.async = true;
        document.body.appendChild(djvuLibJs);
      }

      if (!document.querySelector("script[src='/scripts/djvu_viewer.js']")) {
        const viewerJs = document.createElement("script");
        viewerJs.src = "/scripts/djvu_viewer.js";
        viewerJs.async = true;
        document.body.appendChild(viewerJs);
      }

      if (typeof DjVu !== "undefined" && typeof DjVu.Viewer !== "undefined") {
        window.ViewerInstance = new DjVu.Viewer();
        window.ViewerInstance.render(document.querySelector("#vw"));
        window.ViewerInstance.loadDocumentByUrl(
          `/djvu/${searchParams.djvu}`,
          viewerConfig
        );
      } else {
        setTimeout(checkScriptsLoaded, 200);
      }
    };

    checkScriptsLoaded();
  }, [searchParams]);

  return (
    <>
      <div id="vw"></div>
    </>
  );
};

export default DjvuViewer;

Еще был вариант с компонентом

import Script from 'next/script'

но я его не стал проверять.