Proposal: New Plugin & Module System
I would like to propose having a new system for Gun modules.
Goals:
- Increased functionality of Gun Example: display toast notifications when data fails to save
- Reduce Boilerplate
Example: Turn this code:
let data = reactive()
gun.get('data').map().on((value, key) => {
data[key] = value
})
Into this:
let data = gun.get('data').bind()
- Maintain a low package size by including only the most important functionality in core
- Combine related functionality into a single module Example: index data on save, search it with a custom chain
- Make gun plugins work with
importand typescript
Introduction
A module is a Javascript object that can be added to the Gun instance before new Gun() is run. Many modules will be created using classes instead of defining the object directly. Each module can be made up of any number of plugins, which are contained in the object. I think there should be three types of plugins:
1. Chain Extensions / Custom Methods
Chain extensions are what we have now, we can add methods to the chain like this:
Gun.chain.newMethod = function () {
//do something
return this
}
However, I think something like this would work better for modules:
Gun.addChainMethods({ newMethod: () => {
//do something
return this
})
Hooks
Hooks execute before or after a function is run. Both kinds of hooks will have access to the current gun chain instance. Hooks run after will have access to the same set of data as callbacks, and will be run in addition to, not replacing, callbacks. Each chain method can have an unlimited number of hooks. Methods added with Gun.addChainMethod shouldn't have to define their own hooks, Gun should do this automatically. Adding hooks looks something like this:
Gun.addHooks({
put: {
before: () => alert("data being saved"),
}
})
Modifiers
Modifiers are a function with an input of a Gun instance and an output of a Gun instance. This can, of course, be done already, but I'd like it to be possible in gun modules. A modifier can do anything, including taking away or replacing methods.
Gun = myModifier(Gun)
Putting it all together: modules
The three kinds of plugins I described should go together in a module, like this:
const gun = Gun({
modules: [SEA, searchModule, toasterModule, vueModule, webrtcModule]
})
In addition, modules should be able to declare dependencies. I would suggest that modules look like this:
interface IGunModule {
name: string,
dependencies: string[],
chainMethods?: { [key: string]: any }
hooks?: { [key: string]: {
before: any,
after: any,
}
},
modifiers: modifier[]
}
@code3z last week was hectic, sorry! Then I forgot to reply, sorry. This looks awesome! I wanted to add some more comments to help start this... but wanted to at least reply now before I forgot again lol. Hopefully today/tomorrow, pester me if not.
A method to add chain methods can be done by:
GUN.methods = function(chain){
Object.keys(chain).forEach(function(i){ GUN.chain[i] = chain[i] });
}
I love the bind idea, it can be done by:
GUN.methods({bind: function(){
var data = {};
this.on(function(raw){ Object.assign(data, raw) });
return data;
}});
Hooks can be done with:
GUN.hooks = function(hook){
GUN.hooks.are.push(hook);
}
GUN.hooks.are = [];
GUN.on('create', function(root){
this.to.next(root);
var hooks = GUN.hooks.are;
Object.keys(hooks).forEach(function(i){
var hook = hooks[i];
root.on('put', function(msg){
hook.before(msg);
this.to.next(msg);
hook.after(msg);
});
});
});
Modifiers is how User system is done:
function User(root){
this._ = {$: this};
}
User.prototype = (function(){ function F(){}; F.prototype = Gun.chain; return new F() }()) // Object.create polyfill
User.prototype.constructor = User;
The only thing I disagree with is the modules section. Modules should configure themselves, they can receive options via GUN(options) by listening to the create event, or dynamically updating options on the opt event. All an app dev should have to do to add modules is import/require them, any additional passing them around is unnecessary configuration that is easy to shoot yourself in the foot with.
If you're willing to support your plugin/module system, I'm willing to promote it - hopefully this starting code (there may be some typos) is a helpful start. First publish it as an NPM module for others to add, then let's talk about it in the chat room and awesome-list and other places, this'll be a candidate review process with the community, then Second, if it gains active use/support, we can upgrade it to a gun/lib/ official. Third, as long as someone is willing to maintain it, we can then offer a custom build with it as default as like gun/gun.main.js or similar.