Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

*.runtime.*.js is not added to Service Worker manifest #9309

Closed
alewcock opened this issue Oct 11, 2023 · 8 comments · Fixed by #9955
Closed

*.runtime.*.js is not added to Service Worker manifest #9309

alewcock opened this issue Oct 11, 2023 · 8 comments · Fixed by #9955
Labels
Stale Inactive issues

Comments

@alewcock
Copy link

alewcock commented Oct 11, 2023

🐛 bug report

The runtime js auto-generated file is not added to the Service Worker manifest, so it is not cached when installing a Service Worker update.

🤔 Expected Behavior

Expected it to be in the manifest.

🌍 Your Environment

Software Version(s)
Parcel 2.10.0
@alewcock alewcock changed the title *.runtime.*.js *.runtime.*.js is not added to Service Worker manifest Oct 11, 2023
@safouanmatmati
Copy link

safouanmatmati commented Oct 25, 2023

This is the case on "parcel": "2.9.3" too and cause web app "crash".

If a web app has already been cached by a client browser through the service-worker and a new deployment occurs, client browser fails to start the app as the cached index.html is referencing an index.runtime.[hash].js that has never been not part of the cached files and can't be retrieved from network anymore as it had been replaced by the new one.

Thank you for your help.

@alewcock
Copy link
Author

This is the case on "parcel": "2.9.3" too and cause web app "crash".

If a web app has already been cached by a client browser through the service-worker and a new deployment occurs, client browser fails to start the app as the cached index.html is referencing an index.runtime.[hash].js that has never been not part of the cached files and can't be retrieved from network too as it had beeen replaced by the new one.

Thank you for your help.

Indeed. We also found it on 2.9.3 (which was before "runtime" was added to the name) and were mystified as to what the file was. As a hack, we added logic in the sw install event to parse the html file and look for any rogue js files (ie. missing from the manifest), so that it could dynamically add them to manifest and then cache them.

@safouanmatmati
Copy link

safouanmatmati commented Nov 3, 2023

Thank you @alewcock for your help. I did as you explained, and after many changes it finally works.
I was using precacheAndRoute from Workbox package to handle pre-caching logical.
But parsing the html file requires asynchronous logical which can't be combined with this method.
I had to code my own pre-cache controller & route.

This workaround is a good solution but can require many changes, as in my case.

@SCdF
Copy link

SCdF commented Jan 7, 2024

This looks to have been broken in 2.9.0.

With the following 2.8.3 (the prior release) deps:

{
    "@parcel/packager-raw-url": "2.8.3",
    "@parcel/reporter-bundle-analyzer": "2.8.3",
    "@parcel/service-worker": "2.8.3",
    "@parcel/transformer-sass": "2.8.3",
    "@parcel/transformer-webmanifest": "2.8.3",
    "parcel": "2.8.3"
}

Every file (apart from the service-worker obviously) outputted for my build makes it into the manifest, where manifest comes from import { manifest, version } from '@parcel/service-worker';. Note that this output has no *.runtime.js files.

If I update to 2.9,0, the next available version, I am now missing two index.<hash>.js files, which are extra files generated in 2.9.0.

Moving on to 2.10.0, work has happened to rename the above two files to index.runtime.<hash>.js files., but they are still not in the cache.

So you can fix this by moving back to 2.8.3 (if you don't need anything from a later build).

SCdF added a commit to SCdF/sanremo that referenced this issue Jan 7, 2024
@SCdF
Copy link

SCdF commented Jan 7, 2024

So this looks like the code that generates the service worker manifest: https://github.com/parcel-bundler/parcel/blob/v2/packages/runtimes/service-worker/src/ServiceWorkerRuntime.js

My attempt to replicate its logic:

import { Parcel } from '@parcel/core';

const bundler = new Parcel({
  entries: ['.'],
  defaultConfig: "@parcel/config-default",
  targets: ["frontend"],
  mode: "production"
});

const res = await bundler.run();

const manifest = [];
res.bundleGraph.traverseBundles(b => {
  console.log({
    id: b.id,
    name: b.name,
    bundleBehavior: b.bundleBehavior,
    publicUrl: b.target.publicUrl
  })
  if (b.bundleBehavior === 'inline') {
    return;
  }

  manifest.push([b.target.publicUrl, b.name]);
});

console.log({ manifest })

does output a *.runtime.* file.

Though the whole thing is kind of confusing, my actual build (yarn parcel build --target frontend) outputs two runtime files, my test code above outputs one, and the manifest has none. TBC this 2x in the build and 1x in my hack happens to lots of resources, it's more just an indication that I have no idea what's going on 🤷

I'm wondering if the runtime stuff happens in some later step? So when the service worker is being compiled the runtime file creation hasn't happened yet?

@SCdF
Copy link

SCdF commented Jan 18, 2024

So I looked into this more: I'm not technically deep on either parcel or service workers, so I might just be holding it wrong, but AFAICT the service worker addon looks to be generally scuffed. I ended up writing my own post processor to inject stuff after Parcel is done, allowing me to stay on the latest parcel version.

If think if someone wanted to work out where the runtime stuff gets injected and how to get a plugin running after that point they could build one that works?

Here are things I think are problems:

  • version is the hash of the service worker file itself, taken before the manifest files are added (obviously), which makes it pretty useless as this file will typically never change, and when it changes you don't need to know about it via a hash. As I understand it the flow at least for workbox is that the remote service worker file is always queried on load and diffed (to work out if it needs to be replaced)
  • manifest is only the file names, which is mostly fine as there is a hash in the name, except there are some like index.html that get no hash in their name, so if they ever changes it isn't detectable
  • if you have multiple targets all resources for all targets make it into the manifest
  • except, as this ticket notes, that it doesn't find *.runtime.* files

The way I solved it was:

  • my service-worker has precacheAndRoute(['INJECT_MANIFEST_HERE']);
  • after a build is complete I run a script that
    • iterates over the client build directory, filtering out *.map and the service worker
    • for files that don't have a hash in their name, hash the file
    • generate a replacement array for the above that looks like [{url: "some.file.HASH.js", version: null},{url: "index.html", version: "the_hash_I_made"}...]

@alewcock
Copy link
Author

FWIW: we discovered that if you add the following to your package.json, parcel will not generate a runtime file:

"@parcel/runtime-js": { "splitManifestThreshold": 100000000 },

So, the issue here seems to have something to do with Cascading Invalidation: https://parceljs.org/features/production/#cascading-invalidation

Copy link

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Stale Inactive issues
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants