Documentation / Plugins
Sitespeed.io uses a plugin architecture. This architecture allows you to add/remove/create your own plugins that can run additional tests on URLs or do other things with the result, like store it to a database.
The most basic things you can do is list configured plugins (which are currently used), disable one of the default plugin, or add/enable more plugins.
You can list the plugins that will be used when you do a run:
docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io sitespeedio/sitespeed.io --plugins.list https://en.wikipedia.org/wiki/Barack_Obama
And you will get a log entry that looks something like this:
...
The following plugins are enabled: assets,browsertime,coach,domains,html,screenshot
...
The default plugins lives in the plugin folder. This is a good starting place to look at if you wanna build your own plugin.
You can remove/disable default plugins if needed. For instance you may not want to output HTML and strictly send the data to Graphite.
docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io sitespeedio/sitespeed.io https://www.sitespeed.io --plugins.remove html
If you want to disable multiple plugins say you don’t need the html or screenshots:
docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io sitespeedio/sitespeed.io https://www.sitespeed.io --plugins.remove html screenshot
At anytime if you want to verify that disabling worked, add the plugins.list to your command:
docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io sitespeedio/sitespeed.io https://www.sitespeed.io --plugins.remove html screenshot --plugins.list
You can also add a plugin. This is great if you have plugins you created yourself, plugins others have created, or plugins that are not enabled by default.
There’s a plugin bundled with sitespeed.io called analysisstorer plugin that isn’t enabled by default. It stores the original JSON data from all analyzers (from Browsertime, Coach data, WebPageTest etc) to disk. You can enable this plugin like so:
docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io sitespeedio/sitespeed.io https://www.sitespeed.io --plugins.add analysisstorer
If you want to run plugins that you created yourself or that are shared from others, you can either install the plugin using npm (locally) and load it by name or point out the directory where the plugin lives.
If you run in Docker and you should. You will need to mount your plugin directory as a volume. This is the recommended best practice. Practically you should clone your repo on your server and then mount it like this.
docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io sitespeedio/sitespeed.io -b firefox --plugins.add /sitespeed.io/myplugin -n 1 https://www.sitespeed.io/
If you are running outside of Docker you can load it relative locally.
sitespeed.io https://www.sitespeed.io --plugins.add ../my/super/plugin
If you want to create an image of sitespeed.io with your plugins pre-baked for sharing you can also do so using the following Dockerfile.
FROM sitespeedio/sitespeed.io:<insert version here>
COPY <path to your plugin> /my-custom-plugin
Then build the docker image
docker build -t my-custom-sitespeedio ./plugins
Finally you can run it the same way as mentioned above without the volume mount.
docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io my-custom-sitespeedio firefox --plugins.add /my-custom-plugin --my-custom-plugin.option test -n 1 https://www.sitespeed.io/
Pretty cool, huh? :-)
First let us know about your cool plugin! Then share it with others by publish it to npm or just use Github.
Your plugin needs to follow this structure.
const path = require('path');
module.exports = {
name() {
// This is ... shocking news: the name of the plugin
return path.basename(__dirname);
},
open(context, options) {
// when sitespeed.io start it calls the open function once for all plugins
// the context holds information for this specific run that
// generated at runtime, for example you can get hold of the storageManager
// that stores files to disk.
// The options is the configuration supplied for the run.
},
processMessage(message, queue) {
// The plugin will get all messages sent through the queue
// and can act on specific messages by type:
// message.type
},
close(options, errors) {
// When all URLs are finished all plugins close function is called once.
// Options are the configuration options and errors a array of errors
// from the run.
}
};
This is the name of your plugin. You can use the name when you want to target specific options to your plugin. If you’re plugin name is browsertime you can make sure all your options start with that name.
The open function is called once when sitespeed.io starts, it’s in this function you can initialise whatever you need within your plugin. You will get the context and the options.
The context holds information for this specific run that generated at runtime and looks like this:
{
storageManager, // The storage manager is what you use to store data to disk
resultUrls,
timestamp, // The timestamp of when you started the run
budget, // If you run with budget, the result will be here
name, // The name of the run (the start URL )
intel, // The log system that is used within sitespeed.io https://github.com/seanmonstar/intel
messageMaker, // Help methods to send messages in the queue,
statsHelpers, // Help methods to collect data per domain/tests instead of per URL
filterRegistry // Register metrics that will be sent to Graphite/InfluxDB
}
You can checkout the StorageManager, messageMaker, statsHelpers and filterRegistry to get feel how you can use them.
The options are the options that a user will supply in the CLI, checkout the CLI implementation to see all the options.
The processMessage function in your plugin is called for each and every message that is passed in the application. So what’s a message you may ask? Everything is a message in sitespeed.io.:) A message contains the following information:
When you start the application and feed it with URLs, each URL will generate a message of type URL and will be sent to all configured plugins.
If you want to catch it, you can do something like this:
switch (message.type) {
case 'url':
{
// do some analyse on the URL
}
When you are finished analysing the URL, your plugin can then send a message with the result, so other plugins can use it.
Here’s a snippet of Browsertime sending the screenshots message (the actual screenshot is in results.screenshots):
const messageMaker = context.messageMaker;
...
queue.postMessage(make('browsertime.screenshot', results.screenshots, {
url,
group
}));
If you want to send messages from within your plugin, you get it from the context.
const messageMaker = context.messageMaker;
When all URLs have been analysed, the close function is called once for each plugin. The idea with the close function is to close down assets that your plugin created. Normally the close function is nothing you need to implement.
There are a couple of pre defined messages that will always passed around in the queue.
Plugins also pass on message to each other. The HTML plugin also sends a html.finished message when the HTML is written to disk. The S3 plugin listens for that message and when it gets it it uploads the files and then sends a s3.finished message. And then the Slack plugin listens on s3.finished messages and then sends a Slack message.
Since 6.0 your plugin can generate HTML. You can either generate HTML per run or per page. The first thing you need to do is to report your PUG file to the HTML plugin. You do that by sending a message to the HTML plugin.
You start by listening to the generic setup message sitespeedio.setup. When you get that, you should send your pug file with a message called html.pug. That message needs to have four fields:
Sending a pug looks something like this:
case 'sitespeedio.setup': {
queue.postMessage(
make('html.pug', {
id: 'gpsi',
name: 'GPSI',
pug: this.pug,
type: 'pageSummary'
})
);
break;
}
The HTML plugin will then listen to metrics sent with the type of the id and type, in this case gpsi.pageSummary.
The HTML plugin will automatically pickup data sent with the types of *.run and *.pageSummary. All these needs to have the URL so that it can be mapped to the right place.
A message can look like this (the HTML plugin will pickup messages sent by combining the id + type):
queue.postMessage(
make('gpsi.pageSummary', result, {
url,
group
})
);
You can look at the standalone GPSI plugin or the WebPageTest plugin as an example plugin that both sends run and pageSummary data.
One new feature in 6.0 is that your plugin can tell Browsertime to run JavaScript on the page you test to collect metrics.
You do that by in the setup phase, send the JavaScript you want to run to sitespeed.io
case 'sitespeedio.setup': {
queue.postMessage(
make('browsertime.scripts', {
category: 'yourplugin',
scripts: {
userAgent: '(function() {return navigator.userAgent;})();',
title: '(function() {return document.title;})();'
}
})
)
break;
}
You can then get the metrics back by listening on browsertime.run messages.
case 'browsertime.run': {
console.log(message.data.yourplugin);
break;
}
And if you want to use it in your pug template you will find it under pageInfo.data.browsertime.run.yourplugin. In this example, if you want to print the title you can do like this.
#{pageInfo.data.browsertime.run.yourplugin.title}
If your plugin lives on Github you should check out our example Travis-ci file for the GPSI plugin. In the example, we checkout the sitespeed.io project and run the plugin against the latest master (we also run it daily in the Travis crontab).
We keep a list of plugins at https://github.com/sitespeedio/plugins. If you wanna add your plugin, send a PR!
There’s no way for a plugin to tell the CLI about what type of configuration/options that are needed, but there’s an issue for that. Help us out if you have ideas!