[READ-ONLY] Mirror of https://github.com/danielroe/cross-origin-storage. Load shared dependencies from Cross-Origin Storage (COS).
cross-origin-storage experimental nuxt vite vite-plugin
0

Configure Feed

Select the types of activity you want to include in your feed.

1# vite-plugin-cross-origin-storage 2 3> [!WARNING] 4> Experimental. The [Cross-Origin Storage API](https://github.com/WICG/cross-origin-storage) is an early-stage proposal with no native browser support yet, and this plugin's chunk format is not stable. Do not depend on it in production. 5 6A Vite plugin that extracts shared dependencies (such as `vue`) into **content-addressed** chunks that can be loaded from [Cross-Origin Storage (COS)](https://github.com/WICG/cross-origin-storage). When two sites build the same dependency at the same version, they produce byte-identical chunks with the same SHA-256, so a browser that supports COS can serve the chunk from a shared store instead of fetching it again per origin. 7 8This builds on [Thomas Steiner](https://github.com/tomayac)'s original [`vite-plugin-cross-origin-storage`](https://github.com/tomayac/vite-plugin-cross-origin-storage), and is intended as an update of it. It explores a content-addressed chunking and decentralised (registry-free) sharing model on top of the loader and import-rewriting approach Thomas established. The aim is to merge these changes back upstream. 9 10## How it works 11 12At build time, for each package matched by `packages`: 13 141. The package is externalised from the app graph and re-bundled on its own with `rolldown`, **preserving every export** (no tree-shaking). This makes a chunk's bytes depend only on the package, never on which parts of it the app happened to import, so it is identical across sites. 152. Its dependencies are discovered and bundled too, recursively, so managing one package implicitly manages its whole import subgraph (e.g. `vue` pulls in `@vue/*`). Shared dependencies become their own chunks rather than being duplicated, which also preserves singletons like `@vue/reactivity`. 163. Chunks are hashed **bottom-up**: each chunk imports its dependencies by their content hash (`cos1:<sha256>`), so a chunk can only be hashed once its dependencies are. The result is purely a function of the source plus a pinned build recipe. 174. A runtime loader is injected. It looks each managed chunk up in COS by hash, falling back to the network and storing the fetched chunk for next time, then wires everything together through an import map. 18 19The `cos1:` prefix is a **recipe version**. Chunks are only byte-identical across builds that use the same recipe (the same `rolldown` version and options); the prefix is bumped when the recipe changes so chunks built under different recipes can never collide on the same hash. 20 21## Installation 22 23```bash 24npm install -D vite-plugin-cross-origin-storage 25``` 26 27## Usage 28 29```ts 30// vite.config.ts 31import { defineConfig } from 'vite' 32import { cosPlugin } from 'vite-plugin-cross-origin-storage' 33 34export default defineConfig({ 35 plugins: [ 36 cosPlugin({ 37 packages: [/^(?:vue$|@vue\/)/], 38 }), 39 ], 40}) 41``` 42 43For a plain client build, the plugin injects the loader into `index.html` and removes the default entry `<script>` automatically. 44 45## Options 46 47| Option | Type | Default | Description | 48| --- | --- | --- | --- | 49| `packages` | `Array<string \| RegExp>` | (required) | Packages to extract into COS chunks. Matched against the imported specifier; a plain string is an exact match. Transitive dependencies are collected automatically. | 50| `base` | `string` | Vite's `base` + `build.assetsDir` | Public path the chunks are served from. | 51| `loaderEntry` | `string` | bundled loader | Path to a custom runtime loader entry. | 52| `onGenerated` | `(scriptContent: string) => void` | (unset) | Receives the loader `<script>` body once chunks are emitted. SSR frameworks inject it into their own rendered HTML; when omitted the plugin injects into `index.html`. | 53 54## Browser support 55 56The [Cross-Origin Storage API](https://github.com/WICG/cross-origin-storage) is not yet implemented in any browser. You can try it today with the [Cross-Origin Storage browser extension](https://github.com/web-ai-community/cross-origin-storage-extension). Without it, the loader falls back to ordinary network requests, so the build still works everywhere; it just doesn't share chunks. 57 58## Limitations 59 60- **Managed packages must be self-contained.** A package whose source imports build-time virtuals (e.g. `#build/*`, `#imports`) cannot be bundled standalone and is rejected with a clear error. It also wouldn't be shareable, since its output would differ per app. 61- **Single-entry builds.** The loader wires up one entry chunk; multi-page builds with several HTML entries are not yet supported. 62- **The app entry is never COS-shared.** It is app-specific and is loaded from the network. 63- **Determinism is recipe-scoped.** Sharing only happens between builds on the same package version *and* the same recipe (`cos1:`). 64 65## Credits 66 67Original plugin and the COS loader / import-rewriting approach by [Thomas Steiner](https://github.com/tomayac) ([`tomayac/vite-plugin-cross-origin-storage`](https://github.com/tomayac/vite-plugin-cross-origin-storage)). 68 69## License 70 71MIT