PWA and Babylon

I am trying to add PWA offline support to a Babylon app, to run it without internet on a Pico 4 VR glass set. At first this seemed to work fine, but then I discovered that it did not really cache all the necessary resources.
When wrting the ServiceWorker sw.js one apparently has to specify a list of all files that should be cached. I can do this for my app, but how can I find out all the necessary resources which Babylon needs and supposedly also all the Babylon internel .js files? Is there such a list, which could be used?

Or is there a better way around to automatically cache all the needed resources for offline use?

I did find this post:

but I could not really understand the way the caching is done there and how it knows about which files and assets to cache.

It seem somewhat more complex than I first thought since Babylon has its own caching mechanism.
However, this seems a great resource:

Did you get this working?

It’s easiest when you are using something like webpack, but the general idea is that you use tooling to generate a file manifest that knows the dependencies (essentially, your node_modules) of your code via import or require statements.

ServiceBox is the node package I used to make Space-Truckers: The Video Game that formed the basis for my book, and I found it super simple to get working.

The caching is done by specifying a pre-fetch list of URL’s as part of the PWA/SW registration scripts. Subsequent requests for the same URL will be intercepted and return the cached version from the SW.

HTH!

2 Likes

Yes. I works. However, you need to load the installed app at least once before you can go offline.
An important ingredient is:
engine.enableOfflineSupport = true;
somewhere at the beginning of createScreen().

If you have a typo in one of the filenames to preload, the whole cache.addAll() call fails without telling you which of the files it had problems with. So you need to test them individually to find your typo.

This is why I’d recommend tooling to generate the list of files to preload - one less thing to worry about or do when you change assets!

If you’re not using something like ServiceBox and/or WebPack, one simple way to accomplish this could be to write a shell script that searches through your source code to find strings representing URLs, then spits out a list of those into a file that you can then curate and use with your manifest. It’s not a complete solution, but it’s enough that you won’t have to worry about typos at least :grin::sunglasses:

1 Like

The service worker that I linked above seems to have a pretty smart system even using a cache database. But on the second day it turned out the the PWA that was perfectly running on day one must have dropped its cache on day 2 and it did not work any more on the pico 4 without reconnecting. Not sure how to track down what is the problem.

You should be able to cache offline everything. I was hoping for some more guidance after this was posted: Babylon CDN Traffic Increase - Announcements - Babylon.js (babylonjs.com)

If you can share what’s not being cached would be helpful. I remember the first time I wanted to demo babylon.js offline was an XR demo and the models weren’t loading! LOL.

The problem seems to be that I did not explicitely cache the babylon core parts. If I remote-debug the Pico 4, after a day or two it has forgotten the babylon.js core parts:

Failed to load resource: net::ERR_INTERNET_DISCONNECTED
babylon.js:1 Failed to load resource: net::ERR_INTERNET_DISCONNECTED
babylonjs.proceduralTextures.min.js:1 Failed to load resource: net::ERR_INTERNET_DISCONNECTED
babylonjs.materials.min.js:1 Failed to load resource: net::ERR_INTERNET_DISCONNECTED
babylonjs.postProcess.min.js:1 Failed to load resource: net::ERR_INTERNET_DISCONNECTED
babylonjs.loaders.js:1 Failed to load resource: net::ERR_INTERNET_DISCONNECTED
babylon.gui.min.js:1 Failed to load resource: net::ERR_INTERNET_DISCONNECTED

Previously I tried putting the network locations on the list of files to cache, but this also did not seem to work right. Do I need to download them individually and make my app point to local copies? But then where can I find such a list of dependencies, as it seems that Babylon.js might itself import a number of things (WebGL?). I see that you link seems about this, but I have to admit, that I understand very little of it. (What is a “CDN”? What is “PHP”?)
The command npm install --save babylonjs worked, but I am not sure how to then use the downloaded package. My project currently is JavaScript (not Typescript) and so far I was importing the Babylon packages via <script> tags. I could not locate the npm installed package and dont know how to then serve it from my github.io webpage such that it can be cached in the PWA.

All of those files are available on our CDN, which can be used as the URL for the caching mechanism.

I think there are two caching concepts here that are a bit mixed. The first is the cached javascript files that are the base code for your app, and the other is caching mechanism for your assets (and correct me if I am wrong!). The first can be solved with the CDN (if that is an acceptable solution). You can also build your own app with all of the dependencies, deploy it to your own server (or github.io) and serve it. It will be more effecient, but will require using a build system for your app.

Personally, I am a bit confused as to what exactly is the problem right now, but this might be that I am missing the code/project or an example of what youa re doing now and what exactly isn’t working. But I will be happy to provide any help, if I can :slight_smile:

2 Likes

About the NPM stuff, you may want to research about javascript build systems. They are tools that can take your javascript project, with the npm dependencies and all, perform a bunch of operations (such as bundling), and output files ready to serve. There are many, maaaany build systems, but some famous ones are webpack, parcel and vite. Raanan has an awesome sample project that uses webpack: RaananW/babylonjs-webpack-es6: Babylon.js basic scene with typescript, webpack, es6 modules, editorconfig, eslint, hot loading and more. Will even make coffee if you ask nicely. (github.com) which is a great reference on getting started with a build system in a Babylon context. Webpack’s page also has a guide on PWAs: Progressive Web Application | webpack

I hope this gives you a bit more context and let me know of any questions :slight_smile:

1 Like

Building off of @carolhmj ’s great suggestions, you can also see how Space-Truckers is packaged and made available as a PWA using webpack and regular JavaScript.

If you’re looking for something more in-depth, there are chapters in my book which explicitly cover the topics of building, packaging, and deploying your BJS web application, including step by step on making a PWA.

HTH!

3 Likes

I think due to cors policy there may be a problem with caching these URLs`?

Somehow they show up in the “precache” tab (not so in the “runtime” cache), but with a content legth of zero. I guess the browser anyway caches them separately so it works for a day even with out internet connection, but the next day, it fails.
Interestingly the Axaj one seems to be fine (see last line).
I will try downloading these files by hand now and see if it works then.

It feels like these files are server locally?

AFAIK we don’t serve datgui on our CDN.

If this is the case, this is your server’s configuration that is missing the cors return headers

Thanks for the hints. In the above the non-local network links were just included in the list of files to cache.
The server serving the app is github.io. No idea how to configure this.
I tried with the downloaded babylon.js (etc.) files and then get (after a day) the Warnings, that it cannot find the
babylon.js.map file and similarly “.map” files for all others.
And this error:

Finally it seems to work now, Here is a step-by-step instruction what to do to make your Babylon App also work in offline mode:

  1. Follow the instructions provided here: Using WebGL and PWA to build an adaptive game for touch, mouse and VR devices – David Rousset . This results in creating a manifest and a serviceworker JavaScript.

  2. Search in the code of your own app for fetch commands, which use http: or https: addresses. Download those assets (right-click in chrome) and place them in your local assets folder and change the fetch command to the local assets path.

  3. put the line engine.enableOfflineSupport = true; as the first entry in your create_scene() function. This enables an extra assets caching mechanism of Babylon.

  4. create a folder babylon in your app and download the following files (and possibly more files referenced by <script> tags in your index.html file) into that folder:
    https://cdn.babylonjs.com/babylon.js
    https://cdn.babylonjs.com/babylon.js.map
    https://cdn.babylonjs.com/dat.gui.min.js
    https://cdn.babylonjs.com/earcut.min.js
    https://cdn.babylonjs.com/babylonjs.materials.min.js
    https://cdn.babylonjs.com/babylonjs.materials.min.js.map
    https://cdn.babylonjs.com/babylonjs.proceduralTextures.min.js
    https://cdn.babylonjs.com/babylonjs.proceduralTextures.min.js.map
    https://cdn.babylonjs.com/babylonjs.postProcess.min.js
    https://cdn.babylonjs.com/babylonjs.postProcess.min.js.map
    https://cdn.babylonjs.com/babylonjs.loaders.js
    https://cdn.babylonjs.com/babylonjs.loaders.js.map
    https://cdn.babylonjs.com/babylon.gui.min.js
    https://cdn.babylonjs.com/babylon.gui.min.js.map

  5. Replace your https://cdn.babylonjs/... entries (<script src="...">) in your index.html file with the local versions <script src="babylon/...">

  6. Add all of your assets (including the ones downloaded under section 2.) and the downloaded Babylon files as strings to the list (here PRECACHE_URLS) in your service worker JavaScript file (here pwabuilder-sw.js), see applescrusher/pwabuilder-sw.js at master · davrous/applescrusher · GitHub which will allow them to be cached. Here is a list of the babylon files you can cut-and-paste:
    ‘babylon/babylon.js’, ‘babylon/babylon.js.map’, ‘babylon/dat.gui.min.js’, ‘babylon/earcut.min.js’, ‘babylon/babylonjs.materials.min.js’, ‘babylon/babylonjs.materials.min.js.map’, ‘babylon/babylonjs.proceduralTextures.min.js’, ‘babylon/babylonjs.proceduralTextures.min.js.map’,
    ‘babylon/babylonjs.postProcess.min.js’, ‘babylon/babylonjs.postProcess.min.js.map’, ‘babylon/babylonjs.loaders.js’, ‘babylon/babylonjs.loaders.js.map’, ‘babylon/babylon.gui.min.js’, ‘babylon/babylon.gui.min.js.map’,
    Be ware that a type here is critical and will cause an error in the whole caching process. See last point below on how to do checks.

  7. Increase the version number in your serviceworker file by one, e.g. const PRECACHE = 'precache-v002';.

  8. Deploy your app.

  9. Test your app by installing the PWA, installing from the deployed source, running it once, turning off the internet connection, making sure that you can still start without internet, and waiting for at least one night and try to then start it again without having turned on the internet connection in the mean time. You can see if everything was cached OK by using ... -> Open in Chrome and in the chrome menu More Tools -> Developer Tools -> Application -> Chache Storage -> precache_vxxx with the current number in xxx (002 in the example above) and the runtime entry.

2 Likes

… it seems that there was a recent change in the Babylon structure. The new list of babylon core files that you should cache in your serviceworker:
https://cdn.babylonjs.com/earcut.min.js
https://cdn.babylonjs.com/babylon.js
https://cdn.babylonjs.com/gui/babylon.gui.min.js
https://cdn.babylonjs.com/loaders/babylonjs.loaders.min.js
the loader is needed, if you use the 3D slider GUI or alike, since this requires loading the .glb files in the assets folder. I also had to cache the following babylon assets:
‘babylon/assets/Droid Sans_Regular.json’,
‘babylon/assets/mrtk-fluent-backplate.glb’,
‘babylon/assets/mrtk-mrdl-backplate-iridescence.png’,
‘babylon/assets/profilesList.json’,
‘babylon/assets/right.babylon’,
found out by chrome complaining of missing these, but I did not write down the origins for them.