Help to create a plugin library starting from plugins in a Single Page Tiddlywiki

You can use tiddlywiki itself as a plugin library without the need of nodejs or third party software. See a basic example here: https://tw-as-plugin-library.tiddlyhost.com/

Setup:

  • First you need a tiddler with the tag $:/tags/PluginLibrary and a field url set to the location of the html that contains the code for the plugin library (here, the tiddlywiki itself - more on that bellow)
  • Then you need a script that will serve the plugin files. In that case, this is the tiddlywiki itself. You can see the script by inspecting the source of the wiki: view-source:https://tw-as-plugin-library.tiddlyhost.com
  • This is done by using the tag $:/tags/RawMarkupWikified/TopHead on this tiddler.
  • The wiki need to be allowed to be loaded inside an iframe

Here’s the script :

<script>
var assetList = [{
    "title": "$:/plugins/Telumire/Animate",
    "name": "Animate",
    "description": "Make user interactions available for CSS animation",
    "author": "Telumire",
    "version": "0.0.2",
    "core-version": "5.2.8-prerelease",
    "source": "https://plm.tiddlyhost.com/#:[[$:/plugins/Telumire/Animate]]",
    "list": "readme settings",
    "plugin-type": "plugin",
}];

/*\
title: $:/plugins/tiddlywiki/pluginlibrary/libraryserver.js
type: application/javascript
module-type: library

A simple HTTP-over-window.postMessage implementation of a standard TiddlyWeb-compatible server. It uses real HTTP to load the individual tiddler JSON files.

\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

// Listen for window messages
window.addEventListener("message",function listener(event){
	console.log("plugin library: Received message from",event.origin);
	console.log("plugin library: Message content",event.data);
	switch(event.data.verb) {
		case "GET":
			if(event.data.url === "recipes/library/tiddlers.json") {
				// Route for recipes/library/tiddlers.json
				event.source.postMessage({
					verb: "GET-RESPONSE",
					status: "200",
					cookies: event.data.cookies,
					url: event.data.url,
					type: "application/json",
					body: JSON.stringify(assetList,null,4)
				},"*");
			} else if(event.data.url.indexOf("recipes/library/tiddlers/") === 0) {
				var url = encodeURIComponent(removePrefix(event.data.url,"recipes/library/tiddlers/"));
				// Route for recipes/library/tiddlers/<uri-encoded-tiddler-title>.json
				httpGet(url,function(err,responseText) {
					if(err) {
						event.source.postMessage({
							verb: "GET-RESPONSE",
							status: "404",
							cookies: event.data.cookies,
							url: event.data.url,
							type: "text/plain",
							body: "Not found"
						},"*");
					} else {
						event.source.postMessage({
							verb: "GET-RESPONSE",
							status: "200",
							cookies: event.data.cookies,
							url: event.data.url,
							type: "application/json",
							body: responseText
						},"*");
					}
				});
			} else {
				event.source.postMessage({
					verb: "GET-RESPONSE",
					status: "404",
					cookies: event.data.cookies,
					url: event.data.url,
					type: "text/plain",
					body: "Not found"
				},"*");
			}
			break;
	}
},false);

// Helper to remove string prefixes
function removePrefix(string,prefix) {
	if(string.indexOf(prefix) === 0) {
		return string.substr(prefix.length);
	} else {
		return string;
	}
}

// Helper for HTTP GET
function httpGet(url,callback) {
	var http = new XMLHttpRequest();
	http.open("GET",url,true);
	http.onreadystatechange = function() {
		if(http.readyState == 4 && http.status == 200) {
			callback(null,http.responseText);
		}
	};
	http.send();
}

})();

</script>

This script assume that the plugin is located next to the html file, with the name of the file matching the title of the plugin, uri-encoded : %24%3A%2Fplugins%2FTelumire%2FAnimate.json

Note: this particular example does not actually work because with this setup, the plugin files (.json) need to be next to the wiki (.html), and tiddlyhost only allow uploading a single file by wiki. If you use this setup on github page and put your plugins next to the html file, it should work fine. You could modify the route to allow for a different setup however. Since tiddlyhost has endpoints for tiddler in the json format, it could be possible to have a tiddlywiki acting as a both the library and the repository for the plugins, but I have not tested this.

I’d suggest to keep that wiki as light as possible since the html will be fetched when updating the plugins. See: How to reduce the size of your Tiddlywiki

You can use gatha to package the plugins in the plugin library. There is also a way to do it by using the import tiddler:

Here’s a more complete setup: plm.tiddlyhost.com/

I’m using gatha to package the plugins, then upload the plugin library with the file upload plugin. The resulting file is located here: Plugin Library. It sits next to the packaged plugins, also exported using the same method:

2 Likes