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

Мой рассказ о проблеме

Когда я создавал свой побочный проект, используя isomorphic-git под названием GIT Web Terminal, который также использует мою другую библиотеку с открытым исходным кодом jQuery Terminal, я хотел создать веб-браузер внутри приложения (который использует iframe), а также разрешить ему открывать файлы в новой вкладке. Мне было интересно, возможно ли что-то подобное.

Сервисный работник

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

BrowserFS

Для работы с isomorphic-git вам нужна библиотека, которая даст вам объект файловой системы, подобный NodeJS. Для моего веб-терминала GIT я использовал BrowserFS, которая была основной библиотекой для использования с isomorphic-git, до создания lightning-fs, специальной реализации isomorphic-git fs. С BrowserFS вы можете использовать разные бэкенды, я искал что-то, что будет работать и в сервис-воркере. Я нашел идеальное решение — indexedDB.

Код решения

Код был довольно прост, я решил, что буду использовать префикс __browserfs__, а все, что будет после, будет путем к моему локальному файлу BrowserFS, чтобы не перепутались настоящие файлы и те, что в idexedDB.

Ниже приведен весь код:

Сервис-воркер позволяет использовать настраиваемые заголовки и настраиваемые ответы HTTP, здесь я использовал 301 редиректы и 404 ошибки, а также немного базового HTML с правильным заголовком типа контента.

Чтобы инициализировать работника службы, вы можете использовать этот код:

if ('serviceWorker' in navigator) {
  var scope = location.pathname.replace(/\/[^\/]+$/, '/');
  if (!scope.match(/__browserfs__/)) {
    navigator.serviceWorker.register('sw.js', {scope})
      .then(function(reg) {
         reg.addEventListener('updatefound', function() {
           var installingWorker = reg.installing;
           console.log('A new service worker is being installed:',
                       installingWorker);
         });
         // registration worked
         console.log('Registration succeeded. Scope is ' +
                    reg.scope);
      }).catch(function(error) {
        // registration failed
        console.log('Registration failed with ' + error);
      });
  }
}

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

Рабочая демонстрация

Чтобы увидеть рабочую демонстрацию в действии, перейдите на мой проект Веб-терминал GIT. Когда вы открываете эту ссылку, она открывает веб-терминал, клонирует репозиторий моего другого проекта (мой язык программирования, который находится в стадии разработки, называется Gaiman) и просматривает HTML-файл во встроенном браузере. Обратите внимание, что создание клона займет некоторое время, поэтому наберитесь терпения.

Если вы проверите DOM, вы увидите, что есть iframe, который содержит файл, и если вы посмотрите на исходный файл, вы увидите:

/git/__browserfs__/gaiman/docs/demo/index.html

Вы также можете создать файл непосредственно в терминале, открыв редактор (например, vi или emacs):

vi test.txt
i Hello World :wq
view test.txt

Если вы наберете vi, напишите текст и сохраните файл, вы сможете просмотреть его в браузере.