Dynamic Core Module Reference in TiddlyWiki Plugins

Dynamic Core Module Reference in TiddlyWiki Plugins

The Problem

When overriding a core widget (e.g. text.js), you often need the original version as a sub-widget or fallback. The conventional approach is to maintain a separate copy of the original — but this breaks silently whenever core is upgraded.

The Solution

TiddlyWiki’s core is itself a plugin. All original module source code is preserved in $tw.wiki.getPluginInfo("$:/core").tiddlers, even after being overridden. You can retrieve that source at runtime and re-execute it under a new name.

(function() {
	var pluginInfo = $tw.wiki.getPluginInfo("$:/core");
	var shadowSource = pluginInfo.tiddlers["$:/core/modules/widgets/text.js"].text;

	var twRequire = function(title) {
		return $tw.modules.titles[title] && $tw.modules.titles[title].exports;
	};

	var coreExports = {};
	new Function("exports", "require", shadowSource)(coreExports, twRequire);

	// Register the original "text" widget under a new alias
	exports["plain-text"] = coreExports.text;
})();

Place this IIFE at the top of your overriding module. The original widget is now available as plain-text for internal use, while your custom logic is exported as text.

Why This Works

  • getPluginInfo("$:/core").tiddlers always contains the original shadow source, regardless of any overrides applied on top
  • new Function("exports", "require", source) re-executes the module in isolation, producing a fresh exports object
  • The result is registered into the widget system alongside your override — no separate file needed

Verified Output

// plain-text.js (emptied)   → exports: []
// text.js (override)        → exports: ["plain-text", "text"]  ✓

Advantages over Conventional Approaches

Approach Upgrade-safe? Self-contained?
Copy original into a separate file :cross_mark: Manual sync needed :white_check_mark:
Shadow override only :cross_mark: Loses original :white_check_mark:
Mod-Loader (boot-time patch) :white_check_mark: :cross_mark: Extra dependency
This approach (runtime re-execution) :white_check_mark: Always latest core :white_check_mark: Single file

Caveats

  • The lightweight twRequire shown above only resolves already-loaded modules. If the original module has deep require dependencies at execution time, you may need to extend it.
  • This relies on getPluginInfo being available at module load time, which is the case for all standard module-type: widget modules in TiddlyWiki 5.
  • This is not a silver bullet. If a future core upgrade significantly changes the internal structure or API of the original module, your override will still break — just as it would with a manually maintained copy. The real benefit is simply one less file to maintain, and the guarantee that you’re always executing the latest core source rather than a stale snapshot.

*Discovered while building the Freelinks plugin. Tested on TiddlyWiki v5.4.1-prerelease


2 Likes

TiddlyWiki has a Widget subclassing mechanism. This allows you to overwrite, extend or create a new widget, for your own code in a compatible way.

Typically we try to avoid to change any core function signature, for backwards compatibility reasons. If we need to add new functionality to visible core functions we usually add an obtions object at the end. You can see this structure a lot in the core code.