Make WordPress Core

Opened 4 weeks ago

Closed 2 weeks ago

#65260 closed defect (bug) (fixed)

Emoji detection script breaks the script modules import map in the Site Editor

Reported by: wildworks's profile wildworks Owned by:
Milestone: 7.1 Priority: normal
Severity: normal Version: 6.9
Component: Script Loader Keywords: has-patch has-unit-tests needs-testing close
Focuses: Cc:

Description

When the site editor is opened by Firefox, an error occurs regarding the script module, preventing the use of the following two features. This issue should have potentially occurred at r60899, where the emoji loader was converted into a script module, which was around WordPress 6.9.

1. Client-side Abilities API

Access the Abilities API in the browser console.

const { registerAbilityCategory } = await import( '@wordpress/abilities' );

The following error occurs.

Uncaught (in promise) TypeError: The specifier “@wordpress/abilities” was a bare specifier, but was not remapped to anything. Relative module specifiers must start with “./”, “../” or “/”.

This means that the client-side accessibility API cannot be used in the site editor.

2. Math Block preview

Insert a math block and enter some mathematical formula. The following browser console error occurs, and the formula preview is not rendered.

Uncaught (in promise) TypeError: The specifier “@wordpress/latex-to-mathml” was a bare specifier, but was not remapped to anything. Relative module specifiers must start with “./”, “../” or “/”.

This is because the emoji loader is output as a script module within the head tag before the import map.

<html>
<head>
<script type="module">
/**
 * @output wp-includes/js/wp-emoji-loader.js
 */
</script>
</head>
<body>
<script id="wp-importmap" type="importmap" crossorigin="anonymous">
{
  "imports": {
    "@wordpress/route":           "http://localhost:8888/wp-content/plugins/gutenberg/build/modules/route/index.js?ver=48a77bfa70722b4254e4",
    "@wordpress/latex-to-mathml": "http://localhost:8888/wp-content/plugins/gutenberg/build/modules/latex-to-mathml/index.js?ver=e5fd3ae6d2c3b6e669da",
    "@wordpress/vips/worker":     "http://localhost:8888/wp-content/plugins/gutenberg/build/modules/vips/worker.min.js?ver=de1b94d254f242c2192e",
    "@wordpress/abilities":       "http://localhost:8888/wp-content/plugins/gutenberg/build/modules/abilities/index.js?ver=f3475bc77a30dcc5b38d"
  }
}
</script>
</body>
</html>

Fortunately, this issue does not occur in the post editor because the emoji loader is disabled there.

https://github.com/WordPress/wordpress-develop/blob/5a96ff4d54a97955b02ac3c20f3ae7f21185232f/src/wp-admin/edit-form-blocks.php#L39-L42

As a short-term solution, we might need to disable the emoji loader in the site editor as well.

cc @westonruter @jonsurrell

Change History (17)

#1 @westonruter
4 weeks ago

I see, so this is only an issue in the block preview. It's not an issue in the frontend.

Yes, r60899 to fix #63842 is related, but more specifically it was moved to the footer in r60902 to fix #64076. The issue would have happened even more so if it had been left in wp_head.

(On the frontend, the importmap is printed at wp_footer priority 10. It seems like it should have been printed at priority 9, the same as in the admin however, to go along with r62080 for #64907. Nevertheless, the emoji loader on the frontend is printed at wp_footer priority 20 as part of wp_print_footer_scripts. So it shouldn't be a problem on the frontend.)

For the admin, it seems the problem is that the emoji detection script wasn't moved to the footer like it was on the frontend. This might be all we need to do:

  • src/wp-admin/includes/admin-filters.php

    diff --git a/src/wp-admin/includes/admin-filters.php b/src/wp-admin/includes/admin-filters.php
    index 5337cc02c8..2fe6f34034 100644
    a b if ( ! is_customize_preview() ) { 
    5656        add_action( 'admin_print_styles', 'wp_resource_hints', 1 );
    5757}
    5858
    59 add_action( 'admin_print_scripts', 'print_emoji_detection_script' );
     59add_action( 'admin_print_footer_scripts', 'print_emoji_detection_script' );
    6060add_action( 'admin_print_scripts', 'print_head_scripts', 20 );
    6161add_action( 'admin_print_footer_scripts', '_wp_footer_scripts' );
    6262add_action( 'admin_enqueue_scripts', 'wp_enqueue_emoji_styles' );

(Back-compat concerns notwithstanding.)

However, I think we should take this as an opportunity to implement the loading of that module as an external script via #64259. That would also fix this issue.

This ticket was mentioned in PR #11905 on WordPress/wordpress-develop by @jonsurrell.


3 weeks ago
#2

  • Keywords has-patch has-unit-tests added

Move the emoji detection script to the footer in WP Admin. This ensures it should be printed after an importmap and avoid an issue where Firefox does not process importmaps once a module has been encountered.

This implements a minimal fix suggested by @westonruter.

Since [60899], the emoji detection script is output as a <script type="module">. In the admin it was hooked to admin_print_scripts, so the module script tag was emitted inside <head> ahead of the script-module import map (which is printed at admin_print_footer_scripts priority 9).

Move the hook to admin_print_footer_scripts, mirroring the frontend behavior put in place by [60902] for #64076. Update the matching remove_action() in edit-form-blocks.php so the post editor continues to suppress the emoji detection script.

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

---

This can be tested by following the reproduction steps in the ticket. Firefox should be used.

In the site editor on trunk, module specifiers cannot be resolved because the importmap is not processed. For example await import('@wordpress/route') will throw an error like:

TypeError: The specifier “@wordpress/route” was a bare specifier, but was not remapped to anything. Relative module specifiers must start with “./”, “../” or “/”.

On this branch, the import will work correctly.

---

## Use of AI Tools

AI assistance: Yes
Tool(s): Claude
Model(s): Opus-4.7
Used for: Complete implementation, verification, and testing based on ticket.

#3 @jonsurrell
3 weeks ago

#65165 is a related ticket. There's some discussion of a polyfill for multiple importmaps. I believe that would solve the issues here.

This type of problem is also something that can be caused by themes or plugins, for example https://github.com/WordPress/gutenberg/issues/78041. Multiple importmaps (and a polyfill for now) seems like a nice improvement to prevent this type of problem in the future and from sources outside of WordPress Core's control.

#4 @westonruter
3 weeks ago

@wildworks I'm confused because when testing this I'm not actually seeing the emoji detection script being printed at all in the admin. My above suggestion is invalid because r60902 failed to account for it running in the admin. I've opened #65310 to address this.

So if the emoji detection script is failing to print in the admin, then it seems to be specific to how the Site Editor constructs it iframe to add the scripts from the frontend. I vaguely recall looking at this with @jonsurrell previously, for how scripts and styles from the frontend get added to the Site Editor iframe to maintain visual parity as much as possible. It seems that perhaps this isn't taking into account the HEAD vs footer distinction?

@jonsurrell commented on PR #11905:


3 weeks ago
#5

Closing in favor of #11931

#6 @westonruter
3 weeks ago

In 62410:

Emoji: Use the admin_print_footer_scripts action for printing the emoji detection script in the admin.

This corrects an oversight in an optimization made to print_emoji_detection_script() which moved the emoji detection script to the wp_print_footer_scripts action. Since this action doesn't fire in the admin, no script was printed. Now in the admin, the script is printed at the admin_print_footer_scripts action. Existing sites that wish to omit emoji can continue to do remove_action( 'admin_print_scripts', 'print_emoji_detection_script' ).

Tests are added covering all four branches of print_emoji_detection_script(): hooking the script onto the appropriate footer action, and printing it directly when that action has already fired, in both the admin and the frontend.

Missing parameter and return types are added to the get_echo() test helper.

Developed in https://github.com/WordPress/wordpress-develop/pull/11931.
Follow-up to r60902.

Props westonruter, jonsurrell.
See #64076, #65260.
Fixes #65310.

#7 @westonruter
3 weeks ago

@wildworks Does r62410 fix the issue for you? It seems to for @jonsurrell, although I don't understand why.

#8 @wildworks
3 weeks ago

I confirmed that the two scripts were swapped.

<html>
<head>
</head>
<body>
<script id="wp-importmap" type="importmap" crossorigin="anonymous">
{
  "imports": {
    "@wordpress/route":           "http://localhost:8888/wp-content/plugins/gutenberg/build/modules/route/index.js?ver=48a77bfa70722b4254e4",
    "@wordpress/latex-to-mathml": "http://localhost:8888/wp-content/plugins/gutenberg/build/modules/latex-to-mathml/index.js?ver=e5fd3ae6d2c3b6e669da",
    "@wordpress/vips/worker":     "http://localhost:8888/wp-content/plugins/gutenberg/build/modules/vips/worker.min.js?ver=de1b94d254f242c2192e",
    "@wordpress/abilities":       "http://localhost:8888/wp-content/plugins/gutenberg/build/modules/abilities/index.js?ver=f3475bc77a30dcc5b38d"
  }
}
</script>
<script type="module">
/**
 * @output wp-includes/js/wp-emoji-loader.js
 */
</script>
</body>
</html>

2. Math Block preview

Insert a math block and enter some mathematical formula. The following browser console error occurs, and the formula preview is not rendered.

Uncaught (in promise) TypeError: The specifier “@wordpress/latex-to-mathml” was a bare specifier, but was not remapped to anything. Relative module specifiers must start with “./”, “../” or “/”.

I have confirmed that this issue has been resolved.

1. Client-side Abilities API

Access the Abilities API in the browser console.

const { registerAbilityCategory } = await import( '@wordpress/abilities' );

The following error occurs.

Uncaught (in promise) TypeError: The specifier “@wordpress/abilities” was a bare specifier, but was not remapped to anything. Relative module specifiers must start with “./”, “../” or “/”.

I confirmed that this issue still reproduces. However, it seems to occur in browsers other than Firefox as well. This might be a separate issue.

#9 @jonsurrell
3 weeks ago

I confirmed that this issue still reproduces. However, it seems to occur in browsers other than Firefox as well. This might be a separate issue.

I've been unable to reproduce this (on trunk at ac539ca198ccef82c26d79a716cc22cf3750f240 which includes r62410).

It's very surprising because we can see the module specifier in the importmap in the shared snippet: "@wordpress/abilities": "…/abilities/index.js?ver=…".

A possible explanation that comes to mind is the context. In the editor-canvas iframe, the module is unlikely to be available (see #64360). The @wordpress/abilities module should be available to import in the top context where the importmap is included. If I change the context to the site-editor iframe or try to use it in a script in that context I see the same errors.

#10 @gziolo
3 weeks ago

  • Component changed from Abilities API to Script Loader
  • Milestone changed from Awaiting Review to 7.1

This isn't strictly an issue with the Abilities API, but with the script loader. I updated the component accordingly.

#11 @jonsurrell
2 weeks ago

  • Keywords needs-testing added

Additional testing would be helpful to understand the impact of r62410 on this issue. See #comment:8 and #comment:9 where we have some conflicting reports. Tests can use latest trunk.

#12 follow-up: @wildworks
2 weeks ago

Sorry, I might be mistaken about something. I tried testing again with the trunk branch (01debdf). By default, it seems that the Abilities API is not imported at all. Is this the correct state?

<script id="wp-importmap" type="importmap">
{
  "imports": {
    "@wordpress/latex-to-mathml": "http://localhost:8889/wp-includes/js/dist/script-modules/latex-to-mathml/index.js?ver=e5fd3ae6d2c3b6e669da",
    "@wordpress/route": "http://localhost:8889/wp-includes/js/dist/script-modules/route/index.js?ver=c5843b6c5e84b352f43b"
  }
}
</script>

#13 in reply to: ↑ 12 @jonsurrell
2 weeks ago

Replying to wildworks:

It seems that the Abilities API is not imported at all. Is this the correct state?

I believe with no plugins, @wordpress/abilities is not included in the importmap on the site editor. When I activate either a recent Gutenberg build (from trunk) or the AI plugin (enabled and configured), then the module is available on the site editor and I'm able to run await import('@wordpress/abilities') in the console without error.

#14 @westonruter
2 weeks ago

#65363 was marked as a duplicate.

#15 follow-up: @wildworks
2 weeks ago

I believe with no plugins, @wordpress/abilities is not included in the importmap on the site editor. When I activate either a recent Gutenberg build (from trunk) or the AI plugin (enabled and configured), then the module is available on the site editor and I'm able to run await import('@wordpress/abilities') in the console without error.

Thank you, I have confirmed this. Can we close this ticket now?

#16 in reply to: ↑ 15 @westonruter
2 weeks ago

  • Keywords close added

Replying to wildworks:

Thank you, I have confirmed this. Can we close this ticket now?

Since you opened it, if you're satisfied with the current state, I'd say yes.

#17 @wildworks
2 weeks ago

  • Resolution set to fixed
  • Status changed from new to closed
Note: See TracTickets for help on using tickets.