1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-11-27 03:57:21 +00:00

Tighten terminology for plugins vs. modules

"Plugins" are bundles of tiddlers managed as one, "modules" are
JavaScript tiddlers with a module type identifying when and how they
should be executed.
This commit is contained in:
Jeremy Ruston 2012-08-03 15:09:48 +01:00
parent c11743088a
commit daff9c10f3
17 changed files with 100 additions and 103 deletions

View File

@ -3,7 +3,7 @@ title: $:/core/boot.js
type: application/javascript
The main boot kernel for TiddlyWiki. This single file creates a barebones TW environment that is just
sufficient to bootstrap the plugins containing the main logic of the applicaiton.
sufficient to bootstrap the modules containing the main logic of the applicaiton.
On the server this file is executed directly to boot TiddlyWiki. In the browser, this file is packed
into a single HTML file along with other elements:
@ -63,10 +63,7 @@ if(!$tw.browser) {
// Modules store registers all the modules the system has seen
$tw.modules = $tw.modules || {};
$tw.modules.titles = $tw.modules.titles || {}; // hashmap by module title of {fn:, exports:, moduleType:}
// Plugins store organises module exports by module type
$tw.plugins = $tw.plugins || {};
$tw.plugins.moduleTypes = $tw.plugins.moduleTypes || {}; // hashmap by module type of array of exports
$tw.modules.types = $tw.modules.types || {}; // hashmap by module type of array of exports
// Config object
$tw.config = $tw.config || {};
@ -228,50 +225,50 @@ $tw.utils.resolvePath = function(sourcepath,rootpath) {
}
};
/////////////////////////// Plugin mechanism
/////////////////////////// Module mechanism
/*
Register a single plugin module in the $tw.plugins.moduleTypes hashmap
Register a single module in the $tw.modules.types hashmap
*/
$tw.plugins.registerPlugin = function(name,moduleType,moduleExports) {
if(!(moduleType in $tw.plugins.moduleTypes)) {
$tw.plugins.moduleTypes[moduleType] = [];
$tw.modules.registerTypedModule = function(name,moduleType,moduleExports) {
if(!(moduleType in $tw.modules.types)) {
$tw.modules.types[moduleType] = [];
}
$tw.plugins.moduleTypes[moduleType].push(moduleExports);
$tw.modules.types[moduleType].push(moduleExports);
};
/*
Register all plugin module tiddlers
Register all the module tiddlers that have a module type
*/
$tw.plugins.registerPluginModules = function() {
$tw.modules.registerTypedModules = function() {
for(var title in $tw.wiki.tiddlers) {
var tiddler = $tw.wiki.getTiddler(title);
if(tiddler.fields.type === "application/javascript" && tiddler.fields["module-type"] !== undefined) {
$tw.plugins.registerPlugin(title,tiddler.fields["module-type"],$tw.modules.execute(title));
$tw.modules.registerTypedModule(title,tiddler.fields["module-type"],$tw.modules.execute(title));
}
}
};
/*
Get all the plugins of a particular type in a hashmap by their `name` field
Get all the modules of a particular type in a hashmap by their `name` field
*/
$tw.plugins.getPluginsByTypeAsHashmap = function(moduleType,nameField) {
$tw.modules.getModulesByTypeAsHashmap = function(moduleType,nameField) {
nameField = nameField || "name";
var plugins = $tw.plugins.moduleTypes[moduleType],
var modules = $tw.modules.types[moduleType],
results = {};
if(plugins) {
for(var t=0; t<plugins.length; t++) {
results[plugins[t][nameField]] = plugins[t];
if(modules) {
for(var t=0; t<modules.length; t++) {
results[modules[t][nameField]] = modules[t];
}
}
return results;
};
/*
Apply the exports of the plugin modules of a particular type to a target object
Apply the exports of the modules of a particular type to a target object
*/
$tw.plugins.applyMethods = function(moduleType,object) {
var modules = $tw.plugins.moduleTypes[moduleType],
$tw.modules.applyMethods = function(moduleType,object) {
var modules = $tw.modules.types[moduleType],
n,m,f;
if(modules) {
for(n=0; n<modules.length; n++) {
@ -300,10 +297,10 @@ $tw.Tiddler = function(/* [fields,] fields */) {
delete this.fields[t]; // If we get a field that's undefined, delete any previous field value
}
} else {
// Parse the field with the associated plugin (if any)
var fieldPlugin = $tw.Tiddler.fieldPlugins[t];
if(fieldPlugin) {
this.fields[t] = fieldPlugin.parse.call(this,src[t]);
// Parse the field with the associated field module (if any)
var fieldModule = $tw.Tiddler.fieldModules[t];
if(fieldModule) {
this.fields[t] = fieldModule.parse.call(this,src[t]);
} else {
this.fields[t] = src[t];
}
@ -313,24 +310,24 @@ $tw.Tiddler = function(/* [fields,] fields */) {
};
/*
Hashmap of field plugins by plugin name
Hashmap of field modules by field name
*/
$tw.Tiddler.fieldPlugins = {};
$tw.Tiddler.fieldModules = {};
/*
Register and install the built in tiddler field plugins
Register and install the built in tiddler field modules
*/
$tw.plugins.registerPlugin($tw.config.root + "/kernel/tiddlerfields/modified","tiddlerfield",{
$tw.modules.registerTypedModule($tw.config.root + "/kernel/tiddlerfields/modified","tiddlerfield",{
name: "modified",
parse: $tw.utils.parseDate,
stringify: $tw.utils.stringifyDate
});
$tw.plugins.registerPlugin($tw.config.root + "/kernel/tiddlerfields/created","tiddlerfield",{
$tw.modules.registerTypedModule($tw.config.root + "/kernel/tiddlerfields/created","tiddlerfield",{
name: "created",
parse: $tw.utils.parseDate,
stringify: $tw.utils.stringifyDate
});
$tw.plugins.registerPlugin($tw.config.root + "/kernel/tiddlerfields/tags","tiddlerfield",{
$tw.modules.registerTypedModule($tw.config.root + "/kernel/tiddlerfields/tags","tiddlerfield",{
name: "tags",
parse: $tw.utils.parseStringArray,
stringify: function(value) {
@ -345,8 +342,8 @@ $tw.plugins.registerPlugin($tw.config.root + "/kernel/tiddlerfields/tags","tiddl
return result.join(" ");
}
});
// Install built in tiddler fields plugins so that they are available immediately
$tw.Tiddler.fieldPlugins = $tw.plugins.getPluginsByTypeAsHashmap("tiddlerfield");
// Install built in tiddler fields module so that they are available immediately
$tw.Tiddler.fieldModules = $tw.modules.getModulesByTypeAsHashmap("tiddlerfield");
/////////////////////////// Barebones wiki store
@ -383,25 +380,25 @@ $tw.Wiki.prototype.getTiddler = function(title) {
};
/*
Hashmap of field plugins by plugin name
Hashmap of field modules by serializer name
*/
$tw.Wiki.tiddlerDeserializerPlugins = {};
$tw.Wiki.tiddlerDeserializerModules = {};
/*
Extracts tiddlers from a typed block of text, specifying default field values
*/
$tw.Wiki.prototype.deserializeTiddlers = function(type,text,srcFields) {
srcFields = srcFields || {};
var deserializer = $tw.Wiki.tiddlerDeserializerPlugins[type],
var deserializer = $tw.Wiki.tiddlerDeserializerModules[type],
fields = {};
if(!deserializer && $tw.config.fileExtensionInfo[type]) {
// If we didn't find the serializer, try converting it from an extension to a content type
type = $tw.config.fileExtensionInfo[type].type;
deserializer = $tw.Wiki.tiddlerDeserializerPlugins[type];
deserializer = $tw.Wiki.tiddlerDeserializerModules[type];
}
if(!deserializer) {
// If we still don't have a deserializer, treat it as plain text
deserializer = $tw.Wiki.tiddlerDeserializerPlugins["text/plain"];
deserializer = $tw.Wiki.tiddlerDeserializerModules["text/plain"];
}
for(var f in srcFields) {
fields[f] = srcFields[f];
@ -416,9 +413,9 @@ $tw.Wiki.prototype.deserializeTiddlers = function(type,text,srcFields) {
};
/*
Register the built in tiddler deserializer plugins
Register the built in tiddler deserializer modules
*/
$tw.plugins.registerPlugin($tw.config.root + "/kernel/tiddlerdeserializer/js","tiddlerdeserializer",{
$tw.modules.registerTypedModule($tw.config.root + "/kernel/tiddlerdeserializer/js","tiddlerdeserializer",{
"application/javascript": function(text,fields) {
var headerCommentRegExp = /^\/\*\\\n((?:^[^\n]*\n)+?)(^\\\*\/$\n?)/mg,
match = headerCommentRegExp.exec(text);
@ -429,7 +426,7 @@ $tw.plugins.registerPlugin($tw.config.root + "/kernel/tiddlerdeserializer/js","t
return [fields];
}
});
$tw.plugins.registerPlugin($tw.config.root + "/kernel/tiddlerdeserializer/tid","tiddlerdeserializer",{
$tw.modules.registerTypedModule($tw.config.root + "/kernel/tiddlerdeserializer/tid","tiddlerdeserializer",{
"application/x-tiddler": function(text,fields) {
var split = text.split(/\r?\n\r?\n/mg);
if(split.length > 1) {
@ -441,14 +438,14 @@ $tw.plugins.registerPlugin($tw.config.root + "/kernel/tiddlerdeserializer/tid","
return [fields];
}
});
$tw.plugins.registerPlugin($tw.config.root + "/kernel/tiddlerdeserializer/txt","tiddlerdeserializer",{
$tw.modules.registerTypedModule($tw.config.root + "/kernel/tiddlerdeserializer/txt","tiddlerdeserializer",{
"text/plain": function(text,fields) {
fields.text = text;
fields.type = "text/plain";
return [fields];
}
});
$tw.plugins.registerPlugin($tw.config.root + "/kernel/tiddlerdeserializer/html","tiddlerdeserializer",{
$tw.modules.registerTypedModule($tw.config.root + "/kernel/tiddlerdeserializer/html","tiddlerdeserializer",{
"text/html": function(text,fields) {
fields.text = text;
fields.type = "text/html";
@ -456,8 +453,8 @@ $tw.plugins.registerPlugin($tw.config.root + "/kernel/tiddlerdeserializer/html",
}
});
// Install the tiddler deserializer plugins so they are immediately available
$tw.plugins.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerPlugins);
// Install the tiddler deserializer modules so they are immediately available
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
/////////////////////////// Intermediate initialisation
@ -495,7 +492,7 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
/*
Register a deserializer that can extract tiddlers from the DOM
*/
$tw.plugins.registerPlugin($tw.config.root + "/kernel/tiddlerdeserializer/dom","tiddlerdeserializer",{
$tw.modules.registerTypedModule($tw.config.root + "/kernel/tiddlerdeserializer/dom","tiddlerdeserializer",{
"(DOM)": function(node) {
var extractTextTiddler = function(node) {
var e = node.firstChild;
@ -549,12 +546,12 @@ $tw.plugins.registerPlugin($tw.config.root + "/kernel/tiddlerdeserializer/dom","
return tiddlers;
}
});
// Install the tiddler deserializer plugin
$tw.plugins.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerPlugins);
// Install the tiddler deserializer modules
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
// Load the JavaScript system tiddlers from the DOM
$tw.wiki.addTiddlers($tw.wiki.deserializeTiddlers("(DOM)",document.getElementById("libraryModules")),true);
$tw.wiki.addTiddlers($tw.wiki.deserializeTiddlers("(DOM)",document.getElementById("pluginModules")),true);
$tw.wiki.addTiddlers($tw.wiki.deserializeTiddlers("(DOM)",document.getElementById("modules")),true);
$tw.wiki.addTiddlers($tw.wiki.deserializeTiddlers("(DOM)",document.getElementById("bootKernelPrefix")),true);
$tw.wiki.addTiddlers($tw.wiki.deserializeTiddlers("(DOM)",document.getElementById("bootKernel")),true);
// Load the stylesheet tiddlers from the DOM
@ -591,7 +588,7 @@ $tw.loadTiddlersFromFile = function(file,fields,isShadow) {
};
/*
Load all the plugins from the plugins directory
Load all the tiddlers from a directory
*/
$tw.loadTiddlersFromFolder = function(filepath,basetitle,excludeRegExp,isShadow) {
basetitle = basetitle || "$:/plugins";
@ -664,7 +661,7 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
return module.exports;
};
// Load plugins from the plugins directory
// Load modules from the modules directory
$tw.loadTiddlersFromFolder(path.resolve($tw.boot.bootPath,$tw.config.bootModuleSubDir),null,null,true);
// Load up the shadow tiddlers in the root of the core directory
@ -684,11 +681,11 @@ $tw.loadTiddlersFromFolder(path.resolve($tw.boot.wikiPath,$tw.config.wikiTiddler
/////////////////////////// Final initialisation
// Register plugins from the tiddlers we've just loaded
$tw.plugins.registerPluginModules();
// Register typed modules from the tiddlers we've just loaded
$tw.modules.registerTypedModules();
// Run any startup plugin modules
var mainModules = $tw.plugins.moduleTypes.startup;
// Run any startup modules
var mainModules = $tw.modules.types.startup;
for(var m=0; m<mainModules.length; m++) {
mainModules[m].startup.call($tw);
}

View File

@ -96,7 +96,7 @@ Commander.initCommands = function(moduleType) {
// Install the command modules
moduleType = moduleType || "command";
$tw.commands = {};
var modules = $tw.plugins.moduleTypes[moduleType],
var modules = $tw.modules.types[moduleType],
n,m,f,c;
if(modules) {
for(n=0; n<modules.length; n++) {

View File

@ -97,13 +97,13 @@ Command.prototype.subcommands.config = function() {
};
this.output.write("Configuration:\n");
dumpConfig($tw.config," $tw.config");
dumpObject("Tiddler field plugins:",$tw.Tiddler.fieldPlugins);
dumpObject("Tiddler field modules:",$tw.Tiddler.fieldModules);
dumpObject("Loaded modules:",$tw.modules.titles);
dumpObject("Loaded plugins:",$tw.plugins.moduleTypes);
dumpObject("Command plugins:",$tw.commands);
dumpObject("Parser plugins:",$tw.wiki.parsers);
dumpObject("Macro plugins:",$tw.wiki.macros);
dumpObject("Deserializer plugins:",$tw.Wiki.tiddlerDeserializerPlugins);
dumpObject("Loaded modules:",$tw.modules.moduleTypes);
dumpObject("Command modules:",$tw.commands);
dumpObject("Parser modules:",$tw.wiki.parsers);
dumpObject("Macro modules:",$tw.wiki.macros);
dumpObject("Deserializer modules:",$tw.Wiki.tiddlerDeserializerModules);
return null; // No error
};

View File

@ -3,7 +3,7 @@ title: $:/core/modules/deserializers.js
type: application/javascript
module-type: tiddlerdeserializer
Plugins to deserialise tiddlers from a block of text
Functions to deserialise tiddlers from a block of text
\*/
(function(){

View File

@ -47,7 +47,7 @@ exports.executeMacro = function() {
var tiddler = this.wiki.getTiddler(this.editTiddler),
Editor;
// Figure out which editor to use
// TODO: Tiddler field plugins should be able to specify a field type from which the editor is derived
// TODO: Tiddler field modules should be able to specify a field type from which the editor is derived
if(this.editField === "text" && tiddler && tiddler.fields.type) {
Editor = this.wiki.macros.edit.editors[tiddler.fields.type];
}

View File

@ -3,7 +3,7 @@ title: $:/core/modules/macros/edit/editors/bitmapeditor.js
type: application/javascript
module-type: editor
An editor plugin for editting bitmaps
An editor module for editting bitmaps
\*/
(function(){

View File

@ -3,7 +3,7 @@ title: $:/core/modules/macros/edit/editors/texteditor.js
type: application/javascript
module-type: editor
An editor plugin for editting text
An editor module for editting text
\*/
(function(){

View File

@ -13,7 +13,7 @@ Displays a sequence of tiddlers defined in two JSON structures. The story tiddle
The optional `draft` member indicates that the tiddler is in edit mode, and the value is the title of the tiddler being used as the draft.
When the story tiddler changes, the story macro adjusts the DOM to match. An optional storyview plugin can be used to visualise the changes.
When the story tiddler changes, the story macro adjusts the DOM to match. An optional storyview module can be used to visualise the changes.
And the history tiddler is the stack of tiddlers that were navigated to in turn:
@ -27,7 +27,7 @@ And the history tiddler is the stack of tiddlers that were navigated to in turn:
]
}
The history stack is updated during navigation, and again the storyview plugin is given an opportunity to animate the navigation.
The history stack is updated during navigation, and again the storyview module is given an opportunity to animate the navigation.
\*/
(function(){

View File

@ -266,7 +266,7 @@ var WikiTextParser = function(options) {
this.runRules = [];
var blockRegExpStrings = [],
runRegExpStrings = [],
rules = ($tw.plugins.moduleTypes.wikitextrule || []).slice(0);
rules = ($tw.modules.types.wikitextrule || []).slice(0);
for(var t=0; t<rules.length; t++) {
if(rules[t].blockParser) {
this.blockRules.push(rules[t]);

View File

@ -3,7 +3,7 @@ title: $:/core/modules/recipe.js
type: application/javascript
module-type: tiddlerdeserializer
Plugin to deserialize tiddlers from an old school TiddlyWiki recipe file.
Module to deserialize tiddlers from an old school TiddlyWiki recipe file.
The idea is to process the recipe file recursively, loading tiddlers into the main store using synchronous file operations. The tiddlers have their titles prefixed with the associated marker in curly brackets ("{shadow}", "{tiddler}" etc).

View File

@ -3,7 +3,7 @@ title: $:/core/modules/serializers.js
type: application/javascript
module-type: tiddlerserializer
Plugins to serialise tiddlers to a block of text
Functions to serialise tiddlers to a block of text
\*/
(function(){

View File

@ -15,27 +15,27 @@ This is the main application logic for both the client and server
exports.startup = function() {
var modules,n,m,f,commander;
// Load modules
$tw.plugins.applyMethods("global",$tw);
$tw.plugins.applyMethods("config",$tw.config);
$tw.plugins.applyMethods("utils",$tw.utils);
$tw.modules.applyMethods("global",$tw);
$tw.modules.applyMethods("config",$tw.config);
$tw.modules.applyMethods("utils",$tw.utils);
if($tw.browser) {
$tw.utils.getBrowserInfo($tw.browser);
}
$tw.version = $tw.utils.extractVersionInfo();
$tw.Tiddler.fieldPlugins = $tw.plugins.getPluginsByTypeAsHashmap("tiddlerfield");
$tw.plugins.applyMethods("tiddlermethod",$tw.Tiddler.prototype);
$tw.plugins.applyMethods("wikimethod",$tw.Wiki.prototype);
$tw.plugins.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerPlugins);
$tw.Wiki.tiddlerSerializerPlugins = {};
$tw.plugins.applyMethods("tiddlerserializer",$tw.Wiki.tiddlerSerializerPlugins);
$tw.plugins.applyMethods("treeutils",$tw.Tree);
$tw.plugins.applyMethods("treenode",$tw.Tree);
$tw.Tiddler.fieldModules = $tw.modules.getModulesByTypeAsHashmap("tiddlerfield");
$tw.modules.applyMethods("tiddlermethod",$tw.Tiddler.prototype);
$tw.modules.applyMethods("wikimethod",$tw.Wiki.prototype);
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
$tw.Wiki.tiddlerSerializerModules = {};
$tw.modules.applyMethods("tiddlerserializer",$tw.Wiki.tiddlerSerializerModules);
$tw.modules.applyMethods("treeutils",$tw.Tree);
$tw.modules.applyMethods("treenode",$tw.Tree);
// Set up the wiki store
$tw.wiki.initMacros();
$tw.wiki.initEditors();
$tw.wiki.initStoryViews();
$tw.wiki.initParsers();
// Set up the command plugins
// Set up the command modules
$tw.Commander.initCommands();
// Host-specific startup
if($tw.browser) {

View File

@ -22,10 +22,10 @@ exports.getFieldString = function(field) {
if(value === undefined) {
return undefined;
}
// Parse the field with the associated plugin (if any)
var fieldPlugin = $tw.Tiddler.fieldPlugins[field];
if(fieldPlugin) {
return fieldPlugin.stringify.call(this,value);
// Parse the field with the associated module (if any)
var fieldModule = $tw.Tiddler.fieldModules[field];
if(fieldModule) {
return fieldModule.stringify.call(this,value);
} else {
return value.toString();
}

View File

@ -3,7 +3,7 @@ title: $:/core/modules/utils/dom/popup.js
type: application/javascript
module-type: utils
Plugin that creates a $tw.utils.Popup object prototype that manages popups in the browser
Module that creates a $tw.utils.Popup object prototype that manages popups in the browser
\*/
(function(){

View File

@ -3,7 +3,7 @@ title: $:/core/modules/utils/dom/scroller.js
type: application/javascript
module-type: utils
Plugin that creates a $tw.utils.Scroller object prototype that manages scrolling in the browser
Module that creates a $tw.utils.Scroller object prototype that manages scrolling in the browser
\*/
(function(){

View File

@ -196,7 +196,7 @@ exports.addTiddler = function(tiddler,isShadow) {
Serialise a tiddler to a specified text serialization format
*/
exports.serializeTiddler = function(tiddler,type) {
var serializer = $tw.Wiki.tiddlerSerializerPlugins[type];
var serializer = $tw.Wiki.tiddlerSerializerModules[type];
if(typeof tiddler === "string") {
tiddler = this.getTiddler(tiddler);
}
@ -375,7 +375,7 @@ exports.initParsers = function(moduleType) {
// Install the parser modules
moduleType = moduleType || "parser";
$tw.wiki.parsers = {};
var modules = $tw.plugins.moduleTypes[moduleType],
var modules = $tw.modules.types[moduleType],
n,m,f;
if(modules) {
for(n=0; n<modules.length; n++) {
@ -445,8 +445,8 @@ exports.renderTiddler = function(outputType,title) {
};
/*
Install macro plugins into this wiki
moduleType: Plugin type to install (defaults to "macro")
Install macro modules into this wiki
moduleType: Module type to install (defaults to "macro")
It's useful to remember what the `new` keyword does. It:
@ -460,7 +460,7 @@ exports.initMacros = function(moduleType) {
moduleType = moduleType || "macro";
$tw.wiki.macros = {};
var MacroClass = require("./treenodes/macro.js").Macro,
modules = $tw.plugins.moduleTypes[moduleType],
modules = $tw.modules.types[moduleType],
n,m,f,
subclassMacro = function(module) {
// Make a copy of the Macro() constructor function
@ -485,26 +485,26 @@ exports.initMacros = function(moduleType) {
};
/*
Install editor plugins for the edit macro
Install editor modules for the edit macro
*/
exports.initEditors = function(moduleType) {
moduleType = moduleType || "editor";
var editMacro = this.macros.edit;
if(editMacro) {
editMacro.editors = {};
$tw.plugins.applyMethods(moduleType,editMacro.editors);
$tw.modules.applyMethods(moduleType,editMacro.editors);
}
};
/*
Install view plugins for the story macro
Install view modules for the story macro
*/
exports.initStoryViews = function(moduleType) {
moduleType = moduleType || "storyview";
var storyMacro = this.macros.story;
if(storyMacro) {
storyMacro.viewers = {};
$tw.plugins.applyMethods(moduleType,storyMacro.viewers);
$tw.modules.applyMethods(moduleType,storyMacro.viewers);
}
};
@ -515,8 +515,8 @@ exports.initSavers = function(moduleType) {
moduleType = moduleType || "saver";
// Instantiate the available savers
this.savers = [];
for(var t=0; t<$tw.plugins.moduleTypes[moduleType].length; t++) {
var saver = $tw.plugins.moduleTypes[moduleType][t];
for(var t=0; t<$tw.modules.types[moduleType].length; t++) {
var saver = $tw.modules.types[moduleType][t];
if(saver.canSave(this)) {
this.savers.push(saver.create(this));
}

View File

@ -49,7 +49,7 @@ type: text/x-tiddlywiki-html
<<serialize "$:/core/bootprefix.js" application/javascript>>
</div>
<!----------- Plugin modules ----------->
<div id="pluginModules" style="display:none;">
<div id="modules" style="display:none;">
<<serialize "[is[shadow]type[application/javascript]has[module-type]]" application/x-tiddler-module>>
</div>
<!----------- Boot kernel ----------->