Skip to content
This repository has been archived by the owner on Sep 29, 2023. It is now read-only.

Discussion: Offline Support #680

Open
ibash opened this issue Sep 8, 2018 · 21 comments
Open

Discussion: Offline Support #680

ibash opened this issue Sep 8, 2018 · 21 comments

Comments

@ibash
Copy link

ibash commented Sep 8, 2018

Is anyone else interested in offline support?

I'm using nativefier for Safari Books Online, and I'd like to cache the site and content so I can read anywhere. I've built offline web apps before, so I have some thoughts on how to implement this. Would anyone else be interested in this?

@ghost
Copy link

ghost commented Sep 8, 2018

I would be interested.

@ibash
Copy link
Author

ibash commented Sep 9, 2018

Started to work on a proof of concept.

I think this should work by:

  1. Inject a service worker into the site
  2. Use something like sw-toolbox to do a network first cache
  3. Make the routes and pre-caching customizeable

I'm running into trouble injecting the service worker (chrome doesn't want you to do that for security reasons). Here are the approaches we can try:

  1. use protocol.interceptHttpProtocol

    The caveat is that you need to use a different session to actualy send the requests. I experimented a small bit with this. I think this is still viable, but may lead to annoying edge cases.

  2. use webRequest.onBeforeRequest and redirect the service worker url

    This fails with a mysterious error. Chrome doesn't want you to do this, but it might still be viable using a custom protocol. I haven't looke into the error yet.

  3. disable security on the web contentso

    Fairly confident this would work, but I haven't tried it yet.

  4. use a proxy

    This is probably the best way to go.

  5. serve the website from a custom protocol

    If you do that then you can make that custom protocol serve the service worker.

@niutech
Copy link

niutech commented Sep 12, 2018

It's a great idea to enable offline mode. You could bundle a caching proxy server in node.js, e.g. node-caching-proxy, node-http-cache, node-fishback or node-http-proxy with caching middleware, then pass all the requests through it.

@ibash
Copy link
Author

ibash commented Sep 22, 2018

I have a proof of concept working on my machine using interceptStreamProtocol. Cleaning up the code and then will send a PR :)

@ibash
Copy link
Author

ibash commented Sep 24, 2018

I got this mostly working but hit this bug in electron. Once that's fixed, this should work. If anyone is interested the code is here: https://github.com/ibash/nativefier/tree/offline_2

@ghost

This comment has been minimized.

@ibash
Copy link
Author

ibash commented Oct 24, 2018

My fix for electron should land soon: electron/electron#14887 after that I can go back to hacking on it in https://github.com/ibash/nativefier/tree/offline_2.

@puneetsl

This comment has been minimized.

@ibash
Copy link
Author

ibash commented Jan 11, 2019

@puneetsl proof of concept works. Electron merged my initial fix but not the backported fix: electron/electron#16209

@louguitar
Copy link

Did you ever get this working? I am looking for a way to create an offline nativfier app.

@ibash
Copy link
Author

ibash commented May 28, 2019

@louguitar not all the way.

The problem I ran into was electron/electron#16421. The summary: my approach was to intercept network requests using electron's apis. If you choose to intercept there's a lot of built-in chrome functionality that gets bypassed (like cookie handling, checking certificates, etc). This leads to a whack-a-mole of trying to recreate chrome's network handling.

I haven't looked at what's changed in electron, but if there was an api that allowed injecting a service worker or the ability to both intercept and then send network requests back to chrome, that would make this trivial to implement.

@ibash
Copy link
Author

ibash commented Jun 2, 2019

I found a workaround.

You can inject a service worker without disabling web security by:

  1. Enabling service workers on the filesystem scheme
  2. Creating a service worker script using the html5 filesystem api
  3. Registering the file created

The works because "filesystem:https://example.com" and "https://example.com" are considered to have the same origin. See this comment in chrome.

One gotcha was that enabling service workers for the filesystem scheme needs to be done on the command line and not with protocol.registerSchemesAsPrivileged.

I've made an example here: https://github.com/ibash/service-worker-experiment
If you clone the service-worker-experiment repo and do yarn start you will see:

  1. https://example.com is loaded
  2. A service worker is registered that's defined in service-worker-loader.js

So: With this technique we could enable injecting service workers into arbitrary sites. Once you're able to inject a service worker, you can use them to cache network requests to make a site work offline.

The only gotcha is that to make this robust we need to use the electron webRequest api to allow service workers and get rid of any CSP restrictions.

@ErickOhm
Copy link

is there an update to this? I'm trying to add offline functionality to a website (jstris) if you save the page you get the html/css/js files needed to play offline single player, so I'd like to have this on my app too, it's basically just 1 html file and that links to the css/js and some images, can I add these files to the project or is there a better way to do this?

@ibash
Copy link
Author

ibash commented Jun 21, 2020

@erickmack I didn't continue working on it, you could moving the two commits in this proof of concept: https://github.com/ibash/service-worker-experiment and then adding a service worker to see if that lets you make it work offline.

I haven't tried running it in a while, so really not sure if it will work.

@tarruda
Copy link

tarruda commented Oct 16, 2020

Hi @ibash, it seems https://github.com/ibash/service-worker-experiment is not accessible. Any chance you could publish it again?

@ibash
Copy link
Author

ibash commented Oct 16, 2020

Hi @ibash, it seems https://github.com/ibash/service-worker-experiment is not accessible. Any chance you could publish it again?

Done!

@tarruda
Copy link

tarruda commented Oct 16, 2020

Hi @ibash, it seems https://github.com/ibash/service-worker-experiment is not accessible. Any chance you could publish it again?

Done!

Thank you very much!

@tarruda
Copy link

tarruda commented Oct 17, 2020

Since the service-worker solution didn't work on electron 8, I ended up patching intercept*Protocol APIs to allow selecting which URLs are intercepted: https://gist.github.com/tarruda/554962f987f7f3a1a94d2c1c76c880a8#file-allow-url-patterns-intercept-protocol-diff-L186

@ibash
Copy link
Author

ibash commented Oct 17, 2020

nice!

  1. curious what you're working on / what you need offline for?
  2. one gotcha with the intercept route (unless I'm misremembering) is that the chrome network stack had some differences of how it handles requests than with the node.js network stack, I can't remember the actual implications.

@tarruda
Copy link

tarruda commented Oct 17, 2020

curious what you're working on / what you need offline for?

I use it to replace the response of an external resource (say www.example.com) with my own cached version while keeping chromium "thinking" it was loaded from the right origin, so no CORS headers are necessary.

one gotcha with the intercept route (unless I'm misremembering) is that the chrome network stack had some differences of how it handles requests than with the node.js network stack, I can't remember the actual implications

Yes, there are differences, which is why I wanted to continue using chromium network stack for all other URLs except the ones I need to intercept. For simple resources such as static pages, returning a simple response from the intercept handler is often enough to make everything work.

@alexjyong
Copy link

Anything with this?

I'm trying to make this website work in an app for easy use: https://eloquentjavascript.net/

Since saving the files and running it via file://path/to/html/file doesn't work.

I can run python3 -m http.server 8000 to get it to work. But trying to set this up so folks can use it offline without having to mess with the terminal

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

8 participants