feat: replace the archive.org asm.js encoder with vendored ffmpeg.wasm
MP4/GIF export used to importScripts() an 18.5 MB asm.js ffmpeg build from https://archive.org/download/ffmpeg_asm/ffmpeg_asm.js: no integrity check, no pinning, executed in the page, and unavailable offline. vendor.mjs now copies ffmpeg.wasm out of node_modules, where package-lock.json pins it by hash, and no CDN fallback is left anywhere in the app. @ffmpeg/core-st is the single-threaded core, chosen deliberately: the default @ffmpeg/core is built with pthreads and needs SharedArrayBuffer, which requires COOP/COEP isolation, which would break the Pixabay, Unsplash and Google Fonts requests. That core also forces two things worth knowing: - mainName: 'main' is mandatory. The loader defaults to proxy_main, which only the multi-threaded build exports, so load() compiles all 23 MB and then aborts. - Its main() calls exit(), so an instance survives exactly one command. Reusing one dies with "Program terminated with exit(0)", so convertStreams builds and tears one down per conversion (~110 ms, and the 23 MB heap comes back in between). The teardown also runs on failure: an interrupted run otherwise leaves the loader's "running" flag set and wedges every later conversion until a page reload. MP4 encodes with libx264 -crf 23 -pix_fmt yuv420p plus AAC rather than mpeg4 -b:v 6400k. Same core, better quality per byte, and yuv420p is what makes it play in Safari and QuickTime. The two @ffmpeg packages are dependencies, not devDependencies, so the Docker vendor stage can npm ci --omit=dev without pulling in electron; build.files excludes them from the asar since src/vendor/ffmpeg/ already carries the copies the app loads. WITH_FFMPEG=0 now means MP4/GIF export is unavailable and says so, rather than silently fetching an encoder at run time. Also deletes src/js/libraries/ffmpeg.min.js, an unreferenced ffmpeg.wasm loader stub that would have fetched its core from unpkg, and prunes the stale src/vendor/ffmpeg_asm.js from existing checkouts — src/vendor/ is packaged whole, so it would have shipped 18.5 MB of dead weight in every installer. Verified in Chromium against a real MediaRecorder WebM: core loads with crossOriginIsolated false, MP4 24 KB decoding to 320x240 / 2.00 s, GIF 138 KB, the two back to back, and the missing-core path reporting correctly. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+9
-3
@@ -6,13 +6,19 @@
|
||||
# Build: docker build -t motionity:latest .
|
||||
# Run: docker run --rm -p 8080:8080 motionity:latest
|
||||
#
|
||||
# WITH_FFMPEG=0 drops the 18.5 MB asm.js ffmpeg build from the image. MP4/GIF
|
||||
# export then downloads it from archive.org on first use instead of working
|
||||
# offline; everything else is unaffected.
|
||||
# WITH_FFMPEG=0 drops the 23 MB ffmpeg.wasm core from the image and disables
|
||||
# MP4/GIF export, which then reports itself as unavailable. It no longer falls
|
||||
# back to downloading the encoder at run time: the old asm.js build came from a
|
||||
# public archive.org mirror with no integrity check. Everything else, WEBM
|
||||
# export included, is unaffected.
|
||||
|
||||
FROM node:22-alpine AS vendor
|
||||
ARG WITH_FFMPEG=1
|
||||
WORKDIR /app
|
||||
# ffmpeg.wasm is a runtime dependency, so --omit=dev pulls it in without
|
||||
# dragging electron and electron-builder (~400 MB) into the build.
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci --omit=dev --no-audit --no-fund
|
||||
COPY scripts/vendor.mjs scripts/
|
||||
COPY src/index.html src/
|
||||
RUN if [ "$WITH_FFMPEG" = "1" ]; then \
|
||||
|
||||
Reference in New Issue
Block a user