-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Interactivity API: Use modules instead of scripts in the frontend #56143
Interactivity API: Use modules instead of scripts in the frontend #56143
Conversation
Hi all, I'm a third party dev who has been experimenting with the Interactivity API the past few versions of Gutenberg and notice that with this RC, the API is no longer working for third party blocks (at least the way it used to with just adding a viewScript and the data-wp-interactive attribute to interactive blocks). I'm getting the following errors with blocks/code that was working previously: VM3154 index.min.js:1 Uncaught SyntaxError: Unexpected token 'export' (at VM3154 index.min.js:1:33535) Can someone point me to the new method for registering/using interactive third party blocks? Please let me know if there is a better place to ask this question. Thanks! |
I'm working on a migration guide to explain how to use modules. I'll let you know once it's ready. |
Thanks @luisherranz, greatly appreciated. 🙏 Moving back to 17.02 for the time being. |
Looks like this PR had a small but noticeable impact on LCP - TTFB metrics https://www.codevitals.run/project/gutenberg |
In the Editor? That doesn't make sense… |
@luisherranz no in the frontend. |
That would imply that modules are slower than deferred scripts, which should not be. What is it testing? Which site/theme/blocks? |
Oh, there is a difference indeed, the polyfill! Let me make a PR to load it only when there's an import map and only when the browser doesn't support it, to see if the numbers improve. |
@oandregal knows more about this test but I believe we're used a fixed version of "twentytwentythree“ with the default content. |
Is there a way to see if this PR improves those numbers? |
Yes, you can check the logs of the performance job https://github.com/WordPress/gutenberg/actions/runs/7051192339/job/19193537419?pr=56699 But there's a margin of error, if the change is small, it's better to confirm it in the graphs post merge. |
It didn't improve the metrics, so I'll do more tests. I'll report my findings in the new PR. |
@luisherranz I was able to figure out how to get this all working with the module api/interactivity. Very cool features and I can see how huge this is for WP. What's the best way to stop webpack from trying to bundle the @wordpress/interactivity import so view.js files can still be built without breaking on the front end? So far I've tried this (and every variant I could come up with including no externalsType, no experiments, "wp-interactivity", ["wp", "interactivity"], etc.) in webpack.config.js but no luck:
I'm sure it's something dumb but looking forward to any input/the guide! |
@briangrider, what I did for the This is a temporary solution because that file won't be minified and you cannot divide it into multiple files, but I hope it'd be enough for testing purposes until we figure out how to integrate it with Let me know if that works for you! |
@luisherranz Yep, this is what I was doing too and it works fine! Like you said, not having multiple files and no minification is where I was getting hung up but it doesn't seem like it's too big of a deal at this point because a standard viewScript (at least the ones I'm writing) tends to be around 100-200 lines or less. I think once this is in core, it'll be important to be able to use the standard wp-scripts package but in the interim, this is an easy enough way to be able to experiment with this awesome new functionality |
…6143) * Bundle `@wordpress/interactivity` as an ES module * Add the class with a basic API * Make it work with the Navigation block * Add versions * Register `@wordpress/interactivity` module * Add query and image blocks * Add id with module identifier to the enqueued modules * Add requried $usage for admin/frontend * Avoid the use of enqueue to register modules * Refactor versions * Switch from `both` to `['admin', 'frontend']` * Improve comments * Add an optional static dependency graph * Add static and dynamic dependencies in the server * Add the file and search blocks * Move $version out of $args to match wp_register_script * Improve version logic * Add polyfill * Fix $version using its own arg in register calls * Add unit tests * Refactor tests, add test get import map * Cleaning data * Use gutenberg_url() * Use wp_print_script_tag * Fix DocBlock on get_import_map() * Load navigation module only on Gutenberg plugin * Load query module only on Gutenberg plugin * Load search module only on Gutenberg plugin * Load file module only on Gutenberg plugin * Load image module only on Gutenberg plugin * Make registration optional * Improve navigation logic * Remove unnecessary check * Fix missing view file * Don't print the import map if it's empty * Load the importmap polyfill locally * Move the es-modules-shims package to the top * Use the public functions in the tests * Update test to be more output oriented * Remove we from comments. * Start using modules in the interactivity e2e tests * Update package-lock.json --------- Co-authored-by: Carlos Bravo <[email protected]>
Loading modules does not seem to work with classic themes, as reported by #57370. In the classic theme, only polyfill JS is loaded. Block Theme: <!DOCTYPE html>
<html lang="ja">
<head>
<!-- ... -->
<script type="importmap">
{"imports":{"@wordpress\/interactivity":"http:\/\/localhost:8888\/wp-content\/plugins\/gutenberg\/build\/interactivity\/index.min.js?ver=6.4.2"}}
</script>
<script type="module" src="http://localhost:8888/wp-content/plugins/gutenberg/build/interactivity/image.min.js?ver=6.4.2" id="@wordpress/block-library/image"></script>
<script type="module" src="http://localhost:8888/wp-content/plugins/gutenberg/build/interactivity/navigation.min.js?ver=6.4.2" id="@wordpress/block-library/navigation-block"></script>
<!-- ... -->
</head>
<body>
<!-- ... -->
<script src="http://localhost:8888/wp-content/plugins/gutenberg/build/modules/importmap-polyfill.min.js" defer=""></script>
</body>
</html> Classic Theme: <!DOCTYPE html>
<html lang="ja">
<head>
</head>
<body>
<!-- ... -->
<script src="http://localhost:8888/wp-content/plugins/gutenberg/build/modules/importmap-polyfill.min.js" defer=""></script>
</body>
</html> My guess is that the reason why it doesn't work is as follows: Each block's module JS is enqueued within the block's rendering callback function (Image block example). Based on the enqueued JS, it outputs the import map and module script via the wp_head hook. For block themes, the entire HTML is pre-fetched and the entire page is displayed. Here, the block's rendering callback is called and the block's module JS is enqueued. This is before the But in the classic theme, the block is rendered when the content is rendered, i.e. when I don't have any good ideas at the moment, but I think some logic adjustments are needed. |
Thanks for the report @t-hamano, and thanks for the fix, @c4rl0sbr4v0: |
What?
Built on top of #56118.
This is the third of a series of experiments to understand the requirements of a hypothetical Modules API. More info in the Tracking Issue:
This experiment aims to implement an API that is more complex than the ones implemented in the first and second experiments, adding a required server dependency graph to be able to print only the necessary modules in the import map, apart from preloading modules to avoid initial waterfalls:
<script>
tag in the head.<link rel="modulepreload">
tag in the head.Why?
In the first experiment, it's not easy to know which modules need to be preloaded and, therefore, it's not easy to avoid the initial waterfalls.
In the second experiment, all the registered modules are added to the import map, even the ones that are not used on the page. In this version, declaring the dependencies is required, so we can know all the modules that are going to be used on the page and only include those in the import map.
How?
By leveraging a new
Gutenberg_Modules
class that acts as a singleton and a couple of functions to expose the functionality:gutenberg_register_module
to register modules and add entries to the import map.gutenberg_enqueue_module
to enqueue modules.Then, we print three times using the
wp_head
action:Testing Instructions
type="module"
are loaded by the interactive blocks.@wordpress/interactivity
module is loaded by the other modules usingimport ... from "@wordpress/interactivity"
.@wordpress/interactivity
module is downloaded at the same time as the rest (instead of after, like in the first experiment), and that there is a link tag withrel="modulepreload"
in the head.@wordpress/interactivity
module.Follow-up tasks