-
Notifications
You must be signed in to change notification settings - Fork 433
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Plugin system #63
Comments
Definitely a good direction, and great code to my non-js-expert eyes (is this a common approach to plugins in JS ?). The separation pre pug/post html actions is spot on. This being said I would be for waiting a bit to be sure to get the best architecture possible for plugins. Right now I would suggest we add important features (and bibliography certainly is one) in the core code, and take our time, until we can look at a few of these features and ask "what is the plugin architecture that can take them all out of the code". Right now I can see the MathJax filter, the bibliography, and custom mixins, but that's just after a few weeks, let's wait a bit. My main feature requests for plugins at this point would be:
// use-plugin: mathjax
// use-plugin: bibliography style=someStyle That's what I am doing with the MathJax plugin (which used to be applied on every document, and considerably slowed down every rendering, even for documents which didn't need any mathjax) |
I am not entirely sure if my method of JS plugins is common, I have seen it in a few locations before. Your suggestion of As for the bibliography I do know how I can program it in directly, when I was programming the plugins, I built the bibliography as a plugin, I can easily adapt this a built in system. But, more importantly, I used jsdom to do the bibliography and I think that could be used to do similar things such as a ToC, Figure list, Indexing, etc. |
I believe these lines are how Pug looks for filters that are provided by plugins. It would work for us, relaxed plugins would be npm libraries called
Then the plugins will be resolved in Node using I am also thinking that instead of using {
mathjax: true,
bibliography: {
style: 'apa-citation'
} This would make it much easier to have plugins with options. So we already have several hooks that plugins should consider:
Again I am in no hurry to do that before ReLaXed has a good userbase. |
So, as I worked on the table of contents I was thinking about how @Zulko mentioned it will shift content down and that needs to be taken into account. The same issue would happen for an index list, which would cause the same problem. So I was thinking of the plugin structure and the hooks we would need. For the hooks I would think we need:
Because the page has the power to modify more than the pugs, I do not think that The reason we would need two page passes, is so that the bibliography can generate in the first pass, the ToC, index, and figure list can generate without page numbers. And the second pass the ToC, index, and figure list can fill in the missing page numbers. As for the plugin settings and enabling I think we should provide both the option to use a |
I have done a fair bit of work on a plugin system currently, it will have a different structure than what we first did. If you want to check it out here. It has tonnes of work left to do, but it has plenty of hooks, full async, all type checked and error handling present, mostly documented (as I have been going). Currently, I am working on the way it loads the plugins, either from a json file (or other config type later), and code comments in the master file. There are ways of capturing the plugin names, settings, and dependencies (other plugins). I am stopping for the night. Later on I will need to write up a tree to handle plugin dependencies and control load order of plugins, plugins are still going to load asynchronously. The hooks are/will be:
Plugins, along with using their own |
EDIT: just edited a bit. sorry for the noise. Awesome. Some remarks.
The implementation I had in mind was this. First the json in which the user defines the plugins (the structure is so it will look much simpler in YAML): [
[
"mathjax",
{"everywhere": true}
],
...
] Then here is how the plugins are loaded. They should be reloaded every time the file "plugins.json" changes: pluginsList = require('plugins.json')
// registeredPlugins is not a list of plugins, but has separate lists for mixin, html, etc.
registeredPlugins = { mixins: [], html: [], page1st: [], etc. }
for entry in pluginsList:
[name, options] = entry
pluginConstructor = require('relaxed-' + name) // here, relaxed-mathjax.
// other resolution for local plugins if
plugin = pluginConstructor(options) // here options: {"everywhere": true}
if plugin.mixins:
registeredPlugins.mixins.push(mixin)
if plugin.html:
registeredPlugins.html.push(html)
// now reorder the internal registeredPlugins.mixins, registeredPlugins.html, etc. Then in the ReLaXed code, it will be as simple as var html = ... // render html
registeredPlugins.html.each(function (transformer) {
html = transformer(html)
}) These are just thoughts, I'm open to other ideas. Let me know if it makes sense and if I understood it correctly. |
Sorry, I was heading off to bed when I wrote that, probably not the best time to explain the plugin dependency. I was imagining that a Ill have to make up an example of how I see the plugins being initialized and their operations run. That will give a better understanding of the structure. plugin/index.js // private variables, functions, etc. Not exported
const name = 'plugin_example'
exports.activate = async function(plugin) {
await plugin.registerMixin({
plugin: name, // I probably will come up with a solution to omit this
mixin: path.join(__dirname, 'mixins.pug')
})
await plugin.registerWatcher({
plugin: name,
ext: ['.test', '.test2'],
handler: async function(file) { ... }
})
await plugin.expose({
some_option: 'thing',
some_other_option: 'thing 2'
})
}
exports.deactivate = async function(plugin) {
// In case some sort of tear down is needed after pdf is rendered
}
// Optionally, instead of plugin.expose we could do this, I prefer the plugin.register method myself
exports.options = {}
exports.mixin = path.join(__dirname, 'mixins.pug') |
I just updated the plugin system, it should be operational now, It is integrated, and has gone through 1 very very limited test. I need to create an actual npm module for relaxed to test it out fully. |
Sure, what about the relaxed-bibliography plugin for a start ? |
What about |
@Zulko I was actually going to make a I do not know about anyone else, but, I have been thinking that the pre pug hook, where the plugin hands over the raw pug files, is not needed. I cannot think of a use case that cannot be covered by the html hook or page hooks. I am going to remove that unless someone needs it. @DanielRuf, Yea, when I meant an actual npm package I did not mean a published one, just local testing to ensure everything is working, we will publish real ones later on. |
@Drew-S An "example plugin" makes sense. Can we call it As I said before I share your feeling about prePug filters. As I understand it, it should be easy to add new "hooks" (like prePug) to plugins later, without breaking the compatibility of existing plugins (they'll just have "undefined" for this hook). Is that correct ? |
@Zulk Yes, I do have permission to create a new repo. All the hooks are isolated so adding or removing them will not cause harm, instead of just removing the code we can have the disabled function return an error or statement that it is not available. |
Here is some inspiration on what the yaml file could look like: https://github.com/svg/svgo/blob/master/docs/how-it-works/en.md |
I added yaml support as well as json to the plugin system, I also tested it with normal relaxed, it does not affect anything when plugins are omitted. I think we can integrate the plugin system with the master branch without issue, I still want to get the example plugin made though. I am currently working on that. Yaml structure: someSetting: 'thing'
plugins:
- example-plugin:
- dependencies:
- test2-plugin
- someVariable: 4 JSON Structure: {
"someSetting": "thing",
"plugins": [
{
"example-plugin: {
"dependencies": ["test2-plugin"],
"someVariable": 4
}
}
]
} |
what is "dependencies" and does it need to be set by the user ? Is that some kind of "run after this other plugin ?" |
Its optional. Essentially yes, it is a run after some other plugin thing, I do not think there will be much in the way of dependencies, but it is a real possibility to consider. |
I'm nitpicking, but can we call it |
It honestly does not matter to me what we call it, I just kept to the npm packages.json naming convention. Either works for me. I just completed testing and have a full example plugin ready to go, Ill go ahead a create a new repo and upload the example there. Take a look: example-plugin |
I just pushed a giant commit which does a lot of reorganizing, and rewrites in some extent the way plugins are loaded (I'll document it a bit more later), it comes with some features (again, to be documented) but I may also have cut some of the plugin possibilities you wanted (notably dependencies) when I thought it was too complicated for the moment. Bibliography etc. work, as shown by the tests. I have also renamed some things, for instance Edit: this is a halfway-commit, in the sense that some features will very soon get their own plugins (mermaid, flowcharts, vegalite), which will lead to the removal of |
The latest commit ends the path to "a" plugin system. It is certainly not definitive, there are some hooks I want to add:
|
I will spend some time documenting it later, and updating the
|
I created a plugin system: plugin. I have not done a pull request yet, as the plugin directory location is arbitrary, it is inside the relaxed
src
directory. I want to set a user configuration directory for things like plugins (~/.relaxed/plugins
), global templates, global configurations, etc. But before I do that I would like for some feedback on the plugin system. Plugins are loaded fromsrc/plugins/<plugin>/index.js
and are formatted gist. This system was made for my bibliography system so that it does not run during the puppeteer runtime, as per @Zulko's issue with my current system #59. This also provides a system for other plugins in the future. It consists of three parts, pre-pug processing: where the raw pug string is given (main file only), post-pug processing: where the raw compiled html is given (before saving), and mixin: where any plugin mixins are added along with the default mixins.The text was updated successfully, but these errors were encountered: