Bug: Bud's inline runtime is lost in Gutenberg editor when a block is pre-rendered
LachlanArthur opened this issue · 1 comments
Terms
- I have read the guidelines for Contributing to Roots Projects
- This request is not a duplicate of an existing issue
- I have read the docs and followed them (if applicable)
- I have seached the Roots Discourse for answers and followed them (if applicable)
- This is not a personal support request that should be posted on the Roots Discourse community
Description
Context
I'm using log1x/acf-composer
to create ACF Gutenberg blocks.
What's wrong?
When a block enqueues its own Bud bundle, the inline runtime is lost when loading the Gutenberg editor.
This is due to WP pre-rendering the blocks via internal calls to the WP REST API early in the page lifecycle:
Call stack
Roots\Acorn\Assets\Bundle->js (vendor\roots\acorn\src\Roots\Acorn\Assets\Bundle.php:83)
Roots\Acorn\Assets\Bundle->enqueueJs (vendor\roots\acorn\src\Roots\Acorn\Assets\Concerns\Enqueuable.php:64)
Roots\Acorn\Assets\Bundle->enqueue (vendor\roots\acorn\src\Roots\Acorn\Assets\Concerns\Enqueuable.php:84)
App\Blocks\Testimonials->enqueue (web\app\themes\base\app\Blocks\Testimonials.php:165)
Log1x\AcfComposer\Block->Log1x\AcfComposer\{closure:/app/vendor/log1x/acf-composer/src/Block.php:282-284} (vendor\log1x\acf-composer\src\Block.php:283)
acf_enqueue_block_type_assets (web\app\plugins\advanced-custom-fields-pro\pro\blocks.php:795)
acf_render_block (web\app\plugins\advanced-custom-fields-pro\pro\blocks.php:636)
acf_rendered_block (web\app\plugins\advanced-custom-fields-pro\pro\blocks.php:569)
acf_render_block_callback (web\app\plugins\advanced-custom-fields-pro\pro\blocks.php:502)
WP_Block->render (web\wp\wp-includes\class-wp-block.php:256)
render_block (web\wp\wp-includes\blocks.php:1051)
do_blocks (web\wp\wp-includes\blocks.php:1089)
WP_Hook->apply_filters (web\wp\wp-includes\class-wp-hook.php:308)
apply_filters (web\wp\wp-includes\plugin.php:205)
WP_REST_Posts_Controller->prepare_item_for_response (web\wp\wp-includes\rest-api\endpoints\class-wp-rest-posts-controller.php:1857)
WP_REST_Posts_Controller->get_item (web\wp\wp-includes\rest-api\endpoints\class-wp-rest-posts-controller.php:568)
WP_REST_Server->respond_to_request (web\wp\wp-includes\rest-api\class-wp-rest-server.php:1171)
WP_REST_Server->dispatch (web\wp\wp-includes\rest-api\class-wp-rest-server.php:1018)
rest_do_request (web\wp\wp-includes\rest-api.php:535)
rest_preload_api_request (web\wp\wp-includes\rest-api.php:2884)
array_reduce (web\wp\wp-includes\block-editor.php:635)
block_editor_rest_api_preload (web\wp\wp-includes\block-editor.php:635)
require (web\wp\wp-admin\edit-form-blocks.php:77)
{main} (web\wp\wp-admin\post.php:187)
When the custom block is pre-rendered, the JS is enqueued, and the inline runtime is flagged as having been output.
Then the actual page renders, the inline runtime is not output because the Bundle class remembers inlining it when rendering the block earlier.
What have you tried? / Temporary workaround
For now I'm keeping track of when the REST API callbacks have finished, and using that in each bundle's conditional callback:
function handlingRestCallback(int $increment = 0)
{
static $depth = 0;
$depth += $increment;
return $depth > 0;
}
add_filter('rest_request_before_callbacks', function ($data) {
handlingRestCallback(1);
return $data;
});
add_filter('rest_request_after_callbacks', function ($data) {
handlingRestCallback(-1);
return $data;
});
And the block conditionally enqueues using that function:
\Roots\bundle('blocks/testimonials')->when(fn () => ! handlingRestCallback())->enqueue();
What insights have you gained?
The pre-rendering of blocks is essential for a good editing experience, so it can't be disabled.
Possible solutions
The might be a simpler way to detect that the bundle is being enqueued via an internal REST request, but the workaround above is the only way I've found.
Another workaround (which doesn't really solve the underlying problem) is to include all the block JS in a single editor bundle. This would prevent it from being enqueued during the pre-rendering step.
Steps To Reproduce
- Install
log1x/acf-composer
and create an example blockwp acorn acf:block TestBlock
- Create a script entrypoint for the block
resources/scripts/blocks/test-block.js
and add it to thebud.config.mjs
under a new bundle name:app.entry( { "blocks/test-block": [ "@scripts/blocks/test-block" ], } )
- Enqueue the block's bundle in the block class:
public function enqueue() { \Roots\bundle('blocks/test-block')->enqueue(); }
- Build the theme
npm run build
- Create a page and add the block to it.
- Edit the page and check the source, the inline runtime is now missing
Expected Behavior
The inline runtime should be included in the Gutenberg editor if the theme has enqueued an editor script.
Actual Behavior
The inline runtime is missing if a block with its own enqueued bundle was pre-rendered.
Relevant Log Output
No response
Versions
Acorn v3.1.0
I seem to be having the same issue.
My steps to reproduce are the same, but the way I test is different.
Using this: https://github.com/roots/bud/blob/main/examples/wordpress-editor/src/example.plugin.js
When another bundle has been enqueued, the example linked above does not unregister blocks.
Removing bundle('blocks/test-block')->enqueue()
from the ACF block solves the issue.
I have also tested your temporary workaround @LachlanArthur and that works great.