Three-layer model
- Stremio Web — the browser UI. Handles rendering, navigation, and user input.
- stremio-core-web — the application logic, compiled to WASM and run in a Web Worker. Owns all state.
- Addons — external HTTP services that provide catalogs, streams, and metadata.
stremio-core-web connection
The bridge between the React layer and the WASM core isCoreTransport (src/services/Core/CoreTransport.js). It spawns a Web Worker (worker.js) and communicates through @stremio/stremio-core-web/bridge.
| Method | Purpose |
|---|---|
dispatch(action, field) | Send an action to a core model |
getState(field) | Read a model’s current state |
analytics(event) | Send an analytics event |
decodeStream(stream) | Decode a stream descriptor |
NewState event, which lists which models changed. The CoreEvent event carries named domain events such as SettingsUpdated.
State management
Route-level components subscribe to core state via theuseModelState hook (src/common/useModelState.js).
useModelState:
- Reads the initial state synchronously through
CoreSuspender. - Dispatches an optional load action via
React.useInsertionEffect. - Listens for
NewStateevents and re-fetches only when the relevant model changes. - Pauses updates when the route is not focused (
useRouteFocused). - Dispatches
{ action: 'Unload' }to the model on unmount.
CoreSuspender pattern
CoreSuspender (src/common/CoreSuspender.js) implements the React Suspense data-fetching pattern for core state.
The withCoreSuspender higher-order component wraps any component in a React.Suspense boundary and pre-fetches all model states before the component renders for the first time. This prevents layout flicker on navigation because the state is available synchronously via getState() inside the wrapped component tree.
useCoreSuspender hook exposes getState and decodeStream to components that need synchronous access to pre-fetched state.
Services layer
Five services are instantiated once inApp.js and made available to all components through ServicesContext:
Core
Manages the WASM core lifecycle and exposes
transport for dispatch/getState.Shell
Bridges the native Qt shell when running in the desktop app via a WebChannel transport.
Chromecast
Initialises the Google Cast SDK and exposes a Chromecast transport.
KeyboardShortcuts
Global
keydown listener that maps digit keys and Backspace to navigation.DragAndDrop
dragover/drop listeners. Handles .torrent files dropped onto the window.Router layer
Stremio Web uses a custom hash-based router (src/router/) instead of React Router. The router:
- Reads
window.location.hashon everyhashchangeevent. - Matches the path against a
viewsConfigarray of regexp–component pairs. - Maintains an ordered stack of active route views; navigating to a lower layer clears all views above it.
- Wraps each view in a
RouteFocusedProviderso that only the topmost view receives state updates.
Application bootstrap
App.js orchestrates startup in order:
initialized flag gates rendering. Until both Core and Shell have settled, a blank loader div is shown. This ensures no route component ever runs before the core transport is ready.
Provider tree
Once initialised, the component tree insideApp.js is:
ServicesProvider is outermost, so every component in the tree can call useServices() to access any service.