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

Dear all,

I would like to create and host a plugin library on Github.

I have a single page tiddlywki version that contains the plugins that I would like to include in this plugin library.

However I miss the steps to go from this single page to the plugin library.

I have understood that I would need to use node.js
I have setup a node.js environment and checked that I can create, serve and update a new empty TiddlyWiki node.js version.
I have a github repository with gitub webpages activated to host the library.

However, I do not know:

  • How to import the plugins in the node.js version from the single page version
    (I am not even sure if this step is required)
  • How to generate the plugin library

Could someone help me?

BR,

Eskha

It is straight forward but not trivial. We do need much better documentation here. I’ll have a look if I can put something together. The problem is, that I did set it up for my WikiLabs plugins a long time ago and let the build system do it. So I forgot, where the settings have to be made.

There are some settings that have to be different to the core settings. – Actually your build needs to exclude the core plugins. Otherwise you’d start to publish them too. …

If someone else is faster – do not hesitate, to post your workflow. Mine is optimized towards my personal preferences. So there should be several ways to achieve the goal and mine is probably not the best way to do it.

Once I did figure out what I did I’ll try to create a PR for the tiddlywiki.com/dev wiki.

Have fun!
Mario

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

Hello telumire,

Thank you for your detailed answer.

I have tried previously the plm way because I though it was a great idea and perfect use case for me but I was never able to succeed and has never seen it working.

For instance, if I grab the About tiddler from https://tw-as-plugin-library.tiddlyhost.com/ I can see the library when I go to the “Get more plugins” but the install buttons are not working.

I would also prefer to create the script with the assetList in an automatic way.
(however a $list widget, a template and a copy paste may help for this).

Packaging plugins is not an issue for me.
But I thank you for providing different solutions on this topic that are helpful for the community.

Lastly, due to the recent performance issues on tiddlyhost, at least under windows, I would rather have a second option and since all the plugins libraries I have seen are hosted on github, therefore my idea to go the same path.

I will see if pmario has an update.

Best regards,

Eskha

The tiddlywiki located on “https://tw-as-plugin-library.tiddlyhost.com” doesn’t work to install plugins because the script of the library expect the plugins to be located in the same directory (or folder), which can’t be done on tiddlyhost AFAIK. This can be done on github page however.

It’s an incomplete proof of concept, sorry for the confusion.

The tiddlywiki on “http://plm.tiddlyhost.com/” automatically generate and send tiddlers on github to solve this issue.

Ok, thanks for the clarification.
I will try again next week with http://plm.tiddlyhost.com/ and github.

With the help of ChatGPT, I developed a custom plugin library script that serves plugins from the wiki itself by utilizing Tiddlyhost’s JSON endpoints: https://plugin-library.tiddlyhost.com

The plugin list updates automatically.

To get started, simply clone the wiki, add your plugins, and enable the “Allow site to be loaded inside an iframe” option in the advanced settings:

image

I opened another thread to discuss this approach here: Using a tiddlywiki hosted on tiddlyhost as a plugin library

For an alternative method using GitHub Pages, the PLM setup should work fine.

3 Likes

Thank you telumire.

Your solution is working perfectly.
This is really a game changer!

I now have a working library that will help me upkeep my different wiki as well as distributing more frequent plugin update.
https://delphes-notes-plugins-library.tiddlyhost.com/

I have just noticed a minor issue, library icons are not displayed when selecting get more plugins.

BR,

Eskha

I fixed the issue with the library icons, you can copy/paste this into the assetList tiddler (be careful to adjust the filter in the list widget, I changed the prefix I use)

\define fields() title name description parent-plugin dependents stability version plugin-type requires-reload
\procedure asset()
<$wikify name="image" text={{{ [{!!title}addsuffix[/icon]get[text]] }}}  mode="inline" output="html">
<$let
  type={{!!type}}
  uri={{!!_canonical_uri}}
  external=`$(uri)$`
  base64=`data:${[{!!type}]}$;base64,$(image)$`
  svg=`data:image/svg+xml;utf8,<svg width="22pt" height="22pt" xmlns="http://www.w3.org/2000/svg">${[<image>get[text]else<image>search-replace:g[#],[%23]search-replace:g[
],[]]}$</svg>`
  icon={{{  [<uri>!is[blank]then<external>]~[<image>search[svg]then<svg>]~[<base64>] :filter[<..currentTiddler>addsuffix[/icon]get[title]] }}}
  readme={{{ [{!!title}addsuffix[/readme]get[text]] }}}
>
<$genesis 
  $type="$jsontiddler"
  tiddler={{!!title}}
  exclude={{{ [{!!title}fields:exclude<fields>format:titlelist[]join[ ]] }}}
  $names="
  =[<readme>!is[blank]then[$readme]]
  =[<icon>!is[blank]then[$icon]]
  "
$values="
  =[<readme>!is[blank]]
  =[<icon>!is[blank]]
"/>
</$let>
</$wikify>
\end
<$list filter={{$:/plugins/theophile.dev/tiddlyhostpluginlibrary/assetList!!filter}} join=","><<asset>></$list>