Skip to content
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

Bug: Bud's inline runtime is lost in Gutenberg editor when a block is pre-rendered #281

Open
5 tasks done
LachlanArthur opened this issue Mar 13, 2023 · 1 comment
Open
5 tasks done
Labels
bug Something isn't working

Comments

@LachlanArthur
Copy link

Terms

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

  1. Install log1x/acf-composer and create an example block wp acorn acf:block TestBlock
  2. Create a script entrypoint for the block resources/scripts/blocks/test-block.js and add it to the bud.config.mjs under a new bundle name:
    app.entry( {
      "blocks/test-block": [ "@scripts/blocks/test-block" ],
    } )
  3. Enqueue the block's bundle in the block class:
    public function enqueue()
    {
        \Roots\bundle('blocks/test-block')->enqueue();
    }
  4. Build the theme npm run build
  5. Create a page and add the block to it.
  6. 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

@LachlanArthur LachlanArthur added the bug Something isn't working label Mar 13, 2023
@codepuncher
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants