Skip to content

Instantly share code, notes, and snippets.

@rxri
Last active April 24, 2025 12:08
Show Gist options
  • Save rxri/e561fff9a7a681565312c71829cb5184 to your computer and use it in GitHub Desktop.
Save rxri/e561fff9a7a681565312c71829cb5184 to your computer and use it in GitHub Desktop.
Technical explanation of V8 Snapshot in Spotify

Hi fellow reader,

I'm ririxi, core maintainer of spicetify. Some people asked me to do a technical explanation of what spotify shipped with macOS Intel versions. This would be my first time writing a post like this, so I apologize for any inscriptions.

What is V8 context snapshot?

Spotify under the hood uses CEF (Chromium Embedded Framework) which is a framework around chromium, essentially electron but for C++. Chromium uses a V8 which is a Javascript engine created by Google. V8 can generate serialized representation (bytecode) of the V8 engine's heap. It contains pre-initialized JavaScript objects and functions.

In simple words; V8 analyzes what provided blob (content of javascript file) uses, initializes needed functions and objects while compiling and then puts its heap into context. Since all of this is pre-initialized, app on the startup can get this context snapshot and very quickly load it into the webview resulting in better startup performance.

Modifying snapshot

My first thought was to modify the snapshot because it includes clear-text javascript file (that's because the blob is still included, only the executed functions and objects are pre-generated into bytecode). So... I made quick PoC to modify this by looking for start marker, and end marker, however this resulted in no results. It turns out that this file is in UTF-16LE and not UTF-8. Quick change and file was modified with our patches! But to my surprise or not, app started crashing. From what I found out while writing this post, V8 Context Snapshot contains a header with number of contexts, version (chromium related), rehashibility (no idea what's that for) and most importantly, checksum. We also found a reply from V8 developer on stack overflow saying that this format is undocumented and internal and that V8 will disregard any context not generated for right chromium version. Kinda wild I must say.

I dropped the idea of modifying the snapshot because it was too much work at this point.

What this context holds?

Spotify uses webpack like most of web apps nowadays with React & React Router. Since 1.1.56 their "codebase" is called "xpui" which essentially holds everything, from mini player to all pages etc. This change was made to make their code as cross-platform as possible (desktop / web).

Spotify still left most of the code in its own files, including something called xpui-snapshot.js. This file is a start point for webpack. It expects __webpack_modules__ variable to be available and load (most) webpack modules from it. start of xpui-snapshot.js

This is where our v8 context comes in. This context holds that __webpack_modules__ variable and loads it into webview. This includes xpui.js & vendor~xpui.js (that's how Spotify bundled their code in previous versions)

So, instead of modifying the binary file, I extracted the content from it, and saved it to xpui-modules.js file which then we applied our patches on. image

After doing so, I made spicetify to load xpui-modules.js (our patched one) before xpui-snapshot.js and that worked perfectly.

content of index.html

We now have working spicetify on Spotify version(s) that put xpui into v8_context_snapshot.bin!

We obviously lose some performance gains that Spotify made with this from this approach, but this ensures that spicetify continue working with new versions if they decide to go with this approach on all platforms :)

@Faf4a
Copy link

Faf4a commented Apr 22, 2025

nice read 🚀

@sanoojes
Copy link

Great job ❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment