bigbite / build-tools

MIT License
6 stars 1 forks source link

Building block assets #17

Open g-elwell opened 2 years ago

g-elwell commented 2 years ago

I've been looking into block themes and how blocks are going to be built in WP going forward, there's some interesting developments in enqueuing assets on a per-block basis.

For example, if you register a block using block.json you can define its script/style assets there - including separate ones for editor/frontend bundles. WordPress will only load the assets if the block is present on the current page, so it's a pretty cool optimisation and has already landed in core.

Since these build tools support multiple entrypoints, it's possible to get this working, but I feel like treating a block more as a 'project' could be an overall better approach, especially since a theme or plugin might have several blocks each featuring multiple entrypoints.

This could also enable block code to live together, rather than the current requirement where JS and PHP code for the same block need to be managed in separate locations, perhaps something like this (you'd potentially have multiples of these inside a specific plugin/theme):

/my-block-project
  /src
    /entrypoints
      editor.js  // client-side block registration
      frontend.js  // (optional) front-end functionality
      shared.js // (optional) for generating shared.css and/or a shared js bundle
  /dist
    editor.js
    frontend.js
    shared.css
  asset-settings.php
  block.json
  index.php // server-side block registration

The end result should be that you just need to require the index.php file in order for your block to work, since it uses block.json to register the block, and the block.json tells it which scripts/styles to enqueue. I haven't tested this fully, since I wanted to see what you all think about whether it woulda good idea to integrate this with the build tools?

I'm guessing either another folder would need to be scanned for projects, or we'd consider adding a config so you can tell the build tools which projects it should be looking for explicitly...

Ref: https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/

g-elwell commented 2 years ago

@scottblackburn this is related to enqueuing of assets per-block, would be interested to know what you think

chrishbite commented 4 months ago

Hey @g-elwell and @ampersarnie I was going to open a new issue for Increase support for block.json asset values but noticed this open issue and believe the goals are the same so I've added what would have been my issues description below.

Happy to discuss any of this further though as a lot of this is untested/theoretical as was just putting down some ideas around it.

Description

block.json allows the declaration of a blocks style, script and render assets directly, I believe we should increase support for this to leverage a number of benefits and potentially move towards this way as standard as this is currently the recommended approach for specific block scripts/styles.

The current supported assets via block.json are as follows;

editorScript
script
viewScript
viewScriptModule
editorStyle
style
viewStyle
render 

More information and definitions of the above can be found here.

Currently I think the only way to use block.json assets would be to register your styles/scripts via the corresponding wp_register_ function and then use the registered handle for each asset in the block.json.

Multiple entrypoints files would be required to generate the corresponding asset files for a block and if you have multiple blocks the entrypoints folder will potentially become crowded with the separate files for each block.

src/
  entrypoints/
    block-one-editor.js
    block-one-shared.js
    block-one-frontend.js
    block-two-editor.js
    block-two-shared.js
    block-two-frontend.js
    ...
    ...
    ...
    block-ten-editor.js
    block-ten-shared.js
    block-ten-frontend.js

This will also lead to the maintenance of the required checks around any defined asset constants used from asset-settings.php increasing in difficulty due to the amount of new entries for each of the blocks assets.

I propose that we look into modifying the build tools to also check for src/blocks/* folders or something similar and then generate the corresponding dist/blocks/* folders after a build or watch command.

A basic example of a folder structure of src/blocks would look something like;

src/
  blocks/
    sample-block/
      block.json
      edit.js
      editor.js        (`editorScript` asset)
      shared.js        (`script` asset)
      frontend.js      (`viewScript` asset)
      editor.scss      (`editorStyle` asset)
      shared.scss      (`style` asset)
      frontend.scss    (`viewStyle` asset)
      render.php       (`render` asset)

built to;

dist/
  blocks/
    sample-block/
      block.json
      editor.js        (`editorScript` asset)
      shared.js        (`script` asset)
      frontend.js      (`viewScript` asset)
      editor.scss      (`editorStyle` asset)
      shared.scss      (`style` asset)
      frontend.scss    (`viewStyle` asset)
      render.php       (`render` asset)

These folder structures would be duplicated for as many blocks as necessary.

Each blocks render.php and block.json files would be included in the src/blocks/* folders to avoid fragmenting the blocks files across locations. This makes it easier to maintain each block as the src/blocks/* folder becomes the source of truth for any block changes.

Usage

Depending on changes and with the new structure we could use block.json to handle assets in a couple of ways off the top of my head.

1. Using registered script/style handles in block.json

This would be similar to the way it potentially works now but with the different file/folder structure. Each blocks assets would need to be registered with wp_register_style or wp_register_script and each handle used with the corresponding block.json asset value.

The render value can use the file path directly as the render.php file would always have the same relative path in both the src and dist folders .e.g ./render.php.

2. Referencing the script/style filenames directly in block.json from dist/blocks/*

I believe this would require the most effort to implement in the build tools but would also require the least amount of work when registering a block.

Alongside handling the new file/folder structure we would need to also implement the below;

Without the need to use a registered handle for each blocks assets, the below should be enough to register the block and all required assets.

register_block_type( '../dist/blocks/sample-block/' );

With multiple blocks it should be possible to do something like the below and register them automatically, avoiding having to add each additional block manually.

$path_to_blocks = plugin_dir_path( __FILE__ ) . 'dist/blocks';
$blocks         = scandir( $path_to_blocks );

foreach ( $blocks as $block ) {
  if ( ! is_dir( $path_to_blocks . '/' . $block ) || str_contains( $block, '.' ) ) {
    continue;
  }

  register_block_type( $path_to_blocks . '/' . $block );
}

Notes

Relevant & Supporting Documentation

g-elwell commented 4 months ago

Thanks for sharing @chrishbite ! This issue would also be implemented by https://github.com/bigbite/build-tools/issues/117 which was added recently and is something we can hopefully explore sooner rather than later.

The additional context you've added here will also be relevant in discussions around how we approach that issue