Posted in Javascript

While playing around with Frontity (a react framework for WordPress) I noticed the compiled bundle size for the default Mars theme was pretty huge clocking in at an unacceptable 390KB of JavaScript. That’s a lot to download before my site will appear. Below I detail how I knocked over 100KB off that size with no discernible difference in functionality simply by swapping out React with its lightweight drop in replacement Preact.

Extending WebPack

To replace React we need to modify Frontity’s webpack configuration. At the time of writing it’s not documented how to do that however a forum post by SantosGuillamot contains a link to a CodeSandbox showing how to do it.

In your root folder’s package.json add the following dependencies:

1
2
3
4
5
6
"dependencies": {
	...
	"change-config": "./packages/change-config",
	"preact": "^10.5.14",
	"preact-render-to-string": "^5.1.19"
}

Create the following files:

  1. /packages/change-config/package.json
  2. /packages/change-config/frontity.config.js

Here’s the contents of package.json:

1
2
3
4
5
6
7
8
9
10
11
{
  "name": "change-config",
  "version": "1.0.0",
  "description": "Frontity package created using the Frontity CLI.",
  "keywords": [
    "frontity",
    "frontity-theme"
  ],
  "license": "Apache-2.0",
  "dependencies": {}
}

And here is frontity.config.js:

1
2
3
4
5
6
export const webpack = ({ config, mode }) => {
    config.resolve.alias["react"] = "preact/compat";
    config.resolve.alias["react-dom/test-utils"] = "preact/test-utils";
    config.resolve.alias["react-dom"] = "preact/compat";
    config.resolve.alias["react/jsx-runtime"] = "preact/jsx-runtime";
};

Now back in your root folder open frontity.settings.js and set the following at the end of the packages section:

1
2
3
4
5
6
7
8
const settings = {
  ...
  "packages": [
    ...,
    "@frontity/tiny-router",
    "@frontity/html2react",
    "change-config"
  ]

That should be it. Run

1
2
npx frontity build
npx frontity serve

Here are the before and after filesizes:

Before:

Frontity base Mars theme bundle size

After:

Frontity Mars theme bundle size with React replaced with Preact

A saving of 110KB! Not too shabby.

Read More »

Posted in Javascript

Custom button added to Gutenberg top panel

Gutenberg may be the shiny new toy available for WordPress admin but it still feels very limiting at times – especially when trying to do things the developers don’t anticipate. I wanted to add an extra button at the top of the post edit page next to the Publish button before finding out there is no SlotFill for this but once again, React has us covered with a handy little helper createPortal. createPortal allows you to place a component anywhere in the DOM of your choosing – perfect for what I wanted to do here.

The Component

Without further adieu, component code below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/**
 * WordPress dependencies
 */
import { Button } from '@wordpress/components';
import { compose } from '@wordpress/compose';
import { createPortal, useEffect, useState } from '@wordpress/element';
import { withSelect } from '@wordpress/data';
 
const TopBtn = ( { postPreviewButton } ) => {
	// Empty div element our button will be placed into
	// This div will be inserted before the Publish button with useEffect()
	const [ container ] = useState( document.createElement( 'div' ) );
 
	// The button submit handler
	const onSubmit = () => {
		console.log( 'Button pressed!' );
	};
 
	// Do the actual placing/removing of the button in the DOM
	useEffect( () => {
		// Ensure we have a Preview button to place next to
		if ( ! postPreviewButton ) {
			return;
		}
 
		// Insert our button immediately after the post preview button.
		postPreviewButton.parentNode.insertBefore(
			container,
			postPreviewButton.nextSibling
		);
		// Remove our button on component unload
		return () => {
			postPreviewButton.parentNode.removeChild( container );
		};
	}, [ postPreviewButton ] );
 
	// Use createPortal to place our component into the <div/> container
	return createPortal(
		<>
			<Button
				isSecondary
				showTooltip={ true }
				label="My Custom Button"
				onClick={ onSubmit }
			>
				My Btn
			</Button>
			<span>&nbsp;</span>
		</>,
		container
	);
};
 
export default compose( [
	withSelect( () => {
		return {
			// Provide the Post preview button element so we'll know where to
			// place our component
			postPreviewButton: document.querySelector( '.editor-post-preview' ),
		};
	} ),
] )( TopBtn );

This setup is quite flexible allowing you to add components pretty much anywhere on the page you like. I’ve commented the component as best I could. If you have any questions feel free to ask in the comments section below.

Read More »