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

1declare global { 2 interface Navigator { 3 crossOriginStorage?: { 4 requestFileHandles: ( 5 descriptors: Array<{ algorithm: string, value: string }>, 6 options?: { create?: boolean }, 7 ) => Promise<Array<{ 8 getFile: () => Promise<File> 9 createWritable: () => Promise<{ 10 write: (data: Blob) => Promise<void> 11 close: () => Promise<void> 12 }> 13 }>> 14 } 15 } 16} 17 18export interface CosManifest { 19 /** Public base path that managed chunks are served from, e.g. `/_nuxt/`. */ 20 base: string 21 /** 22 * The entry chunk to import once the import map is ready. It is app-specific, so it is 23 * loaded straight from the network rather than stored in COS by a content hash. 24 */ 25 entry: { specifier: string, file: string } 26 /** Map of content-addressed specifier to `{ file, hash }` for every COS-managed chunk. */ 27 chunks: Record<string, { file: string, hash: string }> 28} 29 30export async function runCosLoader(manifest: CosManifest): Promise<void> { 31 const cos = navigator.crossOriginStorage 32 const imports: Record<string, string> = {} 33 34 async function resolveChunk(hash: string, file: string): Promise<string> { 35 if (cos) { 36 try { 37 const [handle] = await cos.requestFileHandles([{ algorithm: 'SHA-256', value: hash }]) 38 if (handle) { 39 const blob = await handle.getFile() 40 return URL.createObjectURL(new Blob([blob], { type: 'text/javascript' })) 41 } 42 } 43 catch (error) { 44 if ((error as Error)?.name !== 'NotFoundError') { 45 console.error('[cos] lookup failed', error) 46 } 47 } 48 } 49 50 const response = await fetch(file) 51 const blob = new Blob([await response.blob()], { type: 'text/javascript' }) 52 53 if (cos) { 54 try { 55 const [handle] = await cos.requestFileHandles([{ algorithm: 'SHA-256', value: hash }], { create: true }) 56 if (handle) { 57 const writable = await handle.createWritable() 58 await writable.write(blob) 59 await writable.close() 60 } 61 } 62 catch (error) { 63 console.error('[cos] store failed', error) 64 } 65 } 66 67 return URL.createObjectURL(blob) 68 } 69 70 await Promise.all( 71 Object.entries(manifest.chunks).map(async ([specifier, { file, hash }]) => { 72 imports[specifier] = await resolveChunk(hash, manifest.base + file) 73 }), 74 ) 75 76 imports[manifest.entry.specifier] = new URL(manifest.base + manifest.entry.file, location.origin).href 77 78 const script = document.createElement('script') 79 script.type = 'importmap' 80 script.textContent = JSON.stringify({ imports }) 81 document.head.appendChild(script) 82 83 await new Promise(resolve => setTimeout(resolve, 0)) 84 await import(/* @vite-ignore */ manifest.entry.specifier) 85}