Using Svelte in WordPress Plugins

Svelte is a relative newcomer to the JavaScript framework ecosystem. It’s incredibly fast to develop in, has great developer ergonomics, and allows you to move very quickly from thought to product. We’re currently in the process of developing a new WordPress plugin, and we’ve been able to integrate Svelte into our admin experience and wanted to share how we managed to do it.

Screenshot of the Kernl WP Site Performance Monitor WordPress plugin.
WP Site Performance Monitor

How does it work?

WordPress plugins all start out as a basic PHP file. What you do from there is entirely up to you. For our use case, we decided to follow this approach:

  1. Register any REST API routes that we need.
  2. Create a Svelte project using Snowpack
  3. Use Webpack to generate our production bundles
  4. Register the Webpack generated scripts with wp_enqueu_*
  5. Develop

If you aren’t familiar with the JS development ecosystem there are a few terms here you might not have heard of.

  • Snowpack – A lightning-fast frontend build tool, designed for the modern web. It’s extremely easy to get setup with a nice Svelte environment.
  • Webpack – Javascript module bundler and build tool. We will use this to compress our production files.
Snowpack site screenshot
Snowpack

Setting up your plugin

To get started, create a directory in your plugin called js or app. Something that will differentiate it from the rest of your PHP files. After that, you’ll need to make sure you have Node.js installed. For managing multiple versions of Node.js, Node Version Manager (NVM) is a great tool and really simplifies the whole process.

Once you have the basic tooling in place, you can create your Svelte project skeleton using Snowpack

npx create-snowpack-app my-app --template @snowpack/app-template-minimal

Once that process completes, you can run your Svelte project to see if it works.

cd my-app
npm run start

The start command should automatically start your new Svelte project and open a browser.

Welcome to Snowpack screenshot.
Hello world!

One final piece of configuration that we need to do is install and configure Webpack. First install @snowpack/plugin-webpack.

npm install --save @snowpack/plugin-webpack

and finally update your snowpack.config.js file. Under the plugins property

plugins: [
    ... // Snip
    [
      '@snowpack/plugin-webpack',
      {
        extendConfig: config => {
          config.plugins.push(
            new webpack.optimize.LimitChunkCountPlugin({
              maxChunks: 1
            })
          );
          return config;
        }
      }
    ]
  ],

Integrating Svelte into your WordPress Plugin

Now that we have an extremely basic Svelte application, we need to integrate this into your application. The first thing we do is enqueue our Javascript and CSS into WordPress. For our example, we’re making an admin plugin. For CSS:

$cssDir = plugin_dir_path( __FILE__ ) . 'js/build/css';
$cssFiles = scandir($cssDir);
foreach($cssFiles as $file) {
    if (preg_match('/(commons\..+\.css)/i', $file, $m)) {
        wp_enqueue_style(
            $this->plugin_name,
            plugin_dir_url( __FILE__ ) . "js/build/css/{$file}",
            array($this->plugin_name . '-bootstrap'),
            $this->version,
            'all'
        );
    }
}

And for our Javascript files:

$webpackRuntime = null;
$commons = null;
$index = null;

// Find all the webpack bundle files.
$jsDir = plugin_dir_path( __FILE__ ) . 'js/build/js';
$jsFiles = scandir($jsDir);
foreach($jsFiles as $file) {
    if (strpos($file, 'LICENSE') === false) {
        if (preg_match('/webpack-runtime\..+\.js$/i', $file, $m)) {
            $webpackRuntime = $file;
        }

        if (preg_match('/commons\..+\.js$/i', $file, $m)) {
            $commons = $file;
        }

        if (preg_match('/^index\..+\.js$/i', $file, $m)) {
            $index = $file;
        }
    }
}

// Enqueue the webpack scripts
wp_enqueue_script(
    "{$this->plugin_name}-webpack-runtime",
    plugin_dir_url( __FILE__ ) . "js/build/js/{$webpackRuntime}",
    array(),
    $this->version,
    true
);
wp_enqueue_script(
    "{$this->plugin_name}-commons",
    plugin_dir_url( __FILE__ ) . "js/build/js/{$commons}",
    array(
        "{$this->plugin_name}-webpack-runtime",
    ),
    $this->version,
    true
);
wp_enqueue_script(
    "{$this->plugin_name}-index",
    plugin_dir_url( __FILE__ ) . "js/build/js/{$index}",
    array(
        "{$this->plugin_name}-webpack-runtime",
        "{$this->plugin_name}-commons"
    ),
    $this->version,
    true
);

Some of this code is specific to the way this particular plugin was developed, but in general we do following

  1. Find the path to all of the files that Webpack generates.
  2. Enqueue them in the correct order.

This also highlights why in the Snowpack config we set the max_chunk_size to 1. If we hadn’t done that if would be very difficult to figure out what chunks to include where.

Bootstrapping the Svelte Application in WordPress.

The final step in getting Svelte into WordPress is figuring out the bootstrapping process. As part of the script enqueuing that happens above, the index.js file from your Svelte app is included. Here’s what ours looks like:

import Settings from "./settings/Settings.svelte";
import Dashboard from "./dashboard/Dashboard.svelte";

let app;
let topLevelEl = document.getElementById("kernl-spm-top-level");
if (topLevelEl) {
  app = new Dashboard({ target: topLevelEl });
}

let settingsEl = document.getElementById("kernl-spm-settings-container");
if (settingsEl) {
  app = new Settings({ target: settingsEl });
}

export default app;

Two similar things are happening above. For any given page where these scripts are included, we look for a specific element. If the element is found, we start the Svelte app (component) for that element. In that way we can control what Svelte app is started on what page.

If you want to see the full source code for our plugin, head over to GitHub.

Conclusions

The initial process of getting Svelte bootstrapped into WordPress was a little tedious, but the payoff is huge. Once Svelte is into WordPress you can develop your user interface at an incredibly fast pace and easily leverage Svelte’s growing ecosystem.