npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-local-webview

v0.0.2

Published

Run CSR and Unity WebGL bundles from durable local storage without giving up their HTTPS origin.

Readme

react-native-local-webview

Run CSR and Unity WebGL bundles from durable local storage without giving up their HTTPS origin.

LocalWebView keeps complete static web releases in application-owned storage and serves them at their original HTTPS URLs. It follows standard HTTP cache semantics while adding atomic generations, rollback, and explicit storage limits for large assets that should survive WebView-cache eviction.

Before installing

This package is designed for large CSR or Unity WebGL payloads where offline retention is worth an additional background download on first visit. An ordinary WebView remains the cheaper choice for small, always-online sites.

On iOS, preserving an HTTPS origin while returning local bytes requires private WebKit SPI. This can make an App Store submission ineligible. See iOS distribution constraint before adopting the package.

Installation

yarn add react-native-local-webview react-native-nitro-modules
cd ios && pod install

Requirements:

  • React Native New Architecture
  • iOS 16.4+
  • Android API 24+
  • react-native-nitro-modules

React, React Native, and Nitro are peer dependencies with * ranges.

Basic usage

import { LocalWebView } from 'react-native-local-webview';

export function Game() {
  return (
    <LocalWebView
      source={{ uri: 'https://game.example.com/' }}
      cachePolicy={{
        maxBytes: 800 * 1024 * 1024,
        maxGenerations: 2,
      }}
      onBundleStored={({ generationId }) => {
        console.log('Available offline:', generationId);
      }}
      onBundleError={console.error}
      style={{ flex: 1 }}
    />
  );
}

Use source={{ uri }} when migrating an existing WebView. Use virtualUrl for a component dedicated to one entry:

<LocalWebView virtualUrl="https://game.example.com/" style={{ flex: 1 }} />

Do not provide both.

Startup lifecycle

| State | Visible navigation | Durable-cache work | | ---------------------- | ---------------------------------------- | --------------------------------------------------------------------- | | First visit | Remote HTTPS immediately | Low-priority install begins ten seconds after the main document loads | | Fresh hit | Local files at the original HTTPS URLs | No network request and no payload hash | | Stale-while-revalidate | Local generation immediately | Only stale responses validate in the background | | Changed response | Current page remains unchanged | New atomic generation becomes available on the next mount | | Offline | Last HTTP-permitted generation | No origin connection required | | Failed install | Current remote/local page remains usable | Partial generation is discarded |

The ten-second delay is only for the first background installation. Cache hits have no timer: native code reads the persisted state and selects a generation before navigation without moving the asset inventory through React state.

A mounted generation is leased until its WebView unmounts. Pruning cannot remove files underneath a running page, and a local navigation failure can roll back to the previous complete generation.

Server configuration

Use ordinary browser cache headers. A practical immutable-release deployment looks like this:

# index.html: validate the release pointer, but allow instant stale startup
Cache-Control: max-age=0, stale-while-revalidate=86400, stale-if-error=604800
ETag: "index-v42"

# fingerprinted scripts and Unity artifacts
Cache-Control: max-age=31536000, immutable

Fresh resources produce no network request. A stale response is validated with If-None-Match or If-Modified-Since; 304 Not Modified refreshes metadata without reading or hashing the body. If a stale response has neither a validator nor a usable freshness lifetime, it must be downloaded again.

The policy evaluates:

  • response max-age, no-cache, no-store, must-revalidate, immutable, stale-while-revalidate, and stale-if-error;
  • request max-age, min-fresh, and max-stale;
  • Date, Age, Expires, ETag, Last-Modified, and legacy Pragma;
  • Vary request matching; and
  • all Fetch-compatible cache modes described below.

A required response marked no-store or Vary: * cannot be published as part of a durable complete generation. Runtime API responses outside the collected static graph are unaffected.

Cache modes

Set durableCacheMode without colliding with the Android WebView cacheMode prop:

<LocalWebView durableCacheMode="no-cache" virtualUrl="https://game.example.com/" />

| Value | Behavior | | ---------------- | --------------------------------------------------------------- | | default | Apply freshness, validators, and server stale controls | | no-store | Bypass durable storage and use the remote source | | reload | Bypass the stored generation and install a new one | | no-cache | Revalidate even when the stored response is fresh | | force-cache | Prefer a permitted stored response, including stale | | only-if-cached | Require a permitted stored response without opening the network |

Cache limits

<LocalWebView
  virtualUrl="https://game.example.com/"
  cachePolicy={{
    maxBytes: 800 * 1024 * 1024,
    maxGenerations: 2,
    maxInlineBytes: 4 * 1024 * 1024,
  }}
/>

| Option | Meaning | Default | | ---------------- | ------------------------------------------------- | ------: | | maxBytes | Accounted bytes retained for one cache root | 512 MiB | | maxGenerations | Complete generations retained for rollback | 2 | | maxInlineBytes | Largest parser-required resource folded into HTML | 32 MiB |

The default root is derived from the HTTPS origin in application documents storage. Use cacheDirectory to override it.

Supported web content

The static graph collector resolves:

  • classic and module scripts, including static and dynamic imports;
  • stylesheets, CSS imports, url(...), src, and srcset;
  • preload and module-preload resources;
  • classic and module Web Workers;
  • WebAssembly URLs; and
  • Unity loader, framework, .data, and .wasm artifacts.

Parser-required bounded resources can be localized into index.html. Large Unity, WASM, Range-read, and runtime-fetch artifacts stay as individual files and are streamed by the platform interceptor. Runtime requests absent from the static graph continue to the real HTTPS origin.

Origin, History API, and WebView compatibility

Local bytes are returned for their original HTTPS request URLs. The page keeps location.origin, isSecureContext, relative URL resolution, cookies, browser storage, CORS, same-origin checks, workers, and Range requests.

pushState, replaceState, back, forward, and go work normally and are reported through onHistoryChange:

import { useRef } from 'react';
import { LocalWebView, type LocalWebViewHandle } from 'react-native-local-webview';

const ref = useRef<LocalWebViewHandle>(null);

<LocalWebView
  ref={ref}
  virtualUrl="https://app.example.com/"
  onHistoryChange={({ url }) => console.log(url)}
/>;

ref.current?.goBack();

The handle also implements goForward, reload, stopLoading, injectJavaScript, postMessage, clearCache, clearHistory, clearFormData, requestFocus, getHistoryState, and rollback.

Props, events, and imperative methods track [email protected], but the platform views are implemented directly. POST bodies, custom entry headers, inline HTML, and non-HTTPS sources use direct mode automatically. Direct mode is also useful for an A/B measurement:

<LocalWebView durableCacheEnabled={false} source={{ uri: 'https://game.example.com/' }} />

Events and cache APIs

  • onBundleReady reports the generation selected for display.
  • onBundleStored reports a fully installed or revalidated generation.
  • onDurableCacheHit reports native lookup duration and the selected URL.
  • onCacheRollback reports recovery to the previous generation.
  • onBundleError reports cache-policy or background-installation failures.

Imperative cache helpers are exported for maintenance workflows:

import {
  cacheDirectoryForOrigin,
  clearLocalWebViewCache,
  resolveWebBundle,
  rollbackWebBundle,
} from 'react-native-local-webview';

const url = 'https://game.example.com/';
const directory = cacheDirectoryForOrigin(url);

await resolveWebBundle({ virtualUrl: url, cacheMode: 'reload' });
await rollbackWebBundle(directory);
await clearLocalWebViewCache(url);

Security boundaries

Only absolute HTTPS entries are mirrored. Cross-origin static assets require an explicit allowlist:

<LocalWebView
  virtualUrl="https://game.example.com/"
  trustedAssetOrigins={['https://cdn.example.com']}
/>

Redirect targets are checked one hop at a time, and Subresource Integrity is enforced when present. Entry and worker CSP headers fail closed unless content you control explicitly opts into allowContentSecurityPolicyBypass.

iOS distribution constraint

Android exposes local HTTPS response replacement through shouldInterceptRequest. iOS has no equivalent public WKWebView API, so the package registers an HTTPS NSURLProtocol through private WebKit SPI. Simulator E2E verifies the runtime behavior, but private SPI can make an App Store submission ineligible.

Known boundaries

  • Data-derived runtime URLs are not installed unless they are statically discoverable; they remain ordinary network requests.
  • The interceptor is not a Service Worker replacement.
  • First installation duplicates response traffic outside the entry critical path.
  • Simulator/emulator benchmarks do not replace physical-device validation.

Read the repository E2E guide for performance evidence and CONTRIBUTING.md for the persisted format and native execution flow.

License

MIT