• Stars
    star
    547
  • Rank 81,254 (Top 2 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 2 years ago
  • Updated 5 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Service Worker Routing library for in browser HTTP requests

Logo of Wayne library - it represent constrution worker helmet and text with the name of the library

npm PRs Welcome

Service Worker Routing library for in browser HTTP requests

It's like Express inside Service Worker.

Most of the time Service Worker is used for caching of HTTP requests and making the app work when there is no internet (mostly for PWA), but in fact you can create completely new responses to requests that never leave the browser. This library make that easier by adding simple API similar to Express.

Usage

Installation from npm:

npm install @jcubic/wayne
yarn add @jcubic/wayne

Standard way of installing the service worker

if ('serviceWorker' in navigator) {
    const scope = location.pathname.replace(/\/[^\/]+$/, '/');
    navigator.serviceWorker.register('sw.js', { scope, type: 'module' })
             .then(function(reg) {
                 reg.addEventListener('updatefound', function() {
                     const 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);
             });
}

If you want to support browsers that don't support ES Modules in Service Worker use this instead:

if ('serviceWorker' in navigator) {
    const scope = location.pathname.replace(/\/[^\/]+$/, '/');
    navigator.serviceWorker.register('sw.js', { scope })
             .then(function(reg) {
                 reg.addEventListener('updatefound', function() {
                     const 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);
             });
}

Inside same file you can send AJAX requests with standard fetch API.

function get(url) {
    fetch(url)
      .then(res => res.text())
      .then(text => output.innerHTML = text);
}

input.addEventListener('click', () => {
    get(`./user/${user_id.value}`);
});

error.addEventListener('click', () => {
    get(`./error`);
});

Service worker - sw.js file

Importing Wayne module:

  • when worker created as ES Module
import { Wayne } from 'https://cdn.jsdelivr.net/npm/@jcubic/wayne';

const app = new Wayne();
  • When worker created as normal script
importScripts('https://cdn.jsdelivr.net/npm/@jcubic/wayne/index.umd.min.js');

const app = new wayne.Wayne();

Using the library

const users = {
  1: 'Jakub T. Jankiewicz',
  2: 'John Doe',
  3: 'Jane Doe'
};

app.get('/user/{id}', function(req, res) {
  const user = users[req.params.id];
  if (user) {
    res.json({result: user});
  } else {
    res.json({error: 'User Not Found'});
  }
});

app.get('/error', function(req, res) {
  nonExisting();
});

app.get('/redirect', function(req, res) {
  res.redirect(301, '/message');
});

app.get('/message', function(req, res) {
  res.text('Lorem Ipsum');
});

app.get('/external', function(req, res) {
  // lorem ipsum API
  res.redirect('https://api.buildable.dev/@62d55492951509001abc363e/live/lorem-ipsum');
});

File system middleware

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

When not using a module the code will be similar. When you access URLS with prefix __fs__ like ./__fs__/foo it will read files from indexedDB file system named __wayne__. See Lightning-FS repo on details about the library.

RPC mechanism

In Service worker you create generic route that send data to broadcastChannel:

import { send } from 'https://cdn.jsdelivr.net/npm/@jcubic/wayne';

const channel = new BroadcastChannel('__rpc__');

app.get('/rpc/{name}/*', async (req, res) => {
    const args = req.params[0].split('/');
    const method = req.params.name;
    try {
        const data = await send(channel, method, args);
        res.json(data);
    } catch(e) {
        res.text(e.message);
    }
});

and in the main thread you create the other side of the channel and the remote methods:

import { rpc } from 'https://cdn.jsdelivr.net/npm/@jcubic/wayne';

const channel = new BroadcastChannel('__rpc__');

rpc(channel, {
    ping: function() {
        return 'pong';
    },
    sin: function(x) {
        return Math.sin(x);
    },
    random: function() {
        return Math.random();
    },
    json: function() {
        return fetch('https://api.npoint.io/8c7cc24b3fd405b775ce').then(res => res.json());
    }
});

When you send request /rpc/ping you will get response from methods.ping function.

fetch('./rpc/ping')
  .then(res => res.text())
  .then(text => {
     console.log({ text });
  });

With this setup, you can create new functions/methods that will map to HTTP requests.

The demo below uses random request:

let index = 0;
const requests = [
    './rpc/ping/',
    './rpc/json/',
    './rpc/random/',
    './rpc/sin/10'
];

rpc.addEventListener('click', () => {
    get(random_request() );
});

function random_request() {
    const next_index = index++ % requests.length;
    return requests[next_index];
}

Server-Sent Events

Server-Sent Events is the way to stream data in the browser. It's native browser implementation of Long Polling. Here is example how to use SSE with Wayne:

Service Worker

app.get('/sse', function(req, res) {
  const stream = res.sse({
    onClose() {
      clearInterval(timerId);
    }
  });
  var timerId = setInterval(function() {
    const now = (new Date()).toString();
    stream.send({ data: now });
  }, 1000);
});

Main tread

let see_source;

sse_start.addEventListener('click', () => {
    see_source = new EventSource("./sse");
    see_source.onmessage = event => {
        console.log(event.data);
    };
});

sse_stop.addEventListener('click', () => {
    if (see_source) {
        see_source.close();
        see_source = null;
    }
});

Demo

API reference

Wayne object has those methods that correspond to HTTP methods

  • get
  • post
  • put
  • delete
  • patch

each method accepts URL with markers inside curly brackets those markers will be available from Request.params object. Request object is browser native object of a given request see MDN for details. The only change to the native API is that the object have proeprty params.

Here are few most important Request properties:

  • headers - Headers object to get key/value pairs use Object.fromEntires(req.headers.entries()).
  • method - request method as string.
  • url - string with full URL.
  • referrer - HTTP referer.
  • arrayBuffer() - Returns a promise that resolves with an ArrayBuffer representation of the request body.
  • blob() - Returns a promise that resolves with a Blob representation of the request body.
  • formData() - Returns a promise that resolves with a FormData representation of the request body.
  • json() - Returns a promise that resolves with the result of parsing the request body as JSON.
  • text() - Returns a promise that resolves with a text representation of the request body.

Response object is instance of HTTPResponse those have methods:

  • html()
  • json()
  • text()
  • send()

each of those methods accepts string as first argument. Second argument are options:

  • headers - any headers as key value pairs or you can pass Headers object.
  • statusText - The status message associated with the status code, e.g., OK.
  • status - The status code for the response, e.g., 200.
  • type - Content-Type of the response (MIME).

Additional methods:

  • redirect() - accept url or optional first argument that is number of HTTP code
  • sse([options]) - function create Server-Sent Event stream, the return object have method send that send new event.

Application also have middlewere as in Express.js

  • use(function(err, req, res, next) {}) 4 parameters it's error handler
  • use(function(req, res, next) {}) 3 parameters it's middlewere

Additional exported functions:

  • FileSystem({ path: string, fs: <FS Module>, prefix: string }) - function that creates a middleware for the file system. You should use FS that supports Service Worker like the one that use IndexedDB e.g. BrowserFS or LightingFS.
  • rpc(channel, object) - function that should be used in main thread that create RPC like mechanism, first argument is instance of a broadcast channel and second is object with remote functions.
  • send(channel, method: string, args: any[]) - function send remote procedure to main thread.

Story

The idea of using a Service worker to serve pure in browser HTTP requests has a long history. I've first used this technque for my Git Web Terminal and described the usage of it in the article from 2018: How to create Web Server in Browser. In June 2022, I came up with a cool new way of using this technique. While creating PoC for the article I'm going to write (will update this story when ready), I realized that I can extract all the logic of creating those fake HTTP requests into a library. This is how Wayne was born.

The name of the library was inspired by the scene in Wayne's World 2 in which Wayne dresses up as a construction worker.

Watch the video

I hightly recommend both movies if you haven't seen them already.

Contribution

If you have any ideas for an improvement don't hesitate to create an issue. Code contributions are also welcome.

Working on your first Pull Request? You can learn how from this free series How to Contribute to an Open Source Project on GitHub

Article about or mention Wayne

Press

Aknowledge

License

Released with MIT license
Copyright (c) 2022-2023 Jakub T. Jankiewicz

More Repositories

1

jquery.terminal

jQuery Terminal Emulator - JavaScript library for creating web-based terminals with custom commands
JavaScript
2,940
star
2

sysend.js

Web application synchronization between different tabs
JavaScript
1,025
star
3

lips

Scheme based powerful lisp interpreter written in JavaScript
JavaScript
323
star
4

chat-gpt

ChatGPT conversation saving bookmark
JavaScript
291
star
5

tagger

Zero Dependency, Vanilla JavaScript Tag Editor
JavaScript
261
star
6

jquery.splitter

jQuery Splitter is plugin that split your content with movable splitter between them
JavaScript
240
star
7

gaiman

Gaiman: Text based game engine and programming language
JavaScript
137
star
8

leash

Browser Shell
JavaScript
120
star
9

jquery.rotate

Simple plugin that add rotate css property and animation
JavaScript
94
star
10

git

GIT Web Terminal
JavaScript
82
star
11

Clarity

Customizable Monoshape Vector Icon Theme for GTK+
SVG
39
star
12

jquery.filebrowser

File browser jQuery plugin
JavaScript
30
star
13

jquery.terminal-www

jQuery Terminal Website
HTML
26
star
14

favloader

Vanilla JavaScript library for loading animation in favicon
JavaScript
23
star
15

cmatrix

Render Matrix effect animation on Canvas in JavaScript
JavaScript
22
star
16

lily

Simple JavaScript options parser inspired by yargs
JavaScript
21
star
17

jsh.php

Terminal like php shell (PHP web terminal emulator)
PHP
20
star
18

jsvi

fork of JSVI - VI in JavaScript
JavaScript
18
star
19

Monadic

JavaScript micro library - POC
JavaScript
16
star
20

fake-linux-terminal

Fake GNU/Linux, Unix, MacOS terminal based system
HTML
15
star
21

json-rpc

JSON-RPC implementaion in php and JavaScript
PHP
13
star
22

electron-terminal

Base for jQuery Terminal based Electron apps
JavaScript
12
star
23

route.js

Simple routing library that can be use on the server or in the browser
JavaScript
11
star
24

jquery.micro

Pico/Nano like editor for jquery.
JavaScript
11
star
25

coverage.el

Emacs minor mode for displaying code coverage
Emacs Lisp
10
star
26

chat

Simple Chat with Server Side Events, PHP and SQLite
PHP
8
star
27

prism-cli

Syntax highlighting for command line
JavaScript
7
star
28

try-python

Try Python website
Python
7
star
29

commodore64

Commodore 64 jQuery Terminal Demo
HTML
7
star
30

ascii-canvas

String based text rendering for Node and Browser
JavaScript
6
star
31

jquery.resize

Custom resize jQuery event for element
JavaScript
6
star
32

notes

Simple text based notes taking app
JavaScript
6
star
33

webrtc-share

Application for sharing files using WebRTC
PHP
6
star
34

jcubic.pl

Głównie JavaScript - blog głównie o Front-Endzie
PHP
5
star
35

awesome-ascii

List of Awesome ASCII libraries
5
star
36

ansidec

Unix formatting transformer in JavaScript
JavaScript
5
star
37

firepad

Simple firepad based source code editor
HTML
5
star
38

quizerach

Simple Quiz Maker Open Source App (WIP)
TypeScript
4
star
39

calendar

ASCII calendar that can be used in Node.js or Browser
JavaScript
4
star
40

angular.piechart

Angular 1.5 component for svg based piecharts
JavaScript
4
star
41

velvet

Vanilla JavaScript Universal CSS in JS library
TypeScript
4
star
42

jcubic

3
star
43

chess

Terminal based chess game
HTML
3
star
44

snapp

Simple Text based notes taking app
PHP
3
star
45

open-source-library

Template for JavaScript Open Source library
Makefile
3
star
46

ToME

ToME - Tales of Middle Earth
C
3
star
47

leash-cordova

Cordova leash shell
JavaScript
3
star
48

filter-paste-js

intercept content pasting into iframe with design mode
JavaScript
3
star
49

fs-browser

In Browser File System App
JavaScript
3
star
50

jquery-position-event

jQuery cursor position change event
JavaScript
2
star
51

isomorphic-lolcat

Lolcat gradient that can be used in browser or Node
JavaScript
2
star
52

react-wayne-auth

JavaScript
2
star
53

koduj-curriculum

Curriculum for teaching programming using JavaScript and p5.js library
2
star
54

dotfiles

Linux dotfiles
Shell
2
star
55

cataloger

Shopping cart like catalog library
JavaScript
2
star
56

json-rpc-list

List of JSON-RPC implementations
2
star
57

compickr

Flickr composition checker
JavaScript
2
star
58

jankiewicz

Personal Blog of Jakub T. Jankiewicz
Liquid
2
star
59

aimed

Simple JavaScript Markdown Editor
JavaScript
2
star
60

yapp

Yet Another PHP Proxy
JavaScript
2
star
61

kopalinski.sqlite

Słownik Wyrazów Obcych Kopalińskiego jako baza sqlite
Python
2
star
62

koduj

P5.js playground
PHP
2
star
63

static

static files used with cdn.jsdelivr.net
JavaScript
2
star
64

opensourcelogo

Logo for you Open Source project
2
star
65

price.py

Scraping prices from Ceneo.pl and save in SQLite database
Python
1
star
66

php-terminal-jwt

Demo of JWT with jQuery Terminal
PHP
1
star
67

refClass

R
1
star
68

jquery.draglessClick

Better jQuery click event that's not invoked when you drag or select text
JavaScript
1
star
69

swift.manager

Server file browser and terminal with apps support
JavaScript
1
star
70

bassel.jcubic.pl

Bassel badge page
PHP
1
star
71

roman

ReactJS application with unit tests
TypeScript
1
star
72

REPL

REPL Bookmarklets for different languages
1
star
73

Similar-Stuff

Get Similar stuff from tastekid.com
Python
1
star
74

expression.php

Safely evaluate math, string, and boolean expressions
PHP
1
star
75

cv

My resume
Makefile
1
star
76

quatro

Simple Q&A Open Source application in PHP
PHP
1
star
77

interactive-scheme-tutorial

Interactive Scheme Tutorial
HTML
1
star
78

Downloader

Command Line tool for download file from file hosting sites.
Ruby
1
star
79

gps.py

Simple script to add GPS EXIF data to images
Python
1
star
80

flash-3d

School project 3D Flash animation in C++
C
1
star
81

FizzBuzz

JavaScript version of function only FizzBuzz
JavaScript
1
star
82

uncp

UNsplash Cache Proxy
PHP
1
star
83

jsvi-app

jsvi app for leash shell
JavaScript
1
star
84

bash

Bash Interpreter written in JavaScript
1
star