Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/jcubic/wayne

Service Worker Routing library for in browser HTTP requests
https://github.com/jcubic/wayne

browser fake filesystem filesystem-library http http-server http-server-library javascript promise routing service-worker wayne web-server

Last synced: 23 days ago
JSON representation

Service Worker Routing library for in browser HTTP requests

Awesome Lists containing this project

README

        


Logo of Wayne library - it represents construction worker helmet and text with the name of the library

[![npm](https://img.shields.io/badge/npm-0.18.3-blue.svg)](https://www.npmjs.com/package/@jcubic/wayne)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://makeapullrequest.com)
[![jSDelivr](https://data.jsdelivr.com/v1/package/npm/@jcubic/wayne/badge)](https://www.jsdelivr.com/package/npm/@jcubic/wayne)

[Service Worker Routing library for in-browser HTTP requests](https://github.com/jcubic/wayne/)

It's like an Express inside Service Worker.

Most of the time Service Worker is used for caching HTTP requests and making the app work when there
is no internet (mostly for [PWA](https://en.wikipedia.org/wiki/Progressive_web_application)), but in
fact, you can create completely new responses to requests that never leave the browser. This library
makes that easier by adding a simple API similar to Express.

## Usage

Installation from npm:

```bash
npm install @jcubic/wayne
```

```bash
yarn add @jcubic/wayne
```

The standard way of installing the service worker

```javascript
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:

```javascript
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 the same file you can send [AJAX](https://en.wikipedia.org/wiki/Ajax_(programming)) requests with standard
[fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).

```javascript
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

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

const app = new Wayne();
```

* When the Service Worker created as normal script

```javascript
importScripts('https://cdn.jsdelivr.net/npm/@jcubic/wayne/index.umd.min.js');

const app = new wayne.Wayne();
```

* When using bundlers like Vite:

```javascript
import { Wayne } from '@jcubic/wayne';
```

Using the library

```javascript
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('/404', function(req, res) {
res.text('Not Found', { status: 404, statusText: 'Not Found' });
});

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

### Handle the same extension for all requests

```javascript
importScripts(
'https://cdn.jsdelivr.net/npm/@jcubic/wayne/index.umd.min.js',
'https://cdn.jsdelivr.net/gh/jcubic/static@master/js/path.js'
);

const app = new Wayne();

app.get('*', function(req, res) {
const url = new URL(req.url);
const extension = path.extname(url.pathname);
const accept = req.headers.get('Accept');
if (extension === '.js' && accept.match(/text\/html/)) {
res.text('// Sorry no source code for you');
} else {
res.fetch(req);
}
});
```

This code will show the comment `// Sorry no source code for you` for every request to JavaScript
files from the browser (if open in a new tab). When you want to view the file the browser sends
`Accept: text/html` HTTP header.

### File system middleware

```javascript
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
the prefix `__fs__` like `./__fs__/foo` it will read files from the indexedDB file
system named `__wayne__`. See [Lightning-FS](https://github.com/isomorphic-git/lightning-fs) repo for details about the library.

From version 0.12 you can use `test` callback option to check if the file should serve from the filesystem. Note that it will receive URLs from all domains.

From version 0.13.0 you can use `dir` callback function that allow to dynamically change directory of served files.

```javascript
const test = url => {
const path = url.pathname;
// return true if pathname should go to filesystem
return path.match(/__fs__/);
};

const dir = () => '/';

app.use(wayne.FileSystem({ path, fs, mime, test, dir }));
```

From version 0.14.0 both functions `dir` and `test` can be async. So you can use data from IndexedDB
e.g. using [idb-keyval](https://github.com/jakearchibald/idb-keyval) by Jake Archibald.

A patch in 0.14.3 allow putting interceptors to inject something into output HTML from FileSystem
middleware. You do this by adding middleware before FileSystem and patch `res.send` method:

```javascript
function fs_interecept(callback) {
return function(req, res, next) {
const send = res.send.bind(res);
res.send = function(data, ...rest) {
const url = new URL(req.url);
if (test(url)) {
data = callback(data);
}
return send(data, ...rest);
};
next();
};
}

app.use(fs_interecept(function(html) {
return html.replace(/<\/body>/, `console.log('intercepted')

This request is blocked