Sitemap

ITNEXT

ITNEXT is a platform for IT developers & software engineers to share knowledge, connect, collaborate, learn and experience next-gen technologies.

How to create Web Server in Browser

3 min readNov 8, 2021

--

Did you ever wonder if you can build a web server in a browser? Or to be precise to create files and serve them as static assets using URL. In this article, I will explain how to do that.

Press enter or click to view image in full size

My story about the issue

When I was creating my side project using isomorphic-git called GIT Web Terminal, which also uses my other Open Source library jQuery Terminal, I wanted to create a web browser inside the application (that uses iframe) and also allow it to open the files in a new tab. I was wondering if something like this is possible.

Service Worker

Then I’ve realized that server workers, which usually are used to cache files in PWA, can be used to generate new files on the fly and send them to the browser using fetch event.

BrowserFS

To work with isomorphic-git you needed a library that will give you NodeJS like file system object. For my GIT Web Terminal, I’ve used BrowserFS, which was the main library to be used with isomorphic-git, before lightning-fs, dedicated isomorphic-git fs implementation was created. With the BrowserFS you can use different backends, I was searching for something that will work also in the service worker. I’ve found the perfect fit, which was indexedDB.

The code of the solution

The code was quite simple, I decided that I will use the prefix __browserfs__ and everything that is after will be a path to my local BrowserFS file, so the real files and those in idexedDB are not messed up.

Below is the whole code:

The service worker allows to use custom headers and custom HTTP responses, here I’ve used 301 redirects and 404 errors and some basic HTML with a proper content-type header.

To initialize the service worker you can use this code:

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);
});
}
}

You can use this code as is in your project and you will have your own web server in a browser. You can also modify the code and add new features. If you made something interesting please share the result, and please don’t forget to include the license and my copyright at the top of the file (you can include your own copyright above or below mine). This can be a starting point to creating a nice library that will do a lot of cool stuff.

Working Demo

To see the working demo in action, go to my project GIT Web Terminal. When you open that link, it will open the web terminal, clone my other project repo (my work in progress programming language called Gaiman) and view the HTML file in a built-in browser. Note that the clone make take some time so please be patient.

If you inspect the DOM you will see that there is an iframe that holds the file and if look at the source file you will:

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

You can also create the file directly in the terminal by opening the editor (like vi or emacs):

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

If you type vi, write some text and save the file, you will be able to view it in the browser.

EDIT: This trick of having pure in-browser HTTP requests was abstracted into Open Source library called Wayne. You can also read an article, that better show how to use Wayne library on FreeCodeCamp on this link: How to Create a REST API Without a Server.

Since version 0.6.0 of Wayne you have building FileSystem middleware. The code is much shorter:

import { Wayne, FileSystem } from 'https://cdn.jsdelivr.net/npm/@jcubic/wayne';
import FS from "https://cdn.skypack.dev/@isomorphic-git/lightning-fs";
import mime from "https://cdn.skypack.dev/mime";
import path from "https://cdn.skypack.dev/path-browserify";

const { promises: fs } = new FS("__wayne__");

const app = new Wayne();

app.use(FileSystem({ path, fs, mime, prefix: '__fs__' }));

The above code use ES Module-based Service Worker (here you can find article about it) the same will work with normal Service Worker and importScript.

If you like this, you can visit my website and follow me on Twitter: @jcubic.

--

--

ITNEXT
ITNEXT

Published in ITNEXT

ITNEXT is a platform for IT developers & software engineers to share knowledge, connect, collaborate, learn and experience next-gen technologies.

Jakub T. Jankiewicz
Jakub T. Jankiewicz

Written by Jakub T. Jankiewicz

Web developer, technical writer, Open Source programmer and Polish Wikipedia editor. Also not professional photographer and logo designer.

No responses yet