[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.

docs: add readmes

+170 -69
+21
LICENSE
··· 1 + MIT License 2 + 3 + Copyright (c) Daniel Roe <daniel@roe.dev> 4 + 5 + Permission is hereby granted, free of charge, to any person obtaining a copy 6 + of this software and associated documentation files (the "Software"), to deal 7 + in the Software without restriction, including without limitation the rights 8 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 + copies of the Software, and to permit persons to whom the Software is 10 + furnished to do so, subject to the following conditions: 11 + 12 + The above copyright notice and this permission notice shall be included in all 13 + copies or substantial portions of the Software. 14 + 15 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 + SOFTWARE.
+21 -69
README.md
··· 1 - <!-- 2 - Get your module up and running quickly. 1 + # nuxt-cos 3 2 4 - Find and replace all on all files (CMD+SHIFT+F): 5 - - Name: My Module 6 - - Package name: nuxt-cos 7 - - Description: My new Nuxt module 8 - --> 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 the chunk format here is not stable. This is a research project, not a production tool. 9 5 10 - # My Module 6 + Load shared dependencies (such as `vue`) from [Cross-Origin Storage (COS)](https://github.com/WICG/cross-origin-storage). 11 7 12 - [![npm version][npm-version-src]][npm-version-href] 13 - [![npm downloads][npm-downloads-src]][npm-downloads-href] 14 - [![License][license-src]][license-href] 15 - [![Nuxt][nuxt-src]][nuxt-href] 8 + Most sites ship their own copy of common dependencies, and the browser re-downloads them per origin even though the bytes are identical. COS lets a browser keep one shared, content-addressed copy. This project extracts those dependencies into chunks whose filename and inter-chunk references are derived from a SHA-256 of their contents, so two independent sites building the same dependency at the same version produce the same chunk and can share it, with no central registry. 16 9 17 - My new Nuxt module for doing amazing things. 10 + ## Packages 18 11 19 - - [✨ &nbsp;Release Notes](/CHANGELOG.md) 20 - <!-- - [🏀 Online playground](https://stackblitz.com/github/danielroe/nuxt-cos?file=playground%2Fapp.vue) --> 21 - <!-- - [📖 &nbsp;Documentation](https://example.com) --> 12 + | Package | Description | 13 + | --- | --- | 14 + | [`vite-plugin-cross-origin-storage`](./packages/vite-plugin-cross-origin-storage) | The core Vite plugin: content-addressed chunking, bottom-up hashing, and the runtime loader. | 15 + | [`nuxt-cos`](./packages/nuxt-cos) | A thin Nuxt module wrapping the plugin. | 22 16 23 - ## Features 17 + ## Status 24 18 25 - <!-- Highlight some of the features your module provide here --> 26 - - ⛰ &nbsp;Foo 27 - - 🚠 &nbsp;Bar 28 - - 🌲 &nbsp;Baz 19 + This is exploratory. The Cross-Origin Storage API is a [WICG proposal](https://github.com/WICG/cross-origin-storage) with no native browser implementation; today it only works via the [browser extension](https://github.com/web-ai-community/cross-origin-storage-extension). Without COS the loader falls back to ordinary network requests, so builds keep working everywhere. 29 20 30 - ## Quick Setup 21 + The plugin 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, with the aim of merging back upstream. 31 22 32 - Install the module to your Nuxt application with one command: 23 + ## Development 33 24 34 25 ```bash 35 - npx nuxt module add nuxt-cos 26 + pnpm install 27 + pnpm build # build all packages 28 + pnpm test # run unit + e2e tests 29 + pnpm lint 36 30 ``` 37 31 38 - That's it! You can now use My Module in your Nuxt app ✨ 39 - 40 - 41 - ## Contribution 32 + The e2e tests will run a real browser with and without the [Cross-Origin Storage extension](https://chromewebstore.google.com/detail/cross-origin-storage/denpnpcgjgikjpoglpjefakmdcbmlgih). The COS-extension tests need a full Chrome for Testing build (`npx playwright-core install chromium`) and clone the extension at test time; set `COS_SKIP_EXTENSION_TEST=1` only in an environment that genuinely cannot run a headed browser. 42 33 43 - <details> 44 - <summary>Local development</summary> 45 - 46 - ```bash 47 - # Install dependencies 48 - npm install 49 - 50 - # Generate type stubs 51 - npm run dev:prepare 52 - 53 - # Develop with the playground 54 - npm run dev 55 - 56 - # Build the playground 57 - npm run dev:build 58 - 59 - # Run ESLint 60 - npm run lint 61 - 62 - # Run Vitest 63 - npm run test 64 - npm run test:watch 65 - 66 - # Release new version 67 - npm run release 68 - ``` 34 + ## License 69 35 70 - </details> 71 - 72 - 73 - <!-- Badges --> 74 - [npm-version-src]: https://img.shields.io/npm/v/nuxt-cos/latest.svg?style=flat&colorA=020420&colorB=00DC82 75 - [npm-version-href]: https://npmjs.com/package/nuxt-cos 76 - 77 - [npm-downloads-src]: https://img.shields.io/npm/dm/nuxt-cos.svg?style=flat&colorA=020420&colorB=00DC82 78 - [npm-downloads-href]: https://npm.chart.dev/nuxt-cos 79 - 80 - [license-src]: https://img.shields.io/npm/l/nuxt-cos.svg?style=flat&colorA=020420&colorB=00DC82 81 - [license-href]: https://npmjs.com/package/nuxt-cos 82 - 83 - [nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt 84 - [nuxt-href]: https://nuxt.com 36 + [MIT](./LICENSE)
+51
packages/nuxt-cos/README.md
··· 1 + # nuxt-cos 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 the underlying chunk format is not stable. Do not depend on it in production. 5 + 6 + A Nuxt module that loads shared dependencies (such as `vue`) from [Cross-Origin Storage (COS)](https://github.com/WICG/cross-origin-storage). It extracts those dependencies into content-addressed chunks so that a COS-capable browser can reuse the same chunk across different sites instead of downloading it once per origin. 7 + 8 + It is a thin Nuxt wrapper around [`vite-plugin-cross-origin-storage`](https://github.com/danielroe/nuxt-cos/tree/main/packages/vite-plugin-cross-origin-storage); see that package for how the content addressing and sharing work. 9 + 10 + ## Setup 11 + 12 + ```bash 13 + npx nuxt module add nuxt-cos 14 + ``` 15 + 16 + Or add it manually: 17 + 18 + ```ts 19 + // nuxt.config.ts 20 + export default defineNuxtConfig({ 21 + modules: ['nuxt-cos'], 22 + }) 23 + ``` 24 + 25 + By default it manages `vue` and `@vue/*`. The module only runs in production builds (it is a no-op in dev), and it injects the COS loader into the server-rendered HTML, replacing Nuxt's default entry script. 26 + 27 + ## Configuration 28 + 29 + ```ts 30 + export default defineNuxtConfig({ 31 + modules: ['nuxt-cos'], 32 + cos: { 33 + // Packages to extract into COS chunks. Matched against the imported 34 + // specifier; a plain string is an exact match. Transitive dependencies 35 + // are collected automatically. 36 + packages: [/^(?:vue$|@vue\/)/], 37 + }, 38 + }) 39 + ``` 40 + 41 + | Option | Type | Default | Description | 42 + | --- | --- | --- | --- | 43 + | `packages` | `Array<string \| RegExp>` | `[/^(?:vue$\|@vue\/)/]` | Packages to extract into COS chunks. | 44 + 45 + ## Browser support 46 + 47 + The [Cross-Origin Storage API](https://github.com/WICG/cross-origin-storage) is not yet in any browser. You can try it with the [Cross-Origin Storage browser extension](https://github.com/web-ai-community/cross-origin-storage-extension). Without it, chunks load over the network as usual, so your site keeps working; it just doesn't share them. 48 + 49 + ## License 50 + 51 + MIT
+71
packages/vite-plugin-cross-origin-storage/README.md
··· 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 + 6 + A 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 + 8 + This 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 + 12 + At build time, for each package matched by `packages`: 13 + 14 + 1. 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. 15 + 2. 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`. 16 + 3. 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. 17 + 4. 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 + 19 + The `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 24 + npm install -D vite-plugin-cross-origin-storage 25 + ``` 26 + 27 + ## Usage 28 + 29 + ```ts 30 + // vite.config.ts 31 + import { defineConfig } from 'vite' 32 + import { cosPlugin } from 'vite-plugin-cross-origin-storage' 33 + 34 + export default defineConfig({ 35 + plugins: [ 36 + cosPlugin({ 37 + packages: [/^(?:vue$|@vue\/)/], 38 + }), 39 + ], 40 + }) 41 + ``` 42 + 43 + For 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 + 56 + The [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 + 67 + Original 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 + 71 + MIT
+6
packages/vite-plugin-cross-origin-storage/package.json
··· 8 8 "email": "daniel@roe.dev", 9 9 "url": "https://github.com/danielroe" 10 10 }, 11 + "contributors": [ 12 + { 13 + "name": "Thomas Steiner", 14 + "url": "https://github.com/tomayac" 15 + } 16 + ], 11 17 "license": "MIT", 12 18 "repository": { 13 19 "type": "git",