Skip to content

Media: Fix animated GIF to video conversion failing due to missing import map entry#12598

Closed
adamsilverstein wants to merge 4 commits into
WordPress:trunkfrom
adamsilverstein:fix/gif-video-conversion-import-map
Closed

Media: Fix animated GIF to video conversion failing due to missing import map entry#12598
adamsilverstein wants to merge 4 commits into
WordPress:trunkfrom
adamsilverstein:fix/gif-video-conversion-import-map

Conversation

@adamsilverstein

@adamsilverstein adamsilverstein commented Jul 20, 2026

Copy link
Copy Markdown
Member

What

Fixes animated GIF to video conversion, which currently fails silently everywhere client-side media processing runs (block editor included): no animated_video companion is created, and the console shows:

[video-conversion] GIF to video conversion failed: TypeError: Failed to resolve module specifier '@wordpress/video-conversion/worker'

Why

Two separate bugs prevent upload-media.js from lazily importing the conversion worker:

  1. wp_set_client_side_media_processing_flag() clobbers the import map. It calls wp_scripts()->add_data( 'wp-upload-media', 'module_dependencies', array( '@wordpress/vips/worker' ) ) on every admin request. add_data() overwrites rather than merges, wiping the module_dependencies already registered from script-loader-packages.php - which include both @wordpress/vips/worker and @wordpress/video-conversion/worker. The call was harmlessly redundant when introduced in [62428] (the packages file only declared the vips worker then) and became destructive when the video-conversion dependency landed in the asset file. With the entry missing from the import map, the dynamic import() throws. Since the packages registration already handles this correctly, the call is simply removed.

  2. The unminified video-conversion/worker.js is never shipped. Like the VIPS modules, the Gutenberg build only produces worker.min.js (the file is large inlined worker code with no debugging value), but wp_default_script_modules() only special-cases vips/ to always use the minified file. With SCRIPT_DEBUG enabled, the import map pointed at a non-existent worker.js and the import 404ed. The existing vips condition is extended to cover video-conversion/worker.js.

Testing

Manually verified on trunk (Chrome, cross-origin isolated via Document-Isolation-Policy):

Before: uploading an animated GIF logs the module-specifier TypeError (plus a secondary blob: ... ERR_FILE_NOT_FOUND error), and the attachment's media_details has no animated_video.

After: the same upload completes with no console errors, the import map contains both workers, and the attachment gains animated_video: <name>.mp4 and animated_video_poster: <name>.jpeg, with both companion files sideloaded to the uploads directory.

Includes PHPUnit coverage (--group 65664):

  • test_set_flag_preserves_upload_media_module_dependencies() asserts wp_set_client_side_media_processing_flag() leaves the upload-media script's module_dependencies untouched and that both workers are present. Verified to fail against the pre-fix code (the dependency list collapses to just the vips worker) and pass with the fix.
  • test_default_script_module_files_exist() asserts every default script module resolves to an existing file for both SCRIPT_DEBUG variants, so a minified-only module can no longer be registered with a non-existent non-minified URL.

Both full test files pass (25 + 108 tests); php -l and PHPCS pass on all changed files.

Commit message

Media: Fix animated GIF to video conversion module loading.

Fix an issue with animated GIF conversion where the conversion worker could not be resolved from the script modules import map. `wp_set_client_side_media_processing_flag()` re-declared the `wp-upload-media` module dependencies via `WP_Scripts::add_data()`, which overwrites rather than merges, wiping the `@wordpress/video-conversion/worker` entry already registered from the packages asset file.  

Additionally, only a minified build of the video-conversion worker is shipped, so with `SCRIPT_DEBUG` enabled the import map pointed at a non-existent `worker.js`. The always-minified exception in `wp_default_script_modules()` is extended from the vips modules to also cover `video-conversion/worker.js`.

Follow-up to [62428].

Props andrewserong, swissspidy.
Fixes #65664.

Trac ticket: https://core.trac.wordpress.org/ticket/65664

wp_set_client_side_media_processing_flag() re-registered
@wordpress/vips/worker as a module dependency of the wp-upload-media
script on every admin request. WP_Scripts::add_data() overwrites rather
than merges, so this dropped the other dependencies declared in
script-loader-packages.php - notably @wordpress/video-conversion/worker,
which was added there after this call was introduced. With that entry
missing from the import map, import( '@wordpress/video-conversion/worker' )
throws and animated GIFs never get their companion video.

The packages asset file already registers both workers when the script
is registered, so the call can simply be removed.
…_DEBUG

The Gutenberg build only ships video-conversion/worker.min.js: like the
VIPS modules, the unminified worker is large inlined code with no
debugging value, so it is not produced at all. wp_default_script_modules()
only special-cased vips/ for this, so with SCRIPT_DEBUG enabled the
import map pointed at the non-existent worker.js and the dynamic import
failed with a 404, breaking animated GIF to video conversion in
development environments.
The first test guards against wp_set_client_side_media_processing_flag()
modifying the upload-media script's module dependencies again: add_data()
overwrites rather than merges, which is how the video-conversion worker
silently dropped out of the import map.

The second test verifies that every default script module resolves to a
file that exists on disk for both SCRIPT_DEBUG variants, so a module
that is only shipped minified cannot be registered with a non-existent
non-minified URL without failing the suite.

See #65664.
@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props adamsilverstein, andrewserong, swissspidy.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@github-actions

Copy link
Copy Markdown

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

@andrewserong andrewserong left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! This is testing nicely for me on a local checkout, thanks for the explanations in the PR description 👍

Adding the video-conversion worker to the list in script-modules.php makes sense for now. I suppose if we ever grow this list we could abstract the concept somehow, but for the scope of client-side media processing I doubt we'll ever really have more than vips + video-conversion? And if we do want to proposed more worker / skipping non-minified build features, then I reckon we could revisit then.

LGTM!

@adamsilverstein

Copy link
Copy Markdown
Member Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants