GitHub Pages localStorage

When hosting a repositories' websites on GitHub Pages, all of the websites from the same GitHub account will share localStorage among themselves, because localStorage is scoped by the origin (scheme + host name + port):

localStorage
The localStorage read-only property of the window interface allows you to access a Storage object for the Document's origin. MDN
Origin
Web content's origin is defined by the scheme (protocol), hostname (domain), and port of the URL used to access it. MDN

This poses a challenge in case the account hosts multiple independent apps which all use local storage to persist their device-specific state.

localStorage is keyed by a simple string and most apps will opt to use short, plain and descriptive names for these keys; the type of keys that is highly likely to cause a collision when the local storage instance is reused across multiple sites on the same origin.

It is possible to work around this by meticulously prefixing (or in some other way distinguishing) the local storage keys by hand. However, this places undue burden on the developer and a mistake could lead to data corruption across multiple sites.

I am running into this situation with the many tools I make and store on GitHub and host via GitHub Pages. For this reason, I have decided to develop a localStorage wrapper which automatically prefixes the local storage entries' keys by the URL path name to make them unique across multiple sites on the same origin.

Example

Without github-pages-local-storage

#1 https://$user.github.io/$repoA

localStorage.setItem('test', 'test');

#2 https://$user.github.io/$repoB

localStorage.getItem('test'); // Prints `'test'` not `null` localStorage.setItem('test', 'test2');

#3 https://$user.github.io/$repoA

localStorage.getItem('test'); // Prints `'test2'` not `test`

As is apparent, the two sites on the same origin but different paths pollute each others local storages unintentionally. This can cause subtle bugs.

With github-pages-local-storage

#1 https://$user.github.io/$repoA

import 'https://tomashubelbauer.github.io/github-pages-local-storage/index.js'; localStorage.setItem('test', 'test'); // Stores `'test'` under the key `$repoA:test`

#2 https://$user.github.io/$repoB

import 'https://tomashubelbauer.github.io/github-pages-local-storage/index.js'; localStorage.getItem('test'); // Prints `null` localStorage.setItem('test', 'test2'); // Stores `'test'` under the key `$repoB:test`

#3 https://$user.github.io/$repoA

import 'https://tomashubelbauer.github.io/github-pages-local-storage/index.js'; localStorage.getItem('test'); // Prints `'test'` as expected

Prefixing the local storage keys has effectively solved the problem of the local storage being shared across the same origin unintentionally.

Usage

Add this code at the top of your entry point script: import 'https://tomashubelbauer.github.io/github-pages-local-storage/index.js';

Use localStorage as you normally would. Keys will now be prefixed by location.path. You can check this out in action using the form below.

Demo

Specify the key you want to test with:

Write any value to the key:

Read the value of the key:

Deleting is also taken care of:

Check out the browser developer tools to see the prefixed key by running localStorage. For key test you can expect the key /github-pages-local-storage/:test to appear in there.

Use the private mode in your browser to see the local storage in isolation and observe the effects of these methods that way if needed.

Notes

key, length, clear etc.

These methods aren't patched / wrapped yet. I generally don't use them all that much. Once I need them, I will patch them so they work with the scope storage. Let me know if you need these.

path-scoping in SPAs vs MPAs

By using `location.path` as the prefix for the local storage keys, the URL path as a whole becomes the scope of the local storage for that site. That means in case of an MPA (multi-page application) with different URLs for each view, a different local storage instance will be presented on each distinct page/URL. This tool is meant for SPAs (single-page applications).

file: protocol

When testing the app locally on the file: protocol with the github-pages-local-storage library references, the file's path becomes the scope of the local storage instance.

This is related to the above section; it is not going to be a problem for SPAs but will for MPAs. It will also be a problem in case the file ever moves to a new path (i.e.: is moved or renamed).

I am not planning on changing the scoping such that it is more friendly to MPAs because that is not my use-case and it is a non-trivial problem to solve while still making sense across both live and file: protocol accesses.


GitHub