Skip to content

Frontend Plugin API

Where possible we reuse the API from the tools and libraries we are already using rather than defining our own.

Manifest

This uses the vite manifest format to define which files are part of the plugin.

It's a vite-specific JSON-structure designed to allow a backend to serve the asset files.

See https://vitejs.dev/guide/backend-integration#backend-integration for more info.

WARNING

Don't confuse this manifest with a PWA manifest.

Usually, if you were following the plugin development guide, this would be automatically be created for you by setting manifest: true. You can also create them manually, which could be useful for simple cases.

Here is a minimal example of a manually created manifest:

json
{
  "main.js": {
    "file": "assets/main.js",
    "isEntry": true,
    "css": [
      "assets/main.css"
    ]
  },
  "main.css": {
    "file": "assets/main.css"
  }
}

A few points:

  • put this in manifest.json or .vite/manifest.json relative to your frontend plugin root dir
  • the first entry marked isEntry: true will be used as the entry

These files will be served up by the backend at paths such as:

/api/plugins/assets/<plugin-name>/<path-to-asset>

e.g.:

/api/plugins/assets/my-plugin/assets/app.js

Entry point

Inside the entrypoint file it should export a default object with 3 optional fields:

js
export default {
  boot (context) {},
  setup () {},
  slots: {},
}

boot

This is a Quasar boot function, it is passed a context object with lots of useful things on it.

It's good for:

  • registering new routes
  • configuring libraries
  • configure theme colours
  • configuring anything about the vue app before it loads

See https://quasar.dev/quasar-cli-vite/boot-files/ for more about what you can do here.

setup

This is a vue setup() function. It's run when the app first boots.

This is where you can:

  • register app-wide composition hooks
  • any other configuration that needs an instantiated app instance to work

See https://vuejs.org/api/composition-api-setup for more about setup() functions.

slots

You can pass components to these to replace certain sections of the Karrot interface:

js
import SomeComponent from './SomeComponent.vue'
export default {
  slots: {
    about: SomeComponent,
    groupActivities: () => import('./MyAsyncComponent.vue'),
    groupWall: SomeComponent,
    sidenav: SomeComponent,
  }
}

You can register components for these slots:

  • about - the "about" modal dialog when you click "About Karrot" in the left sidenav
  • groupActivities - the main content on the group activities page
  • groupWall - the main content on the group wall page
  • sidenav - the whole left sidenav

Inside your component you can use <slot /> to choose where the original component content goes (or leave it out entirely):

vue
<template>
  <h1>This will appear above the original component</h1>
  <slot />
  <p>This will appear below the original component</p>
</template>

Or wrap it:

vue
<!-- This will put the original component in a red box -->
<template>
  <div class="example">
    <slot />
  </div>
</template>
<style scoped>
.example {
  border: 1px solid red;
}
</style>