One of the difficulties I’m encountering working on the gest-dashboard project is related to how to view folders inside a browser. Or rather, how to use folders containing locally saved HTML files. As long as they are simple files this is not a problem. It gets harder when it comes to more complex web applications. I have tried two solutions. The first involves the use of http.createServer([options][, requestListener]) of Node.js. This however adds a level of complexity to my project.

Then, Ashley Gullen posted a very interesting repository: AshleyScirra/servefolder.dev:

The page at servefolder.dev lets you host a local folder with web development files, such as HTML, JavaScript and CSS, directly in your browser. It works using Service Workers: everything is served from your local system only, nothing is uploaded to a server, and your files are not shared with anybody else.

In other words, I create a local server directly in the browser and I can use it to see my folders as if they are online. But without being online.

Starting from this repository I created my version, Svelte Serve Folder:

server-folder-01.gif

Obviously, the original idea isn’t mine, and I recommend consulting Ashley’s repository directly. Its code is very informative. So instructive that studying it is essential. So, in this article I will report my notes and what I understand. I’ll do this by recreating the original repository with just a few changes:

  1. I will use code written in TypeScript whenever possible: I have noticed that consulting TS code is easier for me in the future;
  2. when possible, I will use Svelte: in this case it is not essential but I plan to reuse what I have learned in other projects with Svelte;
  3. I add the ability to see the contents of the folder directly on the main page, via an iframe: in this case I need to get an idea of ​​how to integrate this technique into Electron’s BrowserView

One thing I won’t use is @rollup/plugin-html to create an HTML template. But I want to think about it in the next few days.

JavaScript Service Workers

For the moment I leave out the graphic aspect and focus on the Service Workers. If you’ve never used them, and this is my case, the first thing to do is understand what they are. Fortunately, on Mozilla.org you can find all the information you need. So, the first thing to do is check out this site:

(After completing this post I also found a nice story by Bowei Han on Medium: How to Make Your Web Apps Work Offline)

In summary, the purpose of Service Workers is to create a bridge between the page hosted in the browser and the server from which it is generated. They are generally used to allow a site to work offline and to manage notifications and actions in the background. They do not have direct access to the HTML page (the so-called DOM), they are completely asynchronous and do not work when the browser is in anonymous mode. And they require an HTTPS connection.

The use requires some obligatory steps:

  • each service worker must first be registered via the ServiceWorkerContainer.register() method
  • then the service worker is downloaded: it is an automatic process that does not require any action from the user
  • after downloading it is time to install it: this action is also automatic but there are cases in which it is better to force it. In this project Ashley uses the [ServiceWorkerGlobalScope.skipWaiting()](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/skipWaiting and Clients.claim() methods, and it’s a good solution
  • and finally there is the activate event (that can be intercepted and managed)

How to Install a Service Worker in JavaScript

A little bit of code. Registering a service worker in JavaScript is simple:

It is a good idea to keep the sw.js file (the one with the service worker code) in the root folder: this makes your life a lot easier.

In sw.js I add an installation triggered event:

And then another triggered by activation:

So I installed the service workers. But how to use them?

Use the File System Access API to select a folder

Well, that’s the idea. Instead of saving the site code offline (or just the site code) it is possible to store the contents of a local folder in memory. This way when we try to access it, it appears as if it were a file on a virtual server. In simpler words: we can convince the browser that that folder is not locally but a remote folder saved by local service workers.

Can I have a web app in a completely offline environment:

server-folder-02.gif

Obviously we need a way to allow files to pass from disk to service workers. In this case, the File System Access API is excellent. I talked about it in depth about a year ago:

I then create a pickFolder function to select a folder on the pc.

After getting the folder I need a way to notify the service workers of the choice. I use a postToSW function:

Now I can send a message from the HTML page to the service worker. But I need to add a function to the sw.js file:

But what if the service worker hasn’t been initialized yet?

Ashley came up with an elegant solution, and it took me some time to figure it out. It consists of two functions. The first is to create a timer to wait the necessary time:

Then I need the ServiceWorkerContainer.oncontrollerchange property to intercept when a service worker receives a new active worker:

Now I have all the tools to create a function to select a folder from the pc and notify the service worker:

Later you can use all of this in an HTML page. In my case I create the App.svelte file:

Open the folder as if it were on a server

In summary, at the moment I can choose a folder from the pc and then notify the service workers. But what happens next? Well, I need a StartHost(e) function:

This allows me to reply to the HTML page by handing over the host name and client id. I can use this information to create a button:

When I click on the button a new page opens. But obviously the page has nothing. I need to add a specific function in sw.js:

Now I have to go back to the main page. I add an event listener for the fetch event

Then I create the handleFetch function:

The generateDirectoryListing function creates an HTML page containing the list of files and folders.

Ashley Gullen’s function is quite basic. In my version I changed it a bit but they are details.

Show the result in an iframe

The original version of this repository is to open the uploaded folder in another browser tab. In my version I have added the ability to see the content directly on the same page. Just use an iframe element and enter the corresponding url:

Well, that’s all for now. There are many other interesting details but these are the basic concepts. I recommend, again, to consult the original repository:

My version:

Finally, I added a list on Medium with my articles on Svelte: