Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the acf domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /home/evomark/public_html/wp-includes/functions.php on line 6121

Warning: Cannot modify header information - headers already sent by (output started at /home/evomark/public_html/wp-includes/functions.php:6121) in /home/evomark/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1896

Warning: Cannot modify header information - headers already sent by (output started at /home/evomark/public_html/wp-includes/functions.php:6121) in /home/evomark/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1896

Warning: Cannot modify header information - headers already sent by (output started at /home/evomark/public_html/wp-includes/functions.php:6121) in /home/evomark/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1896

Warning: Cannot modify header information - headers already sent by (output started at /home/evomark/public_html/wp-includes/functions.php:6121) in /home/evomark/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1896

Warning: Cannot modify header information - headers already sent by (output started at /home/evomark/public_html/wp-includes/functions.php:6121) in /home/evomark/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1896

Warning: Cannot modify header information - headers already sent by (output started at /home/evomark/public_html/wp-includes/functions.php:6121) in /home/evomark/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1896

Warning: Cannot modify header information - headers already sent by (output started at /home/evomark/public_html/wp-includes/functions.php:6121) in /home/evomark/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1896

Warning: Cannot modify header information - headers already sent by (output started at /home/evomark/public_html/wp-includes/functions.php:6121) in /home/evomark/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1896
{"id":497,"date":"2023-12-16T11:51:11","date_gmt":"2023-12-16T11:51:11","guid":{"rendered":"https:\/\/evomark.co.uk\/?page_id=497"},"modified":"2023-12-17T01:22:01","modified_gmt":"2023-12-17T01:22:01","slug":"vite-plugin-gutenberg-blocks","status":"publish","type":"page","link":"https:\/\/evomark.co.uk\/open-source-software\/vite-plugin-gutenberg-blocks\/","title":{"rendered":"Vite Plugin: Gutenberg Blocks"},"content":{"rendered":"\n

Gutenberg block development is still something of a work-in-progress for WordPress. Until recently, it required some major workarounds to develop more than one block to the plugin (we\u2019re told it\u2019s better now) and the tech-stack powering the whole enterprise is pretty ancient. In short, it feels like a strange no-man\u2019s-land between a proper development experience and cycling with stabilisers on.<\/p>\n\n\n\n

We thought we\u2019d give a Vite-powered development process a go with Gutenberg, and while there are a few limitations (no Hot Module Reloading), it\u2019s still a superior experience. For good measure, we even made a create-block script that makes adding new Gutenberg blocks to your plugin a breeze. Add in automatic block loading, and we\u2019re quite happy with what we\u2019ve got here.<\/p>\n\n\n\n

Installation<\/h2>\n\n\n\n

While something of a hybrid package (since it creates a PHP-based plugin in WordPress), we gave this one to NPM because it\u2019s mostly JavaScript-powered. There\u2019s a small amount of setup involved so let\u2019s get to the numbers:<\/p>\n\n\n\n

    \n
  1. Create a new folder in your wp-content\/plugins<\/code> folder to house your new block library<\/li>\n\n\n\n
  2. Initiate a new JavaScript package by running npm init -y<\/code> inside your new plugin folder<\/li>\n\n\n\n
  3. Install this package inside your new plugin folder (i.e. npm install -D vite-plugin-gutenberg-blocks<\/code><\/li>\n\n\n\n
  4. Run npx -p vite-plugin-gutenberg-blocks init<\/code> in your plugin folder to create a development<\/code> folder and a register-blocks.php<\/code> file<\/li>\n\n\n\n
  5. cd development<\/code><\/li>\n\n\n\n
  6. npm install<\/code> to install the required node dependencies<\/li>\n\n\n\n
  7. Now you can run npm run create<\/code> to start off the block creation script. Answer the questions and a new block will be created in your development<\/code> folder. You can add as many blocks as you like and they will be automatically loaded by WordPress once you\u2026<\/li>\n\n\n\n
  8. require_once 'register-blocks.php';<\/code> in your plugins entry PHP file.<\/li>\n<\/ol>\n\n\n\n

    From the development<\/code> folder you can now npm run dev<\/code> and npm run prod<\/code> to develop your Gutenberg blocks library with Vite.<\/p>\n\n\n\n

    Features<\/h2>\n\n\n\n
      \n
    • Automatic configuration of Vite<\/li>\n\n\n\n
    • Copies and creates required assets<\/li>\n\n\n\n
    • Externalised PostCSS stylesheet processing<\/li>\n\n\n\n
    • Supports PostCSS, SCSS and CSS stylesheets (.css or .scss)<\/li>\n\n\n\n
    • Watch mode for developing your block library<\/li>\n\n\n\n
    • Support for PHP-rendered blocks<\/li>\n<\/ul>\n\n\n\n

      Speaking of the last one there\u2026<\/p>\n\n\n\n

      Dynamic Blocks (PHP-rendered)<\/h2>\n\n\n\n

      Your average Gutenberg block is really just a fancy React mini-app that allows users to save HTML output into their post via the editor. When the output is delivered to the frontend, it\u2019s generally just static HTML with some settings from Gutenberg\u2019s editor. This works fine for elements like buttons, forms, galleries et al., but it\u2019s not so good for things that require dynamic content, like posts or other pieces of live data.<\/p>\n\n\n\n

      This is where Gutenberg\u2019s dynamic blocks come in. Essentially, you let JavaScript handle the backend editor stuff and then handover the actual rendering to good old PHP.<\/p>\n\n\n\n

      We won\u2019t go through the actual process of setting this up beyond what\u2019s related to this package:<\/p>\n\n\n\n

      In your blocks block.json<\/code> file, add either \"render\": \"file:.\/template.php\"<\/code> or \"render\": \"file:.\/render.php\"<\/code> to the JSON (the plugin will only look for one of these two filenames).<\/p>\n\n\n\n

      Create the PHP file in your block\u2019s development<\/code> folder. It will be automatically copied to your block\u2019s build folder along with the other build files.<\/p>\n\n\n\n

      Create Block Stubs<\/h2>\n\n\n\n

      Stubs are template files that are used when creating a new block from within your development environment. By default, the create<\/code> script will use stub files from inside the package. However, if you wish to override these with your own stub files, you can do so by placing one or more of them inside your development folder at the locations shown below:<\/p>\n\n\n\n

      \/<\/span> development<\/span><\/div>
      \t<\/span>\/<\/span> packages<\/span><\/div>
      \t<\/span>\/<\/span> stubs<\/span><\/div>
      \t\t<\/span>\/<\/span> src<\/span><\/div>
      \t\t\tblock<\/span>.<\/span>json<\/span>.<\/span>stub<\/span><\/span><\/div>
      \t\t\tedit<\/span>.<\/span>jsx<\/span>.<\/span>stub<\/span><\/span><\/div>
      \t\t\teditor<\/span>-<\/span>style<\/span>.<\/span>css<\/span>.<\/span>stub<\/span><\/span><\/div>
      \t\t\tindex<\/span>.<\/span>jsx<\/span>.<\/span>stub<\/span><\/span><\/div>
      \t\t\tsave<\/span>.<\/span>jsx<\/span>.<\/span>stub<\/span><\/span><\/div>
      \t\t\tstyle<\/span>.<\/span>css<\/span>.<\/span>stub<\/span><\/span><\/div>
      \t\t<\/span>package<\/span>.<\/span>json<\/span>.<\/span>stub<\/span><\/span><\/div>
      \t\tpostcss<\/span>.<\/span>config<\/span>.<\/span>js<\/span>.<\/span>stub<\/span><\/span><\/div>
      \t\tvite<\/span>.<\/span>config<\/span>.<\/span>js<\/span>.<\/span>stub<\/span><\/span><\/div>
      \tlerna<\/span>.<\/span>json<\/span><\/span><\/div>
      \t<\/span>package<\/span>.<\/span>json<\/span><\/div><\/code><\/pre><\/div>\n\n\n\n

      You can choose to publish these stub files to your development folder during the init<\/code> script, or at a later time by running:<\/p>\n\n\n\n

      npx -p vite-plugin-gutenberg-blocks publish<\/span><\/div><\/code><\/pre><\/div>\n\n\n\n

      Limitations<\/h2>\n\n\n\n

      As previously mentioned, this plugin doesn\u2019t currently support Vite\u2019s HMR (Hot Module Reloading) mode, so you\u2019ll have to manually reload the page whenever you make a change to your code. Wait until watch mode has finished rebuilding the block in response to your changes though.<\/p>\n\n\n\n

      Watchers run independently on each block, so once you start watch mode, a change to one block will only rebuild that one block, giving you a very quick development process.<\/p>\n\n\n\n

      Migration to Version 2.x<\/h2>\n\n\n\n

      Version 2 of vite-plugin-gutenberg-blocks<\/code> introduces support for Vite 5 and requires some changes to any existing packages in your project.<\/p>\n\n\n\n

      Upgrade NodeJS version<\/h3>\n\n\n\n

      Vite 5 drops support for Node versions 14.x, 16.x, 17.x and 19.x. Therefore make sure you’re running either version 18.x, 20.x or 21.x on your operating system.<\/p>\n\n\n\n

      Change package.json to a module<\/h3>\n\n\n\n

      Vite 5 drops support for CommonJS (or require<\/code>) syntax. Therefore, all Vite projects must be marked as module-type projects. To change this, in each<\/em> of your blocks, edit the package.json<\/code> file and add the following:<\/p>\n\n\n\n

      {<\/span><\/span><\/div>
      \t<\/span>\"type\"<\/span>:<\/span> <\/span>\"module\"<\/span><\/span><\/div>
      <\/span>}<\/span><\/div><\/code><\/pre><\/div>\n\n\n\n

      Change PostCSS config file to new ES6 modules format<\/h3>\n\n\n\n

      Changing to a module-type project means that, by default, ES6 exports are now expected from all .js files inside your project\/block. Therefore we need to tweak any PostCSS config files that were written in the old CommonJS module.exports<\/code> format to the following:<\/p>\n\n\n\n

      export<\/span> <\/span>default<\/span> <\/span>{<\/span><\/span><\/div>
      \t<\/span>plugins<\/span>:<\/span> <\/span>{<\/span><\/span><\/div>
      \t\t<\/span>\"postcss-nested\"<\/span>:<\/span> <\/span>{<\/span>}<\/span>,<\/span><\/span><\/div>
      \t\t<\/span>\"postcss-import\"<\/span>:<\/span> <\/span>{<\/span>}<\/span>,<\/span><\/span><\/div>
      \t\t<\/span>autoprefixer<\/span>:<\/span> <\/span>{<\/span>}<\/span>,<\/span><\/span><\/div>
      \t<\/span>}<\/span>,<\/span><\/span><\/div>
      <\/span>}<\/span>;<\/span><\/span><\/div>
      \n<\/span><\/div><\/code><\/pre><\/div>\n\n\n\n

      Relocated CreateBlock script (v2.1.0+)<\/h3>\n\n\n\n

      Previously, the “create” script for bootstrapping new blocks in your environment was copied to your development folder during the “init” script. This worked well, but made it impossible to make changes to the script for existing development environments. Therefore, we made the decision to move it inside the vite-plugin-gutenberg-blocks<\/code> package.<\/p>\n\n\n\n

      To change to using the new create script, inside your package.json<\/code> file in your existing development<\/code> folder and find the following line:<\/p>\n\n\n\n

      {<\/span><\/span><\/div>
      \t<\/span>\"scripts\"<\/span>:<\/span> <\/span>{<\/span><\/span><\/div>
      \t\t<\/span>\"create\"<\/span>:<\/span> <\/span>\"node .\/scripts\/create.mjs\"<\/span><\/span><\/div>
      \t<\/span>}<\/span><\/span><\/div>
      <\/span>}<\/span><\/div><\/code><\/pre><\/div>\n\n\n\n

      and change it to:<\/p>\n\n\n\n

      {<\/span><\/span><\/div>
      \t<\/span>\"scripts\"<\/span>:<\/span> <\/span>{<\/span><\/span><\/div>
      \t\t<\/span>\"create\"<\/span>:<\/span> <\/span>\"npx -p vite-plugin-gutenberg-blocks create\"<\/span><\/span><\/div>
      \t<\/span>}<\/span><\/span><\/div>
      <\/span>}<\/span><\/div><\/code><\/pre><\/div>\n\n\n\n

      Using default stubs with optional overrides<\/h3>\n\n\n\n

      Rather than publishing the createBlock template stubs during your init<\/code> function and relying on those, the default is now to use stubs defined inside the package unless there is an override file inside your development environment folder.<\/p>\n\n\n\n

      You will now be asked during the init<\/code> script whether or not you wish to publish the stubs.<\/p>\n\n\n\n

      If you change your mind later, you can use npx -p vite-plugin-gutenberg-blocks publish<\/code> to publish the stubs to your development environment.<\/p>\n\n\n\n

      For full instructions, see the section on “stubs” above.<\/p>\n\n\n\n

      What do you think?<\/h2>\n\n\n\n

      Any thoughts\/suggestions about this package can be posted on our GitHub repo<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"

      Gutenberg block development is still something of a work-in-progress for WordPress. Until recently, it required some major workarounds to develop more than one block to the plugin (we\u2019re told it\u2019s better now) and the tech-stack powering the whole enterprise is pretty ancient. In short, it feels like a strange no-man\u2019s-land between a proper development experience…<\/p>\n","protected":false},"author":2,"featured_media":503,"parent":218,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"templates\/open-source-software.php","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-497","page","type-page","status-publish","has-post-thumbnail","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/evomark.co.uk\/wp-json\/wp\/v2\/pages\/497","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/evomark.co.uk\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/evomark.co.uk\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/evomark.co.uk\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/evomark.co.uk\/wp-json\/wp\/v2\/comments?post=497"}],"version-history":[{"count":26,"href":"https:\/\/evomark.co.uk\/wp-json\/wp\/v2\/pages\/497\/revisions"}],"predecessor-version":[{"id":529,"href":"https:\/\/evomark.co.uk\/wp-json\/wp\/v2\/pages\/497\/revisions\/529"}],"up":[{"embeddable":true,"href":"https:\/\/evomark.co.uk\/wp-json\/wp\/v2\/pages\/218"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/evomark.co.uk\/wp-json\/wp\/v2\/media\/503"}],"wp:attachment":[{"href":"https:\/\/evomark.co.uk\/wp-json\/wp\/v2\/media?parent=497"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}