{"id":17914194,"url":"https://github.com/knadh/indexed-cache","last_synced_at":"2025-03-23T23:30:45.411Z","repository":{"id":38074240,"uuid":"400752743","full_name":"knadh/indexed-cache","owner":"knadh","description":"A tiny Javsacript library for sideloading static assets on pages and caching them in the browser's IndexedDB for longer-term storage.","archived":false,"fork":false,"pushed_at":"2022-07-13T15:29:40.000Z","size":212,"stargazers_count":81,"open_issues_count":0,"forks_count":17,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-18T03:58:52.951Z","etag":null,"topics":["bandwidth-saver","browser-cache","caching","cdn","css-loader","script-loader"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/knadh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-08-28T09:24:37.000Z","updated_at":"2024-12-18T14:47:54.000Z","dependencies_parsed_at":"2022-08-31T02:22:09.195Z","dependency_job_id":null,"html_url":"https://github.com/knadh/indexed-cache","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/knadh%2Findexed-cache","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/knadh%2Findexed-cache/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/knadh%2Findexed-cache/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/knadh%2Findexed-cache/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/knadh","download_url":"https://codeload.github.com/knadh/indexed-cache/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245186438,"owners_count":20574551,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bandwidth-saver","browser-cache","caching","cdn","css-loader","script-loader"],"created_at":"2024-10-28T19:56:41.927Z","updated_at":"2025-03-23T23:30:44.951Z","avatar_url":"https://github.com/knadh.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ca href=\"https://zerodha.tech\"\u003e\u003cimg src=\"https://zerodha.tech/static/images/github-badge.svg\" align=\"right\" /\u003e\u003c/a\u003e\n\n# indexed-cache.js\n\nindexed-cache is a tiny Javascript library that \"sideloads\" static assets (script, link, and img tags) on webpages using the fetch() API and caches them in an IndexedDB store to eliminate the dependency on the standard browser static asset cache, and to eliminate HTTP requests on subsequent page loads. Javascript, CSS, and image assets are stored in IndexedDB as Blob()s.\n\n### For very specific scenarios only\n\nThis library is only meant to be used in very specific scenarios.\n\nUnlike the browser's asset cache, IndexedDB is not cleared automatically, providing a longer term static file storage on the client side. The lib uses ES6 (and IndexedDB) and is only expected to work on recent versions of modern browsers. Ideally, this should have been handled with ServiceWorkers, but they don't work in mobile webviews.\n\nUse if at least a few of these are true:\n\n- There are large static files (JS, CSS) that rarely change.\n- High traffic from a large number of returning users who access web pages with the same assets regularly and frequently.\n- The pages are mostly inside mobile webviews where browser cache gets evicted  (OS pressure) causing the same assets to be fetched afresh over and over wasting bandwidth.\n- Bandwidth is a concern.\n\n### Features\n\n- Supports script, img, link tags.\n- Respects `defer / async` on script tags.\n- Can invalidate cached items with a TTL per tag.\n- Can invalidate cached items with a simple random hash per tag.\n\n### Gotchas\n\n- CORS.\n- First-paint \"flash\" (needs to be handled manually) as scripts and styles only load after HTML is fetched and rendered by the browser.\n- Browser compatibility.\n- Empty space or line breaks between the opening and closing `\u003cscript data-src=\"remote.js\"\u003e\u003c/script\u003e` tags will be executed as an inline script by the browser, after which the browser will not load the remote script when applied. Ensure that the opening and closing script tags have nothing between then.\n- Scripts that rely on the `document.onload` event will need the event to be triggered for them manually once indexed-cache loads with a `document.dispatchEvent(new Event(\"load\"));`\n\n## Usage\n\nTo cache and sideload static assets:\n\n- Change the original `src` (`href` for CSS) attribute on tags to `data-src`.\n- Give tags a unique ID with `data-key`. The cached items are stored in the database with this key. The actual filenames of the assets can change freely, like in the case of JS build systems.\n- Load and invoke indexed-cache at the end.\n\n#### Example\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n    \u003ctitle\u003eindexed-cache\u003c/title\u003e\n    \u003cmeta charset=\"utf-8\" /\u003e\n\n    \u003cscript data-key=\"bundle\" data-src=\"bundle_file1234.js\"\u003e\u003c/script\u003e\n\n    \u003clink rel=\"stylesheet\" type=\"text/css\"\n        data-key=\"style.css\"\n        data-src=\"style.css\" /\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    \u003ch1\u003eindexed-cache\u003c/h1\u003e\n\n    \u003cscript src=\"normal-non-side-loaded.js\"\u003e\u003c/script\u003e\n\n    \u003c!--\n        Whenever the value of data-hash changes (eg: from a build system)\n        or the expiry (optional) is crossed, the file is re-fetched\n        and re-cached.\n    //--\u003e\n    \u003cscript data-src=\"sideloaded.js\"\n        data-key=\"mybigsideloadedscript\"\n        data-hash=\"randomhash\"\n        data-expiry=\"2029-03-25T12:00:00-06:30\"\u003e\n    \u003c/script\u003e\n\n    \u003cimg data-src=\"thumb.png\"\n        data-key=\"thumb.png\"\n        data-hash=\"randomhash\" /\u003e\n\n    \u003c!--\n        Always include and invoke indexed-cache at the end, right before \u003c/body\u003e.\n        Use the unpkg CDN or download and host the script locally (dist/indexed-cache.min.js).\n    !--\u003e\n    \u003cscript src=\"https://unpkg.com/@knadh/indexed-cache@0.4.3/dist/indexed-cache.min.js\" nomodule\u003e\u003c/script\u003e\n\n    \u003c!-- Use this if you are supporting old browsers which doesn't support ES6. --\u003e\n    \u003c!-- \u003cscript src=\"https://unpkg.com/@knadh/indexed-cache@0.4.3/dist/indexed-cache.legacy.min.js\" nomodule\u003e\u003c/script\u003e --\u003e\n\n    \u003cscript\u003e\n        const ic = new IndexedCache();\n        ic.init().then(function() {\n            ic.load();\n        }).catch(function(err) {\n            console.log(\"error loading indexed-cache\", err)\n        })\n    \u003c/script\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n#### Load modern and legacy bundle conditionally\n\nHere is an example on how to load modern(ESM) bundle and legacy bundle conditionally based on browser support.\n\n```html\n    \u003c!-- Only modern browsers understand type=module and legacy browsers will skip this script --\u003e\n    \u003cscript type=\"module\"\u003e\n        // Use ESM bundle.\n        import IndexedCache from \"https://unpkg.com/@knadh/indexed-cache@0.4.3/dist/indexed-cache.esm.min.js\";\n        const ic = new IndexedCache();\n        ic.init().then(function() {\n            ic.load();\n        }).catch(function(err) {\n            console.log(\"error loading indexed-cache\", err)\n        })\n    \u003c/script\u003e\n\n    \u003c!-- This will only be executed on legacy browsers which doesn't support ES6 modules.\n    Modern browsers ignore the script if its tagged `nomodule`. --\u003e\n    \u003cscript src=\"https://unpkg.com/@knadh/indexed-cache@0.4.4/dist/indexed-cache.legacy.min.js\" nomodule\u003e\u003c/script\u003e\n    \u003cscript nomodule\u003e\n        const ic = new IndexedCache();\n        ic.init().then(function() {\n            ic.load();\n\n            // Optionally trigger `onload` if there are scripts that depend on it.\n            // document.dispatchEvent(new Event(\"load\"))\n        }).catch(function(err) {\n            console.log(\"error loading indexed-cache\", err)\n        })\n    \u003c/script\u003e\n```\n\n#### Optional configuration\n\nOne or more of these optional params can be passed during initialization. Default values are shown below.\n\n```javascript\nnew IndexedCache({\n    tags: [\"script\", \"img\", \"link\"],\n    dbName: \"indexed-cache\",\n    storeName: \"objects\",\n\n    // If this is enabled, all objects in the cache with keys not\n    // found on elements on the page (data-key) will be deleted.\n    // This can be problematic in scenarios where there are multiple\n    // pages on the same domain that have different assets, some on\n    // certain pages and some on other.\n    prune: false,\n\n    // Enabling this skips IndexedDB caching entirely,\n    // causing resources to be fetched over HTTP every time.\n    // Useful in dev environments.\n    skip: false,\n\n    // Default expiry for an object in minutes (default 3 months).\n    // Set to null for no expiry.\n    expiry: 131400\n}).load();\n```\n\n- `load()` can be called with a DOM Node or NodeList. When none are given, it scans the entire DOM.\n- To manually prune all objects in the database except for a given list of keys, after `await init()`, call `.prune([list of keys])`.\n\nLicensed under the MIT license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fknadh%2Findexed-cache","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fknadh%2Findexed-cache","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fknadh%2Findexed-cache/lists"}