How to properly use the link href in websites for ideal IPFS and browser usage?

Hi,

In the centralized world using a CDN to serve your commonly used javascript and css files (say like jQuery or Bootstrap) is advised for a variety of reasons. Most of them still hold true, but only if applied to a centralized world.

Using a CDN in a decentralized world all of a sudden gives your super awesome cool shiny website a single point of failure! I personally found this out a couple times now when once of my IPFS play sites was acting suspiciously slow. I am using Bootstrap and the CDN to serve it was acting really slowly (in this case it was this file on bootstrapcdn).

This made me think, why would i use a CDN at all? Sure, in the old paradigm of centralized sites the before mentioned reasons in favor of it still hold. But in a distributed world this can be painful.

Now i want to change this on my sites to be content that is served from IPFS. But when changing it i began to wonder how to even do this in such a way that it’s most efficient for IPFS and the browser?

Lets take just the css bootstrap as an example.
Before i changed anything (thus when using the CDN) i had:

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

Now i can use a relative path (and drop the rest) which makes it look like:

<link rel="stylesheet" href="bootstrap.min.css">

Or i can use a specific IPFS path (only works if ipfs is in the protocol list and set with companion)

<link rel="stylesheet" href="ipfs://QmNrgEMcUygbKzZeZgYFosdd27VE9KnWbyUD73bKZJ3bGi">

(sidenote here, how do i get bafy... by default when doing ipfs add?)

Another alternative is to use a gateway (at the cost of adding a single point of failure again):

<link rel="stylesheet" href="https://ipfs.sc2.nl/ipfs/QmNrgEMcUygbKzZeZgYFosdd27VE9KnWbyUD73bKZJ3bGi">

What am i supposed to provide in the href section to make full use of IPFS? By that i mean that the browser requests the data from IPFS and uses that as cache. I’m asking because the browser (chrome in this case) and based on this information likely has no clue that the file came from IPFS. Therefore it likely doesn’t know that bootstrap.min.css is shared over multiple sites and thus downloads it for every site.

That results in the very same file living in the cache multiple times.

I suppose i’m asking if IPFS companion integrates into the browser cache as well? So that the cache knows that bootstrap.min.css is content address QmNrgEMcUygbKzZeZgYFosdd27VE9KnWbyUD73bKZJ3bGi and fetches it from IPFS. And does not cache it locally at all besides perhaps a name -> content hash lookup? This would be the ideal solution if the browser cache “knows” about IPFS!

Note that the browser can actually know this if it, behind the scenes, lists the files of that site in IPFS commands (say ipfs ls) which would tell the browser that bootstrap.min.css is QmNrgEMcUygbKzZeZgYFosdd27VE9KnWbyUD73bKZJ3bGi.

Before one suggest to go for the third option (this ipfs://QmNrgEMcUygbKzZeZgYFosdd27VE9KnWbyUD73bKZJ3bGi), that’s not really an option as the site then doesn’t work on a browser that knows nothing about IPFS.

I’m curious about your opinions :slight_smile:

Cheers,
Mark

Personally, I go with the relative path for all site assets (images, stylesheets, javascript). Any assets that are shared with other sites, either deliberately or by coincidence end up with the same CID and so get de-duplicated by IPFS nodes. For links to external IPFS sites I use https://ipfs.io/ and use a script to detect the gateway being used and rewrite all the links to use the same gateway. That way the links still work if JavaScript is turned off.

I too would go for relative paths.

Yes, that’s the beauty of hashing and the merkle tree :slight_smile:

But the browser doesn’t know that.
So if i add that very same asset in site X and Y that asset gets stored twice in the browser cache.

Or rather, that’s my assumption. That’s why i’m asking if the browser is actually doing that or if IPFS (companion?) has more in depth knowledge and somehow lets the browser fetch the files from IPFS without it storing a local cache too?

Unfortunately, I think the answer for what is best in regards to IPFS is different than what is best in regards to the browser.

If you are looking at just the browser, the CDN links make sense for the exact same reasons they make sense when IPFS is not involved. Whether the browser will perform content-based de-duplication is dependent on the browser cache implementation. Multiple websites using the same resource with different URLs is not unique to IPFS sites, so there is a possibility it gets done. It’s just that I’m not familiar enough with any browser to know if de-duplication is actually done in any of them.

Regardless, I would still recommend relative paths and including assets in the site in anticipation of browsers gaining native IPFS support, because then the browser will have to perform de-duplication.

Something really clever about IPFS is the browser addon. It allows you to specify a gateway (a single point of failure) and anyone with IPFS installed will find their browser magically redirecting to their local IPFS node, ignoring your gateway. So it works for people with IPFS, and it “works” for people who won’t use IPFS, with the gateway as a fallback.

That being said, I think you’re best going with relative links. We’ll access your website at something like http://localhost:8080/ipfs/Qabcdefghijklmnop/index.html so a link like “bootstrap.min.css” would resolve to "http://localhost:8080/ipfs/Qabcdefghijklmnop/bootstrap.min.css." Thus relative links have an implied content hash, just as secure as specifying it in the link itself!

When a browser’s cache fills up, it deletes least used files, including the copy of other site’s megagooglehooflare.totallynotavirus.min.js. So unless your file is so huge it will destroy a browser’s cache, we won’t even notice the redundancy. Of course if you go back to the old site, your browser has forgotten about the file, but ipfs hasn’t. So you’ll “download” it super fast since IPFS has a local copy for both sites.

I think i just had a super awesome idea! :slight_smile:
Weird way to start a reply like that, lol.

Forget the fact that a browser has it’s own copy.
If IPFS companion knows that the IPFS client runs on the same machine too then it “could” make symbolic links instead of copying the file! This would make the file caching be in IPFS where you’d expect it and would give the browser direct access to the file (as a symbolic link does that too, the file is just stored somewhere else on the filesystem).

Just a random thought i had :slight_smile:

I do wish html would have something like:

<link rel="ipfs stylesheet" href="QmNrgEMcUygbKzZeZgYFosdd27VE9KnWbyUD73bKZJ3bGi">

The intention here is that in the rel attribute you specify ipfs which would give new meaning to the href attribute where you now specify the IPFS resource. In my idea for this (just thinking out loud here) the browser would skip handling that rel if it contains ipfs and lets a third party handler (say IPFS Companion) handle it. By handling it i mean getting the content from that file.

or even better:

<link rel="ipfs stylesheet" href="bootstrap.min.css">

where it would work the same as above but internally IPFS Companion would know that it’s in the site with some Qm... hash and figure out that Qm.../bootstrap.min.css resolves to QmNrgEMcUygbKzZeZgYFosdd27VE9KnWbyUD73bKZJ3bGi. This version would be backwards compatible with the web as is.

Again, i’m just throwing out ideas now. Nothing of this exists.
But… IPFS Companion could potentially add support for this?!
@lidel, i’m curious what you think about it!

You want to get familiar with https://docs.ipfs.io/how-to/address-ipfs-on-web/

TLDR to ensure seamless upgrade and backward-compatibility with the old web use relative or absolute URLs that include content-addressed paths:

<link rel="stylesheet" href="https://ipfs.sc2.nl/ipfs/QmNrgEMcUygbKzZeZgYFosdd27VE9KnWbyUD73bKZJ3bGi?filename=style.css">
<link rel="stylesheet" href="/ipfs/QmNrgEMcUygbKzZeZgYFosdd27VE9KnWbyUD73bKZJ3bGi?filename=style.css">

Browsers that support IPFS (either by means of IPFS Companion extension or native support in the future) will recognize content path /ipfs/QmNrgEMcUygbKzZeZgYFosdd27VE9KnWbyUD73bKZJ3bGi and load your asset over IPFS instead of HTTP. Everyone else will still get the correct data from your public gateway, which makes everyone happy.

@markg85 Good news: IPFS Companion already automatically detects all content-addressed paths on websites and redirects those requests to a local gateway (provided by go-ipfs or IPFS Desktop), so there is no need for any custom notation, it “just works” :slight_smile:

1 Like