feat(chat): bundle the WebView renderers' JavaScript into the app - #368
Merged
Conversation
The artifact, diagram and math renderers loaded KaTeX, mermaid, marked, highlight.js, Tailwind, Babel and React from public CDNs at render time. Vendoring them fixes what the app executes at build time, lets the renderers work offline, and satisfies F-Droid's rule against downloading executable code without explicit opt-in consent. Part of #288.
Contributor
Android debug APKArtifact:
|
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.
The artifact, diagram and math renderers are WebViews that loaded KaTeX, mermaid, marked, highlight.js, Tailwind, Babel and React from public CDNs at render time. All of it now ships inside the app; nothing executable is fetched at runtime.
This removes the runtime dependency on third-party hosts. The renderers no longer wait on the network to draw a diagram or a formula, so they work offline, and what the app executes is fixed at build time rather than decided by whatever a CDN serves that day — an unversioned URL had already drifted a major version without failing a build or a test. Pinned files in git turn that class of change into a reviewable diff.
Part of #288. F-Droid's policy asks that an app not download executable code without explicit opt-in consent; vendoring satisfies that, and an opt-in gate would have been the alternative route.
Vendoring
scripts/web-assets.json— registry of the 9 assets: version, license, source, what uses it, and apin_reason. Several of those reasons are hard constraints rather than notes — mermaid must stay on the v10 line (v11+ is ESM-only and fails in Android WebView), react is bounded by UMD availability and react-dom must match it exactly, highlight.js must come from@highlightjs/cdn-assetsbecause the main package is CommonJS-only, and Tailwind cannot move to v4 without changing which utilities resolve./update-web-assets— the skill that performs a repin: it reads eachpin_reasonbefore proposing a bump, re-downloads from the official source, regenerates the lock and manifest, and ends by naming what has to be checked on a device. BothCLAUDE.mdfiles document the registry and the rule that vendored files are never hand-edited.scripts/vendor-web-assets.py—--check,--sync,--outdated,--bump,--list.--checkverifies the tree against a sha256 lock and the generated Kotlin manifest, and runs in CI's lint job.feature/chat/src/commonMain/composeResources/files/web/, each project's LICENSE alongside it. +2.47 MB compressed in the APK.Renderers
file:///android_asset/….loadFileURL(_:allowingReadAccessTo:), becauseloadHTMLStringcannot load local subresources at any base URL.import React from 'react'unchanged.Behaviour changes
highlightoption, removed in v5 —setOptionsaccepts one and never calls it — and the highlight.js URL served CommonJS, which throws in a WebView. Now wired through the marked-highlight extension against the team's browser build.style-src https:andfont-src https:, which is the same permission the vendoring removes. Such an artifact renders with fallback styling rather than failing.Tests
VendoredWebAssetInstrumentedTest— loads each renderer's real HTML into a WebView with the settings the scheme depends on,allowFileAccess = falseamong them, and asserts against the live DOM that each library defined itself and produced output: KaTeX's bundled fonts resolve, both the chat-message and artifact mermaid renderers emit SVG, markdown code carries hljs markup coloured by the theme, Tailwind compiles a utility class, and a React artifact mounts and evaluates a hook.VendoredAssetReferenceTest— no document references a remote origin, no CSP permits one to execute, and every path a document references exists in the generated manifest.ReactArtifactRenderTest— rewritten for local resolution.Verification
:app:assembleDebug, and the iOS simulator compile pass.scripts/vendor-web-assets.py --checkpasses; all 41 files confirmed present in the built APK.Notes
page-*.htmlper distinct document into its asset cache. They are cleared when a repin changes the assets, so between repins the count grows with the number of distinct documents rendered.Trackinganti-feature, and release builds fall back to the committed debug key when no signing config is present, where F-Droid needs an unsigned release APK.