From fbd2dfd9f860dc8d7a2084a3eb24a52f65416492 Mon Sep 17 00:00:00 2001 From: Johnpaul Date: Tue, 10 Dec 2024 09:50:31 +0100 Subject: [PATCH 01/12] setup PWA icons and service worker --- packages/convert/app/entry.client.tsx | 23 +++++++ .../app/lib/register-service-worker.ts | 14 +++++ packages/convert/app/root.tsx | 4 +- packages/convert/public/manifest.json | 27 ++++++++ packages/convert/public/pwa-icon-192.png | Bin 0 -> 1996 bytes packages/convert/public/pwa-icon-512.png | Bin 0 -> 4711 bytes packages/convert/public/service-worker.js | 59 ++++++++++++++++++ packages/convert/vite.config.ts | 13 +++- 8 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 packages/convert/app/entry.client.tsx create mode 100644 packages/convert/app/lib/register-service-worker.ts create mode 100644 packages/convert/public/manifest.json create mode 100644 packages/convert/public/pwa-icon-192.png create mode 100644 packages/convert/public/pwa-icon-512.png create mode 100644 packages/convert/public/service-worker.js diff --git a/packages/convert/app/entry.client.tsx b/packages/convert/app/entry.client.tsx new file mode 100644 index 00000000000..812fa42efe6 --- /dev/null +++ b/packages/convert/app/entry.client.tsx @@ -0,0 +1,23 @@ +import {RemixBrowser} from '@remix-run/react'; +import {startTransition} from 'react'; +import {hydrateRoot} from 'react-dom/client'; + +const registerServiceWorker = () => { + if ('serviceWorker' in navigator) { + window.addEventListener('load', () => { + navigator.serviceWorker + .register('/service-worker.js') + .then((registration) => { + console.log('SW registered:', registration); + }) + .catch((error) => { + console.log('SW registration failed:', error); + }); + }); + } +}; + +startTransition(() => { + hydrateRoot(document, ); + registerServiceWorker(); +}); diff --git a/packages/convert/app/lib/register-service-worker.ts b/packages/convert/app/lib/register-service-worker.ts new file mode 100644 index 00000000000..8d85613e457 --- /dev/null +++ b/packages/convert/app/lib/register-service-worker.ts @@ -0,0 +1,14 @@ +export const registerServiceWorker = () => { + if ('serviceWorker' in navigator) { + window.addEventListener('load', () => { + navigator.serviceWorker + .register('/service-worker.js') + .then((registration) => { + console.log('SW registered:', registration); + }) + .catch((error) => { + console.log('SW registration failed:', error); + }); + }); + } +}; diff --git a/packages/convert/app/root.tsx b/packages/convert/app/root.tsx index 7aca28603ee..2fee55c37ba 100644 --- a/packages/convert/app/root.tsx +++ b/packages/convert/app/root.tsx @@ -1,6 +1,7 @@ -import {Links, Outlet, Scripts, ScrollRestoration} from '@remix-run/react'; import './tailwind.css'; +import {Links, Outlet, Scripts, ScrollRestoration} from '@remix-run/react'; + export function Layout({children}: {readonly children: React.ReactNode}) { return ( @@ -10,6 +11,7 @@ export function Layout({children}: {readonly children: React.ReactNode}) { Remotion Convert + diff --git a/packages/convert/public/manifest.json b/packages/convert/public/manifest.json new file mode 100644 index 00000000000..7a6515c203e --- /dev/null +++ b/packages/convert/public/manifest.json @@ -0,0 +1,27 @@ +{ + "name": "Remotion Convert", + "short_name": "Remotion Convert", + "description": "Convert videos using WebCodecs", + "start_url": "/", + "display": "standalone", + "background_color": "#ffffff", + "theme_color": "#0B84F3", + "icons": [ + { + "src": "/pwa-icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/pwa-icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "/pwa-icon-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} \ No newline at end of file diff --git a/packages/convert/public/pwa-icon-192.png b/packages/convert/public/pwa-icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..f925e335b04a478ba012f82115c30cd05e9b8fb7 GIT binary patch literal 1996 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 z zbvMG}WDanMIJ(}4W+NU7YZp;$bcyJiD(akPj@Ias^zBha_%_4?k3+F#q;{3);Mq71 z!|vnYENR~)?v0UT9wngd)}km0Hf0=_>oN!li3!U4(E7SjYeRGiiETJ%ii1QWtK0|% z9S_=#GDlbQ^+)l#b6F+u9C(|SJuppsYv%*u;EMxdcmYI`Kpmfl)aFFG`$(~pbw3+i z$_o}98|8D!DKr?Bn^B6-jC1539zrm_1(w0kV+=r!2UHvKxd6AHxaV@4jH z*BKttrM?tsXHMas_iD@-3Pp+uIV`PQJ$0?+NU}A>hq3IryMC%LhX*q(DfC5>)O+^8 zs4LRC;B*kW!r;rrBlkgR3T$TohlVki&qWAfA=(NtJCQ0}`2?MokNhOu27Ygwf5~W? zmI>8Xlrb!moEctNA%)u<87ec@)m7L&9oOIMj*Vc0AzUU8_MDTsMuKT!HPnCgSUT(< z`?YQ~*&E(Fe@Y(X`?c$!6x*;`;P~6Dw>=)#0p&fLWbSdGA=QRjv#TCvXCemtcl6vC zIZdjKv`&Ie1E+qw7jRj(+#XtLgm1)ER>d4SqF&vD8dRAw!|UrRD`pz3(N#r2$fZ%A z9ZOlmoW2OZ{(T*8ygZa)8&65w@GZgKSp0jcE_wfvf8!7H?;3{R<27&Y(|yTV-+qZR zDC#HV>);u54ZlzcwNnW7$74ny(H`~Bss|aW|F2UggnyxLXafiMikG%FJ(CRkjOd3| z?DwCWn~KTmw#d}NH z;;eX~)=ZXawC`Yc(Y_bT*A1+_<=OsTI-hs}t?oR>7>TzSdrpt5ulQy3Y|E0SaJd;MWarvXFA-1-9g7^ChT+74JTL z)N5eu6C(8Wo8|~o`rp2aA;OnvN}Z^R-rmnH118ltC4K794LBF~ta*?xBRvn3@S@Ltk_-*N?%_Oc&a$TluZ$ZjgniPywTpF82mkuCTyLVMjM+2H z#pf^T$?tjsj}~t~0n3MsAZ{Oy-(C*pYIFSG#G094WQI(eaLV>=AiU33mcPzo;Uy<) zWK7$_(R6rp>&twu!b#^(RawSReCGbGK`#8!gxLy~Vg)B4iBLW}lLe4@Q)f)~{5BE< zCx7|C1#*!(bF>*wmi8MFl*el$qI&Mlr6yF!P%gaIiMw2~r0~T>r}q{z6aj)OLKiok zCGI^myb5;2QL)35A$_Q)82ZlP1q(+vKy~K8EEJQ^c(mBSD{)eh9nwlPYhE=#+XFq3 zJ}=nVP)u})vik?u;|b{0v}yW>`NG}BAUD<6KJi_TO|!js7PHlYm|k#aQ%~{?%_;zo z1l(=vC`Fzt=tbkF@u6+ANrutdgC4^Xwc#x(nO4jj_r7rN?GDTa>o39`5h$ZS`(yLz eGj^k!x1&t+v{u;dRi*zDg3yq;!6#?XIsXG~(LAyM literal 0 HcmV?d00001 diff --git a/packages/convert/public/service-worker.js b/packages/convert/public/service-worker.js new file mode 100644 index 00000000000..d33bb0b7577 --- /dev/null +++ b/packages/convert/public/service-worker.js @@ -0,0 +1,59 @@ +const CACHE_NAME = 'remotion-convert-v1'; + +self.addEventListener('install', (event) => { + event.waitUntil( + caches.open(CACHE_NAME).then((cache) => { + return cache.addAll([ + '/', + '/manifest.json', + // Add other critical assets here + ]); + }) + ); +}); + +self.addEventListener('activate', (event) => { + event.waitUntil( + caches.keys().then((cacheNames) => { + return Promise.all( + cacheNames + .filter((name) => name !== CACHE_NAME) + .map((name) => caches.delete(name)) + ); + }) + ); +}); + +self.addEventListener('fetch', (event) => { + event.respondWith( + // Try network first + fetch(event.request) + .then((response) => { + // Clone the response because we might need to read it twice + const responseClone = response.clone(); + + // Update cache with new response + caches.open(CACHE_NAME).then((cache) => { + cache.put(event.request, responseClone); + }); + + return response; + }) + .catch(() => { + // If network fails, try cache + return caches.match(event.request).then((response) => { + if (response) { + return response; + } + // If both network and cache fail, show offline page + if (event.request.mode === 'navigate') { + return caches.match('/'); + } + return new Response('Network error happened', { + status: 408, + headers: { 'Content-Type': 'text/plain' }, + }); + }); + }) + ); +}); \ No newline at end of file diff --git a/packages/convert/vite.config.ts b/packages/convert/vite.config.ts index 85c57392f6f..e6705434e25 100644 --- a/packages/convert/vite.config.ts +++ b/packages/convert/vite.config.ts @@ -1,9 +1,9 @@ -import {vitePlugin as remix} from '@remix-run/dev'; +import {defineConfig} from 'vite'; import {installGlobals} from '@remix-run/node'; -import {vercelPreset} from '@vercel/remix/vite'; import path from 'path'; -import {defineConfig} from 'vite'; +import {vitePlugin as remix} from '@remix-run/dev'; import tsconfigPaths from 'vite-tsconfig-paths'; +import {vercelPreset} from '@vercel/remix/vite'; installGlobals(); @@ -14,4 +14,11 @@ export default defineConfig({ '@': path.resolve(__dirname, './app'), }, }, + build: { + rollupOptions: { + input: { + 'service-worker': './service-worker.js' + } + } + } }); From 650101dbe20b3adf746e830c78956f4a18888d11 Mon Sep 17 00:00:00 2001 From: Johnpaul Date: Tue, 10 Dec 2024 11:58:50 +0100 Subject: [PATCH 02/12] fix PWA path --- packages/convert/app/entry.client.tsx | 4 ++-- packages/convert/app/root.tsx | 2 +- packages/convert/public/manifest.json | 10 +++++----- packages/convert/public/service-worker.js | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/convert/app/entry.client.tsx b/packages/convert/app/entry.client.tsx index 812fa42efe6..e6774ee5f9a 100644 --- a/packages/convert/app/entry.client.tsx +++ b/packages/convert/app/entry.client.tsx @@ -1,12 +1,12 @@ import {RemixBrowser} from '@remix-run/react'; -import {startTransition} from 'react'; import {hydrateRoot} from 'react-dom/client'; +import {startTransition} from 'react'; const registerServiceWorker = () => { if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker - .register('/service-worker.js') + .register('/convert/service-worker.js') .then((registration) => { console.log('SW registered:', registration); }) diff --git a/packages/convert/app/root.tsx b/packages/convert/app/root.tsx index 2fee55c37ba..667159376ff 100644 --- a/packages/convert/app/root.tsx +++ b/packages/convert/app/root.tsx @@ -11,7 +11,7 @@ export function Layout({children}: {readonly children: React.ReactNode}) { Remotion Convert - + diff --git a/packages/convert/public/manifest.json b/packages/convert/public/manifest.json index 7a6515c203e..5371fc7aca2 100644 --- a/packages/convert/public/manifest.json +++ b/packages/convert/public/manifest.json @@ -2,26 +2,26 @@ "name": "Remotion Convert", "short_name": "Remotion Convert", "description": "Convert videos using WebCodecs", - "start_url": "/", + "start_url": "/convert", "display": "standalone", "background_color": "#ffffff", "theme_color": "#0B84F3", "icons": [ { - "src": "/pwa-icon-192.png", + "src": "/convert/pwa-icon-192.png", "sizes": "192x192", "type": "image/png" }, { - "src": "/pwa-icon-512.png", + "src": "/convert/pwa-icon-512.png", "sizes": "512x512", "type": "image/png" }, { - "src": "/pwa-icon-512.png", + "src": "/convert/pwa-icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" } ] -} \ No newline at end of file +} diff --git a/packages/convert/public/service-worker.js b/packages/convert/public/service-worker.js index d33bb0b7577..d016a4867b2 100644 --- a/packages/convert/public/service-worker.js +++ b/packages/convert/public/service-worker.js @@ -4,8 +4,8 @@ self.addEventListener('install', (event) => { event.waitUntil( caches.open(CACHE_NAME).then((cache) => { return cache.addAll([ - '/', - '/manifest.json', + '/convert', + '/convert/manifest.json', // Add other critical assets here ]); }) @@ -47,7 +47,7 @@ self.addEventListener('fetch', (event) => { } // If both network and cache fail, show offline page if (event.request.mode === 'navigate') { - return caches.match('/'); + return caches.match('/convert'); } return new Response('Network error happened', { status: 408, From e7551c38334925ad4ba3c5b39711af2d55a99765 Mon Sep 17 00:00:00 2001 From: Johnpaul Date: Tue, 10 Dec 2024 13:59:36 +0100 Subject: [PATCH 03/12] enhance autoSelectWriter to handle offline mode and improve WebFS support --- packages/webcodecs/src/auto-select-writer.ts | 61 +++++++++++++------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/packages/webcodecs/src/auto-select-writer.ts b/packages/webcodecs/src/auto-select-writer.ts index 3f626044175..26516aa3b4a 100644 --- a/packages/webcodecs/src/auto-select-writer.ts +++ b/packages/webcodecs/src/auto-select-writer.ts @@ -1,28 +1,49 @@ -import {bufferWriter} from '@remotion/media-parser/buffer'; import {canUseWebFsWriter, webFsWriter} from '@remotion/media-parser/web-fs'; -import type {WriterInterface} from '@remotion/media-parser'; -import type {LogLevel} from './log'; import {Log} from './log'; +import type {LogLevel} from './log'; +import type {WriterInterface} from '@remotion/media-parser'; +import {bufferWriter} from '@remotion/media-parser/buffer'; export const autoSelectWriter = async ( - writer: WriterInterface | undefined, - logLevel: LogLevel, + writer: WriterInterface | undefined, + logLevel: LogLevel, ): Promise => { - if (writer) { - Log.verbose(logLevel, 'Using writer provided by user'); - return writer; - } + if (writer) { + Log.verbose(logLevel, 'Using writer provided by user'); + return writer; + } + + Log.verbose(logLevel, 'Determining best writer'); + + // Check if we're offline using the navigator API + const isOffline = !navigator.onLine; + + if (isOffline) { + Log.verbose(logLevel, 'Offline mode detected, using buffer writer'); + return bufferWriter; + } + + try { + const webFsSupported = await Promise.race([ + canUseWebFsWriter(), + // Add a timeout to avoid hanging in PWA + new Promise((_, reject) => + setTimeout(() => reject(new Error('WebFS check timeout')), 3000) + ) + ]); - Log.verbose(logLevel, 'Determining best writer'); - if (await canUseWebFsWriter()) { - Log.verbose(logLevel, 'Using WebFS writer because it is supported'); - return webFsWriter; - } + if (webFsSupported) { + Log.verbose(logLevel, 'Using WebFS writer because it is supported'); + return webFsWriter; + } + } catch (err) { + Log.verbose(logLevel, `WebFS check failed: ${err}. Falling back to buffer writer`); + } - Log.verbose( - logLevel, - 'Using buffer writer because WebFS writer is not supported', - ); - return bufferWriter; -}; + Log.verbose( + logLevel, + 'Using buffer writer because WebFS writer is not supported or unavailable', + ); + return bufferWriter; +}; \ No newline at end of file From 0a10bd672a1fef0147c40e5b4c0eefed8d29a055 Mon Sep 17 00:00:00 2001 From: Johnpaul Date: Tue, 10 Dec 2024 15:37:50 +0100 Subject: [PATCH 04/12] set correct placement for service worker --- packages/convert/app/entry.client.tsx | 7 +- .../app/lib/register-service-worker.ts | 14 --- packages/convert/public/manifest.json | 1 + packages/convert/public/service-worker.js | 59 ---------- .../docs/static/convert-service-worker.js | 104 ++++++++++++++++++ 5 files changed, 107 insertions(+), 78 deletions(-) delete mode 100644 packages/convert/app/lib/register-service-worker.ts delete mode 100644 packages/convert/public/service-worker.js create mode 100644 packages/docs/static/convert-service-worker.js diff --git a/packages/convert/app/entry.client.tsx b/packages/convert/app/entry.client.tsx index e6774ee5f9a..5fe7e483123 100644 --- a/packages/convert/app/entry.client.tsx +++ b/packages/convert/app/entry.client.tsx @@ -1,15 +1,12 @@ import {RemixBrowser} from '@remix-run/react'; -import {hydrateRoot} from 'react-dom/client'; import {startTransition} from 'react'; +import {hydrateRoot} from 'react-dom/client'; const registerServiceWorker = () => { if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker - .register('/convert/service-worker.js') - .then((registration) => { - console.log('SW registered:', registration); - }) + .register('/convert-service-worker.js') .catch((error) => { console.log('SW registration failed:', error); }); diff --git a/packages/convert/app/lib/register-service-worker.ts b/packages/convert/app/lib/register-service-worker.ts deleted file mode 100644 index 8d85613e457..00000000000 --- a/packages/convert/app/lib/register-service-worker.ts +++ /dev/null @@ -1,14 +0,0 @@ -export const registerServiceWorker = () => { - if ('serviceWorker' in navigator) { - window.addEventListener('load', () => { - navigator.serviceWorker - .register('/service-worker.js') - .then((registration) => { - console.log('SW registered:', registration); - }) - .catch((error) => { - console.log('SW registration failed:', error); - }); - }); - } -}; diff --git a/packages/convert/public/manifest.json b/packages/convert/public/manifest.json index 5371fc7aca2..52f646703a5 100644 --- a/packages/convert/public/manifest.json +++ b/packages/convert/public/manifest.json @@ -1,5 +1,6 @@ { "name": "Remotion Convert", + "id": "com.remotion.convert", "short_name": "Remotion Convert", "description": "Convert videos using WebCodecs", "start_url": "/convert", diff --git a/packages/convert/public/service-worker.js b/packages/convert/public/service-worker.js deleted file mode 100644 index d016a4867b2..00000000000 --- a/packages/convert/public/service-worker.js +++ /dev/null @@ -1,59 +0,0 @@ -const CACHE_NAME = 'remotion-convert-v1'; - -self.addEventListener('install', (event) => { - event.waitUntil( - caches.open(CACHE_NAME).then((cache) => { - return cache.addAll([ - '/convert', - '/convert/manifest.json', - // Add other critical assets here - ]); - }) - ); -}); - -self.addEventListener('activate', (event) => { - event.waitUntil( - caches.keys().then((cacheNames) => { - return Promise.all( - cacheNames - .filter((name) => name !== CACHE_NAME) - .map((name) => caches.delete(name)) - ); - }) - ); -}); - -self.addEventListener('fetch', (event) => { - event.respondWith( - // Try network first - fetch(event.request) - .then((response) => { - // Clone the response because we might need to read it twice - const responseClone = response.clone(); - - // Update cache with new response - caches.open(CACHE_NAME).then((cache) => { - cache.put(event.request, responseClone); - }); - - return response; - }) - .catch(() => { - // If network fails, try cache - return caches.match(event.request).then((response) => { - if (response) { - return response; - } - // If both network and cache fail, show offline page - if (event.request.mode === 'navigate') { - return caches.match('/convert'); - } - return new Response('Network error happened', { - status: 408, - headers: { 'Content-Type': 'text/plain' }, - }); - }); - }) - ); -}); \ No newline at end of file diff --git a/packages/docs/static/convert-service-worker.js b/packages/docs/static/convert-service-worker.js new file mode 100644 index 00000000000..73b99fdf536 --- /dev/null +++ b/packages/docs/static/convert-service-worker.js @@ -0,0 +1,104 @@ +const CACHE_NAME = 'remotion-convert-v1'; + +// Helper function to determine if a request is under /convert +function isConvertPath(url) { + return url.pathname.startsWith('/convert'); +} + +const $FILES = [ + '/convert', + '/convert/manifest.json', + '/convert/pwa-icon-192.png', + '/convert/pwa-icon-512.png', +]; + +self.addEventListener('install', (event) => { + event.waitUntil( + (async () => { + const cache = await caches.open(CACHE_NAME); + await cache.addAll($FILES); + await self.skipWaiting(); + })(), + ); +}); + +self.addEventListener('activate', (event) => { + event.waitUntil( + (async () => { + // Clean up old caches + const cacheNames = await caches.keys(); + await Promise.all( + cacheNames + .filter((name) => name !== CACHE_NAME) + .map((name) => caches.delete(name)), + ); + // Take control of all pages immediately + await self.clients.claim(); + })(), + ); +}); + +self.addEventListener('fetch', (event) => { + const url = new URL(event.request.url); + + if (!isConvertPath(url)) { + return; + } + + + // Only handle same-origin requests + if (!url.origin.includes(self.location.origin)) { + return; + } + + // If it is a file selected from the user's device, do not cache it + if (url.protocol === 'file:') { + return; + } + + // Special handling for /convert paths + if (isConvertPath(url)) { + event.respondWith( + (async () => { + try { + // Try to fetch the network request + const response = await fetch(event.request); + + // Cache the new response + const cache = await caches.open(CACHE_NAME); + await cache.put(event.request, response.clone()); + + return response; + } catch (error) { + // If network fails, try cache + const cachedResponse = await caches.match(event.request); + if (cachedResponse) { + return cachedResponse; + } + + // If both network and cache fail, return a basic offline response + if (event.request.headers.get('accept')?.includes('text/html')) { + return caches.match('/convert'); + } + + return new Response('Network error happened', { + status: 408, + headers: {'Content-Type': 'text/plain'}, + }); + } + })(), + ); + return; + } + + // For all other requests, do a simple network-first strategy + event.respondWith( + (async () => { + try { + return await fetch(event.request); + } catch (error) { + return caches.match(event.request); + } + })(), + ); +}); From 28bed6dd5d63ce2db6d0aa905940b46000e834a5 Mon Sep 17 00:00:00 2001 From: Johnpaul Date: Tue, 10 Dec 2024 15:38:02 +0100 Subject: [PATCH 05/12] fix manifest icon size --- .../src/gcpInstaller/gcpInstaller.tar | Bin 30720 -> 35840 bytes packages/convert/public/pwa-icon-512.png | Bin 4711 -> 5382 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/packages/cloudrun/src/gcpInstaller/gcpInstaller.tar b/packages/cloudrun/src/gcpInstaller/gcpInstaller.tar index 8d24fa64f8f42a10dd576780bac61f472a4aa662..c456c72cf654fae74282f04da9fe063f37a5b150 100644 GIT binary patch delta 1907 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 literal 4711 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 z zbvMG}WDanMIJ(}4W+NU7YZp;$bcyJiD(akPj@Ias^zBha_%_4?k3+F#q;{3);Mq71 z!|vnYENR~)?v0UT9wngd)}km0Hf0=_>oN!li3!U4(E7SjYeRGiiETJ%ii1QWtK0|% z9S_=#GDlbQ^+)l#b6F+u9C(|SJuppsYv%*u;EMxdcmYI`Kpmfl)aFFG`$(~pbw3+i z$_o}98|8D!DKr?Bn^B6-jC1539zrm_1(w0kV+=r!2UHvKxd6AHxaV@4jH z*BKttrM?tsXHMas_iD@-3Pp+uIV`PQJ$0?+NU}A>hq3IryMC%LhX*q(DfC5>)O+^8 zs4LRC;B*kW!r;rrBlkgR3T$TohlVki&qWAfA=(NtJCQ0}`2?MokNhOu27Ygwf5~W? zmI>8Xlrb!moEctNA%)u<87ec@)m7L&9oOIMj*Vc0AzUU8_MDTsMuKT!HPnCgSUT(< z`?YQ~*&E(Fe@Y(X`?c$!6x*;`;P~6Dw>=)#0p&fLWbSdGA=QRjv#TCvXCemtcl6vC zIZdjKv`&Ie1E+qw7jRj(+#XtLgm1)ER>d4SqF&vD8dRAw!|UrRD`pz3(N#r2$fZ%A z9ZOlmoW2OZ{(T*8ygZa)8&65w@GZgKSp0jcE_wfvf8!7H?;3{R<27&Y(|yTV-+qZR zDC#HV>);u54ZlzcwNnW7$74ny(H`~Bss|aW|F2UggnyxLXafiMikG%FJ(CRkjOd3| z?DwCWn~KTmw#d}NH z;;eX~)=ZXawC`Yc(Y_bT*A1+_<=OsTI-hs}t?oR>7>TzSdrpt5ulQy3Y|E0SaJd;MWarvXFA-1-9g7^ChT+74JTL z)N5eu6C(8Wo8|~o`rp2aA;OnvN}Z^R-rmnH118ltC4K794LBF~ta*?xBRvn3@S@Ltk_-*N?%_Oc&a$TluZ$ZjgniPywTpF82mkuCTyLVMjM+2H z#pf^T$?tjsj}~t~0n3MsAZ{Oy-(C*pYIFSG#G094WQI(eaLV>=AiU33mcPzo;Uy<) zWK7$_(R6rp>&twu!b#^(RawSReCGbGK`#8!gxLy~Vg)B4iBLW}lLe4@Q)f)~{5BE< zCx7|C1#*!(bF>*wmi8MFl*el$qI&Mlr6yF!P%gaIiMw2~r0~T>r}q{z6aj)OLKiok zCGI^myb5;2QL)35A$_Q)82ZlP1q(+vKy~K8EEJQ^c(mBSD{)eh9nwlPYhE=#+XFq3 zJ}=nVP)u})vik?u;|b{0v}yW>`NG}BAUD<6KJi_TO|!js7PHlYm|k#aQ%~{?%_;zo z1l(=vC`Fzt=tbkF@u6+ANrutdgC4^Xwc#x(nO4jj_r7rN?GDTa>o39`5h$ZS`(yLz eGj^k!x1&t+v{u;dRi*zDg3yq;!6#?XIsXG~(LAyM From 2969aafdd93e94f02b4489e5887a97916385b23b Mon Sep 17 00:00:00 2001 From: Johnpaul Date: Tue, 10 Dec 2024 15:47:02 +0100 Subject: [PATCH 06/12] use 2 secs timeout for WebFs check --- packages/webcodecs/src/auto-select-writer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webcodecs/src/auto-select-writer.ts b/packages/webcodecs/src/auto-select-writer.ts index 26516aa3b4a..d594da637bc 100644 --- a/packages/webcodecs/src/auto-select-writer.ts +++ b/packages/webcodecs/src/auto-select-writer.ts @@ -29,7 +29,7 @@ export const autoSelectWriter = async ( canUseWebFsWriter(), // Add a timeout to avoid hanging in PWA new Promise((_, reject) => - setTimeout(() => reject(new Error('WebFS check timeout')), 3000) + setTimeout(() => reject(new Error('WebFS check timeout')), 2000) ) ]); From 03e17064d836b3443f7f988918aca8134d1be367 Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Thu, 12 Dec 2024 10:44:35 +0100 Subject: [PATCH 07/12] get service worker working --- packages/convert/app/entry.client.tsx | 3 ++- packages/convert/app/root.tsx | 2 +- .../public/service-worker.js} | 7 +++---- packages/convert/vite.config.ts | 13 +++---------- 4 files changed, 9 insertions(+), 16 deletions(-) rename packages/{docs/static/convert-service-worker.js => convert/public/service-worker.js} (98%) diff --git a/packages/convert/app/entry.client.tsx b/packages/convert/app/entry.client.tsx index 5fe7e483123..3fd6aa01c9b 100644 --- a/packages/convert/app/entry.client.tsx +++ b/packages/convert/app/entry.client.tsx @@ -1,4 +1,5 @@ import {RemixBrowser} from '@remix-run/react'; +import React from 'react'; import {startTransition} from 'react'; import {hydrateRoot} from 'react-dom/client'; @@ -6,7 +7,7 @@ const registerServiceWorker = () => { if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker - .register('/convert-service-worker.js') + .register('/convert/service-worker.js') .catch((error) => { console.log('SW registration failed:', error); }); diff --git a/packages/convert/app/root.tsx b/packages/convert/app/root.tsx index 667159376ff..8d6096920a6 100644 --- a/packages/convert/app/root.tsx +++ b/packages/convert/app/root.tsx @@ -10,7 +10,7 @@ export function Layout({children}: {readonly children: React.ReactNode}) { Remotion Convert - + diff --git a/packages/docs/static/convert-service-worker.js b/packages/convert/public/service-worker.js similarity index 98% rename from packages/docs/static/convert-service-worker.js rename to packages/convert/public/service-worker.js index 73b99fdf536..c9ab2f54fd8 100644 --- a/packages/docs/static/convert-service-worker.js +++ b/packages/convert/public/service-worker.js @@ -40,11 +40,10 @@ self.addEventListener('activate', (event) => { self.addEventListener('fetch', (event) => { const url = new URL(event.request.url); - + if (!isConvertPath(url)) { return; } - // Only handle same-origin requests if (!url.origin.includes(self.location.origin)) { @@ -69,7 +68,7 @@ self.addEventListener('fetch', (event) => { await cache.put(event.request, response.clone()); return response; - } catch (error) { + } catch { // If network fails, try cache const cachedResponse = await caches.match(event.request); if (cachedResponse) { @@ -96,7 +95,7 @@ self.addEventListener('fetch', (event) => { (async () => { try { return await fetch(event.request); - } catch (error) { + } catch { return caches.match(event.request); } })(), diff --git a/packages/convert/vite.config.ts b/packages/convert/vite.config.ts index e6705434e25..85c57392f6f 100644 --- a/packages/convert/vite.config.ts +++ b/packages/convert/vite.config.ts @@ -1,9 +1,9 @@ -import {defineConfig} from 'vite'; +import {vitePlugin as remix} from '@remix-run/dev'; import {installGlobals} from '@remix-run/node'; +import {vercelPreset} from '@vercel/remix/vite'; import path from 'path'; -import {vitePlugin as remix} from '@remix-run/dev'; +import {defineConfig} from 'vite'; import tsconfigPaths from 'vite-tsconfig-paths'; -import {vercelPreset} from '@vercel/remix/vite'; installGlobals(); @@ -14,11 +14,4 @@ export default defineConfig({ '@': path.resolve(__dirname, './app'), }, }, - build: { - rollupOptions: { - input: { - 'service-worker': './service-worker.js' - } - } - } }); From e32cdd30b8c3bdba01afe01291dda37cf686c2cc Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Thu, 12 Dec 2024 11:12:28 +0100 Subject: [PATCH 08/12] nice! ship it --- .../service-worker.ts} | 13 +++--- packages/convert/build-service-worker.ts | 43 +++++++++++++++++++ packages/convert/package.json | 2 +- packages/convert/tsconfig.json | 2 +- 4 files changed, 51 insertions(+), 9 deletions(-) rename packages/convert/{public/service-worker.js => app/service-worker.ts} (93%) create mode 100644 packages/convert/build-service-worker.ts diff --git a/packages/convert/public/service-worker.js b/packages/convert/app/service-worker.ts similarity index 93% rename from packages/convert/public/service-worker.js rename to packages/convert/app/service-worker.ts index c9ab2f54fd8..4fd1bb000f2 100644 --- a/packages/convert/public/service-worker.js +++ b/packages/convert/app/service-worker.ts @@ -1,3 +1,7 @@ +const $FILES = []; +// ^ leave this - will get filled in during build +// --auto-generated-until-here + const CACHE_NAME = 'remotion-convert-v1'; // Helper function to determine if a request is under /convert @@ -5,18 +9,12 @@ function isConvertPath(url) { return url.pathname.startsWith('/convert'); } -const $FILES = [ - '/convert', - '/convert/manifest.json', - '/convert/pwa-icon-192.png', - '/convert/pwa-icon-512.png', -]; - self.addEventListener('install', (event) => { event.waitUntil( (async () => { const cache = await caches.open(CACHE_NAME); await cache.addAll($FILES); + // @ts-expect-error no types await self.skipWaiting(); })(), ); @@ -33,6 +31,7 @@ self.addEventListener('activate', (event) => { .map((name) => caches.delete(name)), ); // Take control of all pages immediately + // @ts-expect-error no types await self.clients.claim(); })(), ); diff --git a/packages/convert/build-service-worker.ts b/packages/convert/build-service-worker.ts new file mode 100644 index 00000000000..e3915effe23 --- /dev/null +++ b/packages/convert/build-service-worker.ts @@ -0,0 +1,43 @@ +import fs from 'fs'; +const files = fs.readdirSync('spa-dist/client'); +const assets = fs.readdirSync('spa-dist/client/assets'); +const toCache = [ + ...files + .filter((f) => { + return fs.statSync(`spa-dist/client/${f}`).isFile(); + }) + .map((f) => `/convert/${f}`.replace('/index.html', '')), + ...assets + .filter((f) => { + if (!fs.statSync(`spa-dist/client/assets/${f}`).isFile()) { + throw new Error('Unexpected output'); + } + return true; + }) + .map((f) => `/convert/assets/${f}`), +]; + +const result = await Bun.build({ + entrypoints: ['./app/service-worker.ts'], +}); + +if (!result.success) { + console.log(result.logs); + throw new Error('Failed to build service worker'); +} + +const firstOutput = result.outputs[0]; + +if (!firstOutput) { + throw new Error('No output'); +} +const text = await firstOutput.text(); +const replaced = '$FILES = [];'; +if (!text.includes(replaced)) { + throw new Error('Unexpected output'); +} + +await Bun.write( + 'spa-dist/client/service-worker.js', + text.replace(replaced, `$FILES = ${JSON.stringify(toCache)};`), +); diff --git a/packages/convert/package.json b/packages/convert/package.json index c077ea74bbe..1b7a23d0894 100644 --- a/packages/convert/package.json +++ b/packages/convert/package.json @@ -6,7 +6,7 @@ "type": "module", "scripts": { "build-page": "remix vite:build", - "build-spa": "remix vite:build -c vite-spa.config.ts", + "build-spa": "remix vite:build -c vite-spa.config.ts && bun build-service-worker.ts", "dev": "remix vite:dev", "typecheck": "tsc", "test": "bun test test", diff --git a/packages/convert/tsconfig.json b/packages/convert/tsconfig.json index 6597292eba4..11105109d1d 100644 --- a/packages/convert/tsconfig.json +++ b/packages/convert/tsconfig.json @@ -10,7 +10,7 @@ "test" ], "compilerOptions": { - "lib": ["DOM", "DOM.Iterable", "ES2022"], + "lib": ["WebWorker", "DOM", "DOM.Iterable", "ES2022"], "types": ["@remix-run/node", "vite/client", "@types/bun"], "isolatedModules": true, "esModuleInterop": true, From 679fbc6a9b491ba4750a35d675c6ac3727edbfd5 Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Thu, 12 Dec 2024 11:12:49 +0100 Subject: [PATCH 09/12] Update auto-select-writer.ts --- packages/webcodecs/src/auto-select-writer.ts | 87 ++++++++++---------- 1 file changed, 45 insertions(+), 42 deletions(-) diff --git a/packages/webcodecs/src/auto-select-writer.ts b/packages/webcodecs/src/auto-select-writer.ts index d594da637bc..5542d090999 100644 --- a/packages/webcodecs/src/auto-select-writer.ts +++ b/packages/webcodecs/src/auto-select-writer.ts @@ -1,49 +1,52 @@ import {canUseWebFsWriter, webFsWriter} from '@remotion/media-parser/web-fs'; -import {Log} from './log'; -import type {LogLevel} from './log'; import type {WriterInterface} from '@remotion/media-parser'; import {bufferWriter} from '@remotion/media-parser/buffer'; +import type {LogLevel} from './log'; +import {Log} from './log'; export const autoSelectWriter = async ( - writer: WriterInterface | undefined, - logLevel: LogLevel, + writer: WriterInterface | undefined, + logLevel: LogLevel, ): Promise => { - if (writer) { - Log.verbose(logLevel, 'Using writer provided by user'); - return writer; - } - - Log.verbose(logLevel, 'Determining best writer'); - - // Check if we're offline using the navigator API - const isOffline = !navigator.onLine; - - if (isOffline) { - Log.verbose(logLevel, 'Offline mode detected, using buffer writer'); - return bufferWriter; - } - - try { - const webFsSupported = await Promise.race([ - canUseWebFsWriter(), - // Add a timeout to avoid hanging in PWA - new Promise((_, reject) => - setTimeout(() => reject(new Error('WebFS check timeout')), 2000) - ) - ]); - - if (webFsSupported) { - Log.verbose(logLevel, 'Using WebFS writer because it is supported'); - return webFsWriter; - } - } catch (err) { - Log.verbose(logLevel, `WebFS check failed: ${err}. Falling back to buffer writer`); - } - - Log.verbose( - logLevel, - 'Using buffer writer because WebFS writer is not supported or unavailable', - ); - return bufferWriter; -}; \ No newline at end of file + if (writer) { + Log.verbose(logLevel, 'Using writer provided by user'); + return writer; + } + + Log.verbose(logLevel, 'Determining best writer'); + + // Check if we're offline using the navigator API + const isOffline = !navigator.onLine; + + if (isOffline) { + Log.verbose(logLevel, 'Offline mode detected, using buffer writer'); + return bufferWriter; + } + + try { + const webFsSupported = await Promise.race([ + canUseWebFsWriter(), + // Add a timeout to avoid hanging in PWA + new Promise((_, reject) => + setTimeout(() => reject(new Error('WebFS check timeout')), 2000), + ), + ]); + + if (webFsSupported) { + Log.verbose(logLevel, 'Using WebFS writer because it is supported'); + return webFsWriter; + } + } catch (err) { + Log.verbose( + logLevel, + `WebFS check failed: ${err}. Falling back to buffer writer`, + ); + } + + Log.verbose( + logLevel, + 'Using buffer writer because WebFS writer is not supported or unavailable', + ); + return bufferWriter; +}; From 4e819db37a99f8d412d233c07978460e7e59f18d Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Thu, 12 Dec 2024 11:17:14 +0100 Subject: [PATCH 10/12] Update auto-select-writer.ts --- packages/webcodecs/src/auto-select-writer.ts | 25 +++++++++++++------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/webcodecs/src/auto-select-writer.ts b/packages/webcodecs/src/auto-select-writer.ts index 5542d090999..12a2618322c 100644 --- a/packages/webcodecs/src/auto-select-writer.ts +++ b/packages/webcodecs/src/auto-select-writer.ts @@ -1,6 +1,9 @@ import {canUseWebFsWriter, webFsWriter} from '@remotion/media-parser/web-fs'; -import type {WriterInterface} from '@remotion/media-parser'; +import { + MediaParserInternals, + type WriterInterface, +} from '@remotion/media-parser'; import {bufferWriter} from '@remotion/media-parser/buffer'; import type {LogLevel} from './log'; import {Log} from './log'; @@ -25,13 +28,19 @@ export const autoSelectWriter = async ( } try { - const webFsSupported = await Promise.race([ - canUseWebFsWriter(), - // Add a timeout to avoid hanging in PWA - new Promise((_, reject) => - setTimeout(() => reject(new Error('WebFS check timeout')), 2000), - ), - ]); + const { + promise: timeout, + reject, + resolve, + } = MediaParserInternals.withResolvers(); + const time = setTimeout( + () => reject(new Error('WebFS check timeout')), + 2000, + ); + + const webFsSupported = await Promise.race([canUseWebFsWriter(), timeout]); + resolve(); + clearTimeout(time); if (webFsSupported) { Log.verbose(logLevel, 'Using WebFS writer because it is supported'); From 0caf429946289e957010b7deadda1928b47a8fb6 Mon Sep 17 00:00:00 2001 From: Jonny Burger Date: Thu, 12 Dec 2024 11:37:31 +0100 Subject: [PATCH 11/12] Update service-worker.ts --- packages/convert/app/service-worker.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/convert/app/service-worker.ts b/packages/convert/app/service-worker.ts index 4fd1bb000f2..c922339f1bc 100644 --- a/packages/convert/app/service-worker.ts +++ b/packages/convert/app/service-worker.ts @@ -1,3 +1,5 @@ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-nocheck const $FILES = []; // ^ leave this - will get filled in during build // --auto-generated-until-here From 8b3e8ca4909a282a141791ab2f0fa11fb73aeab6 Mon Sep 17 00:00:00 2001 From: Johnpaul Date: Thu, 12 Dec 2024 11:51:54 +0100 Subject: [PATCH 12/12] fix entry.client.tsx --- packages/convert/app/entry.client.tsx | 31 +++++++++++++-------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/packages/convert/app/entry.client.tsx b/packages/convert/app/entry.client.tsx index 3fd6aa01c9b..6fb3f8b2536 100644 --- a/packages/convert/app/entry.client.tsx +++ b/packages/convert/app/entry.client.tsx @@ -1,21 +1,20 @@ -import {RemixBrowser} from '@remix-run/react'; -import React from 'react'; -import {startTransition} from 'react'; -import {hydrateRoot} from 'react-dom/client'; +import { RemixBrowser } from "@remix-run/react"; +import { hydrateRoot } from "react-dom/client"; +import { startTransition } from "react"; const registerServiceWorker = () => { - if ('serviceWorker' in navigator) { - window.addEventListener('load', () => { - navigator.serviceWorker - .register('/convert/service-worker.js') - .catch((error) => { - console.log('SW registration failed:', error); - }); - }); - } + if ("serviceWorker" in navigator) { + window.addEventListener("load", () => { + navigator.serviceWorker + .register("/convert/service-worker.js") + .catch((error) => { + console.log("SW registration failed:", error); + }); + }); + } }; startTransition(() => { - hydrateRoot(document, ); - registerServiceWorker(); -}); + hydrateRoot(document, ); + registerServiceWorker(); +}); \ No newline at end of file