dshop
dshop copied to clipboard
Serve UI via IPNS / DNSLink
Right now the UI and shop data are bundled under a single IPFS hash which means every shop would need to be redeployed in order to get UI updates.
Instead, we could have the UI served via IPNS / DNSLink from, eg, /ipns/ui.ogn.app so that all shops can get UI updates at the same time.
To prevent caching issues we could do something like append the current timestamp to the bundle files (to the nearest 5 mins). eg Math.floor(+ new Date()/1000 / 60 / 5)
Think I'd like to take a stab at this. Probably a good time to deal with #120 as well.
Think I'm going to build a CI/CD pipeline to handle this and update the DNS records on the fly. Thinking we should build a dist package for every release(saved as a cloudbuild artifact if possible), but bundle the last N
releases in the IPFS directory, which is then served from the ipfs-cluster via DNSLink record for ui.ogn.app
.
So, it would be like...
- ~~
/ipns/ui.ogn.app/index.html
~~ -
/ipns/ui.ogn.app/builds.json
-
/ipns/ui.ogn.app/[build_hash1]/app.css
-
/ipns/ui.ogn.app/[build_hash1]/app.js
-
/ipns/ui.ogn.app/[build_hash2]/app.css
-
/ipns/ui.ogn.app/[build_hash2]/app.js
- ...
Perhaps we could add a file like builds.json
that the cached app can check to see if it's the latest bundle? If it's out of date it could toast request a reload by the user.
Thoughts?
Thinking about this a bit more. index.html
is probably going to have to be part of the store deployment. That and the config/product data. The HTML file will be what loads the assets from ui.ogn.app
.
Thanks for writing down your thoughts. In terms of wanting to bundle the last N releases in the IPFS directory, what are the use cases you are thinking of? To be able to rollback to an older version? If it adds complexity I'd be fine only having the latest version.
Historical bundles are specifically to deal with #120
Yea since index.html is the file that'll refer to the build files, I'm not sure it can include build hashes. Right now, the index.html for each store is essentially this:
<!doctype html>
<html lang="en" dir="ltr">
<head>
<title>Dshop</title>
<link rel="stylesheet" href="app.acb54700.css" crossorigin="anonymous" />
</head>
<body>
<div id="app"></div>
<script src="dist/app.acb54700.js" crossorigin="anonymous"></script>
</body>
</html>
I'm proposing that we instead set it to this:
<!doctype html>
<html lang="en" dir="ltr">
<head>
<title>Dshop</title>
<link rel="stylesheet" href="https://ui.ogn.app/app.css" crossorigin="anonymous" />
</head>
<body>
<div id="app"></div>
<script src="https://ui.ogn.app/app.js" crossorigin="anonymous"></script>
</body>
</html>
The bundles on https://ui.ogn.app would then always be up to date. Another option is to have a bootstrap script that detects if the site is being served from IPFS and load via DNSLink if so, ie:
<!doctype html>
<html lang="en" dir="ltr">
<head>
<title>Dshop</title>
<link rel="stylesheet" href="/ipns/ui.ogn.app/app.css" crossorigin="anonymous" />
</head>
<body>
<div id="app"></div>
<script src="/ipns/ui.ogn.app/app.js" crossorigin="anonymous"></script>
</body>
</html>
For advances users, we can give them the option to deploy their shop and include the bundles, or refer to our bundles. For our bundles, it might be good to have a major version number included incase we have breaking changes that'd cause older shops to stop working for whatever reason (eg we update the data schema).
If we skip hashes in the URLs we end up with the problem they are originally there for, caching. users could end up seeing CSS and JS fles that doesn't jive with eachother. That's also why I suggested builds.json
for the dapp to check if it's up to date and force a reload if necessary.
I think this might need to be a bit more intelligent than pointing it at ui.ogn.app/app.js
.
Yea, perhaps we have a bootstrap JS script with a cache buster (eg append ?randomNumber to URLs) that has some logic to test for the latest version, perhaps via builds.json as you suggest. bootstrap.js can live alongside index.html.
I guess all this becomes a bit more complex when we try to generate HTML files for products and categories at build time for SEO 😬.
I agree we'll probably need some bootstrapping JS(maybe even just in the HTML file to reduce HTTP requests).
Do we want to address that SEO stuff now, then? That's quite the pickle. Do we just turn our SPA into a Jekyll build? Are there any ways to make SPAs crawler-friendly yet?
Will probably need to replace HashRouter with BrowserRouter. Might be as simple as generating the same simple HTML files with specific product metadata, which shouldn't be too bad. Though maybe we start with one thing at a time.
devops pipeline added in PR #454
Will do some testing, pair it with #459, tighten it up, and we should be good to go
FYI: Fiddling with GCP Cloud CDN in #495
Don't think this should wait for that, though there's a chance it'll be usable soon.
@nnick do you have any details on the issue you were stuck on? Might be good to document so some future people can maybe poke at this.
Yes we have a separate bundle for the Checkout page that for some reason wasn't being loaded from the CDN. It tries to load the bundle from the current domain instead of the CDN. The error shows when you go to the checkout when using a UI served from a CDN.
@mikeshultz @nick shall we move this to the backlog?
Sounds good