feat(viewer): server-side asset fallback when the Service Worker can't register#39
Open
erseco wants to merge 6 commits into
Open
feat(viewer): server-side asset fallback when the Service Worker can't register#39erseco wants to merge 6 commits into
erseco wants to merge 6 commits into
Conversation
…t register The viewer renders an .elpx by registering a scoped Service Worker that streams the package's internal assets from memory. That can't work when Nextcloud is embedded in an origin already owned by a controlling Service Worker (e.g. the Nextcloud Playground): the browser fetches a worker's script straight from the network, bypassing the controlling SW, so the virtual /apps/exelearning/sw.js route 404s and registration throws. When registration fails, fall back to the existing server-side AssetController (/apps/exelearning/asset/<fileId>/<entry>), which extracts and streams each entry from the stored package — no client Service Worker needed. Requires the canonical file id; otherwise the original error is surfaced as before. - paths: buildAssetUrl() + ASSET_PREFIX (+ tests) - iframe-renderer: extract buildSandboxedIframe() shared by both paths - ElpxViewer: try SW, catch -> attachServerIframe()
Contributor
Preview this PR in the Nextcloud PlaygroundA fresh Nextcloud boots in your browser with this branch's Bundled eXeLearning editor: |
…tton - blueprint: disable firstrunwizard and set core whatsNewEnabled=no so the instance lands straight on Files (mirrors the playground default blueprint). - README + PR comment: use the official playground-preview-button.svg (referenced via raw.githubusercontent on the playground repo) at ~50% size (width 224), linking to the playground in a new tab.
Resolve the latest stable eXeLearning editor tag once, download exactly
that, and surface it in the PR comment ('Bundled eXeLearning editor:
<version>') instead of the build-artifact line.
…cope
The editor iframe URL came from server-rendered initial state, computed
with an empty webroot. When Nextcloud is served under a sub-path (e.g. the
browser Playground scopes everything under /playground/<scope>/…), that
unscoped URL used as the iframe src escapes the scope and 404s — the host
then waits forever on "Loading editor…".
Build it client-side with generateUrl('/apps/exelearning/editor/iframe'),
which resolves against the live OC.webroot and is correct both in a normal
install and under a scoped path. Same flow in the embedded viewer and the
standalone editor page. Drops the now-unused appWebRoot() helper.
…ks under a scoped path
The editor's embedding config (basePath, parentOrigin, trustedOrigins) was
computed server-side. Under a scoped sub-path (e.g. the browser Playground),
the server's webroot is empty, so basePath was unscoped — the editor's
ResourceFetcher then loaded its theme/content bundles from
/apps/exelearning/js/editor/bundles/*.zip, which escapes the scope and 404s,
and Save failed ("Failed to fetch content/css/base.css").
Derive basePath from document.baseURI (which equals the scoped <base href>
at runtime), and parentOrigin/trustedOrigins from window.location.origin, in
the injected config script. Correct both in a normal install and under a
scoped path.
The bundled eXeLearning editor ships its themes and content CSS as
js/editor/bundles/*.zip (themes/base.zip, content-css.zip, …), which the
editor's ResourceFetcher loads when exporting on Save. .distignore excluded
`*.zip` unanchored, so rsync stripped these nested bundles from the
distribution package — the editor then 404s on Save ("Failed to fetch
content/css/base.css"). This affected both the playground preview and any
real packaged release (make up copies js/ directly, so it only showed in
packaged builds).
Anchor the excludes to the repo root (`/*.zip`, `/*.tar.gz`) so only the
top-level build artifacts are stripped, not the editor's runtime bundles.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Opening an
.elpxin the Nextcloud Playground fails with:The viewer renders a package by registering a scoped Service Worker that streams the package's internal assets from memory. But the Playground is itself a Service Worker emulating the Nextcloud server. When the browser registers a second worker, it fetches that worker's script straight from the network, bypassing the controlling SW (by spec) — so
/apps/exelearning/sw.jshits the static host and 404s. (Fetched normally through the page it returns 200; only the registration fetch bypasses the playground SW.)Fix
When SW registration fails, fall back to the existing server-side
AssetController(/apps/exelearning/asset/<fileId>/<entry>) — which already exists "for environments where Service Workers are not viable (e.g. embedded in another origin)" but wasn't wired into the viewer. It extracts and streams each entry from the stored package, so the iframe renders entirely through normal HTTP (which the playground routes to PHP-wasm). No client Service Worker needed.The SW path stays the default for normal installs; the fallback only kicks in on registration failure and needs the canonical file id (always present in the Files viewer). If there's no usable file id the original error is surfaced as before.
Changes
elpx/paths.ts:buildAssetUrl()+ASSET_PREFIX(+ unit tests).elpx/iframe-renderer.ts: extractbuildSandboxedIframe()shared by the SW and server paths (identical sandbox flags + external-link rewiring).viewer/ElpxViewer.vue: try SW → on failureattachServerIframe().Test
npm test(54 pass),npm run lint,npm run typecheck✅. Verified end-to-end against the Playground preview (see the playground link this PR posts).