Plugins Development Rules
No Inlining
FastSchema Plugins System allows developers to register resource handlers and hooks with js function. However, the js function must not be inlined when registering.
The js function MUST be defined independently in the GLOBAL SCOPE and then registered using the function name.
Not working
// Hook function
config.OnPreResolve(ctx => {
// Do something
});
// Resource handler
plugin.resources.Add(ctx=> {
return 'pong';
}, { get: 'ping' });
Working
// Hook function
const OnPreResolve = ctx => {
// Do something
};
// Resource handler
const ping = ctx => {
return 'pong';
};
const Config = config => {
config.OnPreResolve(OnPreResolve);
}
const Init = plugin => {
plugin.resources.Add(ping);
}
Global Scope
FastSchema Plugins System using Goja Runtime to execute the js code. The JS file will be compiled to Goja Program and executed in the Goja Runtime.
The execution of a Goja Program takes time and resources. To mitigate this, FastSchema Plugins using sync.Pool
to manage the Goja Runtime.
The sync.Pool
will store the Goja Runtime and reuse it for the next execution. This will reduce the overhead of creating a new Goja Runtime for each execution. It will also reduce the overhead of Golang Garbage Collector.
Global Scope Variables
Because of reusing the Goja Runtime, the Global Scope of the JS file will be shared between executions. This can lead to unexpected behavior if the Global Scope variables are mutated.
let counter = 0;
const OnPreResolve = ctx => {
counter++;
};
In the example above, the counter
variable will be shared between executions. In the OnPreResolve
, the counter
will be incremented by 1. But if the execution is done multiple times, the counter
will be incremented multiple times in a new or shared runtime (which can't be guaranteed). It may be 1, 2, 3, or any other value.
To mitigate this, we should not MUTATE the variable in the Global Scope.
// BAD
let counter = 0;
// GOOD
const counter = 0;
Global Scope Functions
When registering a js function as a resource handler or hook, the function name will be used as a key to register the function.
Whenever a resource handler or hook needs to be executed, the FastSchema Plugins System look up the function in Goja Runtime using its name.
If the function is defined in a nested scope, the function lookup will fail and the system will throw an error.
To make sure the function is registered correctly, the function MUST be defined in the Global Scope.
// NOT WORKING
const Config = config => {
const OnPreResolve = ctx => {
// Do something
};
config.OnPreResolve(OnPreResolve);
};
// WORKING
const OnPreResolve = ctx => {
// Do something
};
const Config = config => {
config.OnPreResolve(OnPreResolve);
};