Using @wordpress
packages on the frontend
As part of the gutenberg project WordPress has gained much more than just the editor itself. The gutenberg repository currently houses more than 80 individual packages. These packages span everything from the actual react components, utilities to calculate word count, end-to-end test utilities and much more. Naturally there is the desire to also use some of these packages in the frontend code we are shipping. However, because there are many caveats when trying to use them on the frontend which is why it is generally not recommended to do so.
You can find a list of @wordpress/
packages that are the exception to this rule and that can be used in the Useful packages outside of the editor section.
Bundle size
One of the pitfalls of using the Dependency Extraction Webpack Plugin is that you don't see the size of the externalized WordPress packages. They are not a part of your bundle but instead get added as an additional script that gets loaded before yours. And these WordPress bundled scripts don't allow you to do any sort of tree shaking.
This is especially problematic because they often rely on individual functions from lodash
but therefore load all of lodash as a result. Which is a heavy import.
Speaking of lodash
one pitfall is, that the Dependency Extraction Webpack Plugin externalizes more than just the @wordpress/*
dependencies. It externalizes all these imports:
moment
@babel/runtime/regenerator
lodash
/lodash-es
jquery
react
react-dom
react-refresh/runtime
@wordpress/*
There are some @wordpress/
packages, like the @wordpress/icons
package, that are not bundled in WordPress and therefore don't get externalized. You can view the excluded list in the GitHub repo.
This means that even if any of your other frontend dependencies tries to load something from lodash the Dependency Extraction Webpack Plugin will pick that up and add lodash
to your dependency array.
Editor dependant packages
The @wordpress/packages
can also be divided into different groups. There are some that are dependant on being used in the editor. The entire @wordpress/block-editor
package for example should not be used outside of the editor because it depends on the surrounding architecture like the data api being setup correctly etc.
As a rule of thumb any package that includes editor in it's name should not be used outside of the editor.
Useful packages outside of the editor
There are some packages that suit themselves very well for being used outside of the editor. This list is not comprehensive and if something is not listed here it doesn't mean that it cannot be used on the frontend. These are just some good examples of packages that showed they work well on the frontend.
@wordpress/dom-ready
The @wordpress/dom-ready
package is a simple utility function that makes it super simple to only invoke a callback once the dom is loaded.
import domReady from '@wordpress/dom-ready';
domReady( function () {
//do something after DOM loads.
} );
If you look at the source code for the package it really is nothing more than an event listener for the DOMContentLoaded
event with additional checks for the document.readyState
complete
or interactive
.
@wordpress/i18n
Localizing strings within frontend js code always is a bit of a pain. Usually you would use wp_localize_script
in order to provide the localized strings as a variable. This gets rather difficult to manage though with plurals etc. Using the @wordpress/i18n
package to manage frontend translations can solve this by providing the developers with the same __
, _n
, _x
, etc. functions that they are used to from php.
Since we are not using the WordPress bundled version of the i18n
package we will manually need to load our script translations though like so:
/**
* Get the Translation strings used on Frontend JSs
* the load_script_textdomain function handles loading the correct json file for the the current locale
*
* Because we are bundling the i18n package in our theme we need to manually call `setLocaleData` on the frontend.
* `wp_set_script_translations` calls `wp.i18n.setLocaleData` which is not the same instance of `i18n` as the one we
* bundle in the theme.
*
* @see https://core.trac.wordpress.org/browser/tags/5.8/src/wp-includes/class.wp-scripts.php#L591
*/
$json_translations = load_script_textdomain( 'frontend', 'tenup-theme', TENUP_THEME_PATH . 'languages' );
if ( ! $json_translations ) {
// Register empty locale data object to ensure the domain still exists.
$json_translations = '{ "locale_data": { "messages": { "": {} } } }';
}
// Localize JS translations
wp_localize_script(
'frontend',
'tenupThemeFrontendTranslations',
json_decode( $json_translations, true )
);
import { setLocaleData } from '@wordpress/i18n';
/**
* setTranslationData
*
* use the data supplied via `wp_localize_script` to manually set the locale data for the `i18n` package
* This would normally happen automatically by using the `wp_set_script_translations` function in php but because
* we are no longer using the `i18n` package bundled in WordPress core we need to manually replicate this behavior.
*
* @see https://core.trac.wordpress.org/browser/tags/5.8/src/wp-includes/class.wp-scripts.php#L591
*
* @return {void}
*/
export function setTranslationData() {
if (!window.tenupThemeFrontendTranslations) {
return;
}
const domain = 'tenup-theme';
const translations = window.tenupThemeFrontendTranslations;
const localeData = translations.locale_data[domain] || translations.locale_data.messages;
localeData[''].domain = domain;
setLocaleData(localeData, domain);
}
@wordpress/html-entities
The @wordpress/html-entities
package is super useful when working with data from the WordPress REST API when you manually need to decode html entities because you may not want to use the rendered
value due to having to use innerHTML
or dangerouslySetInnerHTML
if you are using react.
import { decodeEntities } from '@wordpress/html-entities';
const result = decodeEntities( 'á' );
console.log( result ); // result will be "á"