Zum Inhalt springen

Momentan arbeite ich an einer Basis für Websites für Freiwillige Feuerwehren in Oberösterreich, die ich mit dem Static Site Generator Gridsome umsetzen möchte.

In unserem Feuerwehr-Management-System gibt es ein API mit dem aktuelle Informationen, wie Einsätze und Übungen, aus dem System abgerufen werden können. Man kann den Content vom REST API natürlich auch über die gridsome.server.js in die Website einbinden und im GraphQL zur Verfügung stellen:

// Server API makes it possible to hook into various parts of Gridsome
// on server-side and add custom data to the GraphQL data layer.
// Learn more: https://gridsome.org/docs/server-api/

// Changes here require a server restart.
// To restart press CTRL + C in terminal and run `gridsome develop`

const axios = require('axios')

module.exports = function (api) {
  api.loadSource(({ addCollection }) => {
    // Use the Data Store API here: https://gridsome.org/docs/data-store-api/

    const collection = addCollection('Event')
    const res = await axios.get('https://some.api.com/events')

    for (const event of res.data) {
        collection.addNode({
            ...event
        })
    }
  })

  api.createPages(({ createPage }) => {
    // Use the Pages API here: https://gridsome.org/docs/pages-api/
  })
}

Das hat jedoch folgende Nachteile:

  • Die gridsome.server.js kann sehr groß und unhandlich werden, vor allem wenn die Daten noch nachbearbeitet werden bevor sie in den Data Layer eingefügt werden.
  • Der Code kann für mehrere Websites nicht an einer einzigen Stelle gewartet werden.

Darum habe ich dann ein Plugin entwickelt um die Daten anzubinden. Mittlerweile habe ich bereits mehrere Plugins entwickelt, wie z.B. ein Source Plugin für RSS.

Hier erfährt ihr wie das funktioniert.

Das braucht ihr dafür:

  • Node.js
  • NPM oder Yarn
  • GitHub Account (kostenlos)
  • NPM Account (kostenlos, optional)

Schritt 1: Neues NPM Paket erzeugen

Ein Gridsome-Plugin ist immer ein NPM Package. Deshalb brauchen wir ein neues Verzeichnis mit einer package.json:

{
  "name": "star-trek-gridsome-plugin",
  "description": "> TODO: description",
  "version": "1.0.0-alpha.0",
  "author": "Christoph Hochstrasser <christoph@hochstrasser.io>",
  "homepage": "https://github.com/chh/gridsome-source-rss",
  "license": "MIT",
  "main": "index.js",
  "keywords": [
    "gridsome",
    "gridsome-plugin",
    "gridsome-source"
  ],
  "scripts": {
    "test": "echo \"Error: run tests from root\" && exit 1"
  },
  "dependencies": {
      "axios": "^0.20.0"
  }
}

Wichtig sind hier die Keywords "gridsome", "gridsome-plugin" und "gridsome-source" (wenn das Plugin Content hinzufügt), damit das Plugin unter https://gridsome.org/plugins/ gefunden wird.

Schritt 2: index.js

Als nächstes benötigen wir eine index.js im selben Verzeichnis wie die Datei package.json.

Hier werden wir eine Klasse deklarieren, welche die Plugin-Schnittstelle von Gridsome implementiert und vom Modul standardmäßig exportiert wird. Der Konstruktur erhält das Gridsome API und die Optionen (aus gridsome.config.js) als Argumente.

Starten wir mit der Klasse und etwas Demo-Code:

// index.js
class StarTrekGridsomePlugin {
    constructor(api, options) {
        api.afterBuild(() => {
            console.log("my-cool-gridsome-plugin", options)
        })
    }
}

module.exports = StarTrekGridsomePlugin

Der ganze Code sollte jetzt in ein Git Repository eingecheckt werden und danach auf GitHub veröffentlicht werden. Wie ihr ein NPM Paket veröffentlicht findet ihr hier.

Ich verwende während der Entwicklung yarn link, damit ich nicht ständig eine neue Version des NPM Pakets veröffentlichen muss.

Danach kann das Plugin als Abhängigkeit in der package.json des Gridsome-Projektes und in der gridsome.config.js eingebunden werden.

package.json:

{
    "dependencies": {"star-trek-gridsome-plugin": "1.0.0-alpha.0"
    }
}

gridsome.config.js:

module.exports = {
    plugins: [
        {
            use: 'star-trek-gridsome-plugin',
            options: {
                test: 'hello world',
            }
        }
    ]
}

Die Optionen aus options wird als zweites Argument an den Konstruktor der Plugin-Klasse übergeben.

Wenn ihr jetzt yarn run build oder npm run build ausführt, dann sollten in der Konsole irgendwo die Optionen, die an unser Plugin übergeben wurden, ausgegeben werden.

Schritt 3: Die Optionen für unser Plugin definieren

Mit der statischen Methode defaultOptions() können die verfügbaren Optionen und ihre Standardwerte angegeben werden. Dafür passen wir die Klasse etwas an:

// index.js
class StarTrekGridsomePlugin {
    static defaultOptions() {
        return {
            typeName: 'StarTrek',
        }
    }

    constructor(api, options) {
        api.afterBuild(() => {
            console.log("star-trek-gridsome-plugin", options)
        })
    }
}

module.exports = StarTrekGridsomePlugin

Somit hat das Plugin eine Option typeName, die in der gridsome.config.js gesetzt werden kann, aber den Standardwert StarTrek hat, wenn die Option nicht angegeben wurde.

// gridsome.config.js
module.exports = {
    plugins: [
        {
            use: 'my-cool-gridsome-plugin',
            options: {
                typeName: 'CustomType'
            }
        }
    ]
}

Schritt 4: Mit dem Data Store API neuen Content hinzufügen

Mit dem Data Store API kann Content zum Data Layer von Gridsome hinzugefügt werden, der dann mit GraphQL abgefragt werden kann.

Das Data Store API bekommen wir in dem wir api.loadSource() auf das Gridsome-API aufrufen:

// index.js
class StarTrekGridsomePlugin {
    static defaultOptions() {
        return {
            typeName: 'StarTrek',
        }
    }

    constructor(api, options) {
        api.loadSource(async (actions) => {
            // `actions` ist das Data Store API
        })
    }
}

module.exports = StarTrekGridsomePlugin

Über actions können wir jetzt eine neue Collection hinzufügen, in die wir mit addNode neue Objekte einfügen können. Wir verwenden hier auch die typeName Option, damit die Nutzenden des Plugins den Namen des GraphQL-Typs anpassen können:

api.loadSource(async (actions) => {
    const seasons = actions.addCollection({ typeName: `${options.typeName}Season` })

    seasons.addNode({
        id: 'tng-season-1',
        series: 'The Next Generation',
        season: 1,
        characters: [
            //
        ]
    })
})

Wir können natürlich auch einen API Endpoint verwenden, wie z.B. das Star Trek API:

api.loadSource(async (actions) => {
    const seasons = actions.addCollection({ typeName: `${options.typeName}Season` })

    const res = await axios.post('http://stapi.co/api/v1/rest/season/search', null, {
        params: {
            title: 'TNG'
        },
    })

    for (const season of res.data.seasons) {
        seasons.addNode({
            id: season.uid,
            ...season
        })
    }
})

Normalerweise setze ich in addNode nur die id (falls nicht bereits vorhanden) und übernehme alle Daten vom API. Das reicht normalerweise aus, weil in Gridsome nur die Daten zugänglich gemacht werden, die über GraphQL auch abgefragt wurden.

Bei komplexeren APIs kann auch über das Data Store API ein eigenes GraphQL Schema definiert werden.

Jetzt können wir folgende GraphQL Abfrage nutzen, um die Seasons von Star Trek: The Next Generation anzuzeigen:

query {
  allStarTrekSeason {
    edges {
      node {
        id
        title
        series {
          title
        }
        numberOfEpisodes
      }
    }
  }
}

Tipp: Markdown zu einer Node hinzufügen

Indem bei addNode eine internal Eigenschaft angegeben wird, kann der Inhalt als Markdown verarbeitet werden. Das ist jedoch ein internes API und kann sich jederzeit ändern.

collection.addNode({
    id: '1',
    internal: {
        content: 'Das ist **Markdown**.',
        mimeType: 'text/markdown',
        // Ich verwende hier eine eindeutige ID für die Node:
        origin: 'collection/1',
    }
})

Recap

In diesem Tutorial haben wir gemeinsam ein neues Gridsome Plugin geschrieben, das Daten von einem API abfragt, zum Data Store hinzufügt und die mit GraphQL abgefragt werden können.

Es gibt noch viele weitere Möglichkeiten für Gridsome-Plugins:

Nach oben springen

Wir achten auf deine Privatsphäre und nutzen Cookies nur um die Benutzererfahrung zu verbessern. Kein Tracking, versprochen. Datenschutz