Skip to content

Converting jsPsych 5 plugins to jsPsych 7

First, look at the documentation for plugin development for jsPsych 7.

https://www.jspsych.org/7.3/developers/plugin-development/#constructor

Plugin definition file

jsPsych 5

Notice that it adds an object with info and a trial() field to the global jsPsych.plugins object using an IIFE to avoid polluting the global namespace.

const MapTask = require("./maptask");

jsPsych.plugins["pcllab-africa-map-task"] = (function () {
  let plugin = {};

  plugin.info = {
    name: "pcllab-africa-map-task",
    parameters: {},
  };

  plugin.trial = function (display_element, trial) {
    trial = jsPsych.pluginAPI.evaluateFunctionParameters(trial);

    const maptask = new MapTask(display_element, trial);
    maptask.start();
  };

  return plugin;
})();

You use it by specifiying the key on jsPsych.plugins.

experiment.js
const trial = {
  type: "pcllab-africa-map-task",
  // etc...
};

jsPsych 7

The plugin is now a class with a trial() method. jsPsych is no longer a global variable, but a private variable passed to each plugin through its constructor.

An info object defines all available parameters and their default values. jsPsych will automatically assign default values based on this object. This is done instead of running jsPsych.pluginAPI.evaluateFunctionParameters(trial) or some custom setParameter() that sets default values.

It's also Typescript, because importing a Javascript plugin in a Typescript project (experiment) will show a typedef not found warning unless you want to manually create typedefs.

import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from "jspsych";
import MapTask from "./MapTask";

const info = {
  name: "pcllab-africa-map-task",
  parameters: {
    /**
     * Stimuli array
     */
    stimuli: {
      type: ParameterType.COMPLEX,
      pretty_name: "Stimulus",
      default: [],
      array: true,
    },
    // etc...
  },
};

type Info = typeof info;

class AfricaMapTaskPlugin implements JsPsychPlugin<Info> {
  static info = info;

  private jsPsych: JsPsych;

  constructor(private j: JsPsych) {
    this.jsPsych = j;
  }

  trial(display_element: HTMLElement, trial: TrialType<Info>) {
    const mapTask = new MapTask(display_element, trial, this.jsPsych);
    mapTask.start();
  }
}

export default AfricaMapTaskPlugin;

You use it by importing the class and specifying the type.

experiment.js
import pcllabAfricaMapTask from "@pcllab/plugin-africa-map-task";

const trial = {
  type: pcllabAfricaMapTask,
  // etc...
};

Migration Issues

  • jsPsych is no longer a global variable, so you have to pass it to where it's used.
  • Api changes. For example, jsPsych.pluginAPI.evaluateFunctionParameters is no longer part of the public api.
  • Broken dependencies. For example, while upgrading pcllab-core, I had to patch custom-event, a deprecated library used by dragula, another deprecated library. pnpm patch is your friend here.