-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
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
Add beforeEmbed and afterEmbed hook #1571
Conversation
This pull request is being automatically deployed with Vercel (learn more). 🔍 Inspect: https://vercel.com/docsify-core/docsify-preview/3nHYfjUq2gqrV2eqty6vgkV5MPC7 |
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit 4ef235f:
|
Edit: done |
Hello! This seems like a useful addition. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we decide we are okay to merge this an have hooks that are coupled to (require) marked
, then the only thing we need to do is change or describe what "embed" means. This currently won't have any meaning to someone reading the docs.
@@ -18,9 +18,21 @@ window.$docsify = { | |||
return content; | |||
}); | |||
|
|||
hook.beforeEmbed(function(tokens, next) { | |||
// Invoked each time after parsing the Markdown file, but before embedding is applied to the token list. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to change the wording, or otherwise describe what "embedding" is. I don't think that currently Docsify users have any concept of "embed", and the term "embed" is currently just an internal detail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I doubt that given there is a whole page about embedding files in the documentation: https://docsify.js.org/#/embed-files
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, yeah, oops. 😄
Does marked give back tokens just for the embed? Or what exactly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"tokens" is an array of token, produced by the compile.lexer(raw)
call. It is indeed a vendor-specific data structure produced by marked.
docsify/src/core/render/embed.js
Line 103 in 66303fe
let tokens = compile.lexer(raw); |
Docsify's embed mechanism operates on this token list as well.
@@ -5,6 +5,8 @@ export function initLifecycle(vm) { | |||
'init', | |||
'mounted', | |||
'beforeEach', | |||
'beforeEmbed', | |||
'afterEmbed', | |||
'afterEach', | |||
'doneEach', | |||
'ready', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should list the order of hooks, otherwise people have to find this in the code right here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The updates to the "Write a Plugin" page do a better job of describing when hooks are invoked. The updates aren't live yet, but they can be viewed on the develop
branch preview.
export function prerenderEmbed( | ||
{ compiler, raw = '', fetch, beforeEmbed }, | ||
done | ||
) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another thing is, this hook would depend on marked
, thus is markdown-compiler-specific. What if we change renderers later?
Maybe it is good for now (performance boost) and if we change markdown renderer later then it would simply be a breaking change.
Arguably even without this hook, it would be a breaking change because output of the strings can change. But with this hook in place, it could be that a different markdown renderer does not have a concept of tokens that can be passed to a hook plugin.
Also, what if we wish to add the ability to specify markdown renderers? beforeEach and afterEach would continue to make sense, but maybe beforeEmbed would not make sense if a different markdown renderer does not pass tokens out.
So the question is: do we want to add this, and be coupled to marked
? Or not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we decide we want this, I think the way it is implemented looks good.
@@ -33,6 +33,8 @@ describe('Docsify', function() { | |||
|
|||
expect(hook.init).toBeInstanceOf(Function); | |||
expect(hook.beforeEach).toBeInstanceOf(Function); | |||
expect(hook.beforeEmbed).toBeInstanceOf(Function); | |||
expect(hook.afterEmbed).toBeInstanceOf(Function); | |||
expect(hook.afterEach).toBeInstanceOf(Function); | |||
expect(hook.doneEach).toBeInstanceOf(Function); | |||
expect(hook.mounted).toBeInstanceOf(Function); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sidenote, we need better hooks tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you mind adding tests so that it shows how to use the hook and tokens (and makes sure it won't break later).
The other tests are bad (they are lacking, obviously), but moving forward we should test new features at least.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant to review as "Request changes", regarding the "embed" wording.
But let's chat first about if we want to have these hooks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--
@@ -18,9 +18,21 @@ window.$docsify = { | |||
return content; | |||
}); | |||
|
|||
hook.beforeEmbed(function(tokens, next) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should pass tokens
produced from a markdown parser to a plugin hook. As @trusktr pointed out, this makes the plugin functionality dependent on a specific markdown library which IMHO is not a good idea.
More importantly, I don't think we should pass "markdown before it becomes HTML" in two different formats (string
vs tokens
) to two very similar hooks:
hook.beforeEach(function(content) {
// ...
return content;
});
hook.beforeEmbed(function(tokens) {
// ...
return tokens;
});
If plugins authors want to work with tokens, they can generate their own tokens by accessing Docsify's renderer directly within their plugin:
window.$docsify = {
plugins: [
function(hook, vm) {
hook.beforeEach(function(content) {
const renderer = vm.config.markdown.renderer
// Do renderer stuff...
return content;
});
}
]
}
@@ -33,6 +33,8 @@ describe('Docsify', function() { | |||
|
|||
expect(hook.init).toBeInstanceOf(Function); | |||
expect(hook.beforeEach).toBeInstanceOf(Function); | |||
expect(hook.beforeEmbed).toBeInstanceOf(Function); | |||
expect(hook.afterEmbed).toBeInstanceOf(Function); | |||
expect(hook.afterEach).toBeInstanceOf(Function); | |||
expect(hook.doneEach).toBeInstanceOf(Function); | |||
expect(hook.mounted).toBeInstanceOf(Function); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -5,6 +5,8 @@ export function initLifecycle(vm) { | |||
'init', | |||
'mounted', | |||
'beforeEach', | |||
'beforeEmbed', | |||
'afterEmbed', | |||
'afterEach', | |||
'doneEach', | |||
'ready', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The updates to the "Write a Plugin" page do a better job of describing when hooks are invoked. The updates aren't live yet, but they can be viewed on the develop
branch preview.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would make for a welcome addition. See in-line comments for code change requests.
FWIW, adding new beforeEmbed
and afterEmbed
hooks are a good approach for adding this feature as a non-breaking change. Long term, it may be preferable (TBD) to pass all markdown (cover, content, embeds, sidebar, navbar, etc.) to a single "do stuff with markdown" hook along with meta data to indicate what type of markdown it is. That's a conversation for a later date, but I wanted to mention it in case anyone was concerned with the growing number of plugin hooks.
@kevinresol -- Checking in. This PR kinda got lost, but if you're willing to make a few updates it would make for a nice addition to Docsify. |
Sorry but my memory about this has long gone and I don't right now have time to pick it up again... |
Summary
Add a "beforeEmbed", "afterEmbed" hook that will receive and return the markdown token list before and after the "embed file" mechanism takes place.
This will be useful for plugins that wish to pre-process the markdown. Currently one has to parse the markdown in
beforeEach
, work with the parsed token list and then re-stringify the tokens into markdown string for the next step, which is wasteful. With these hooks, one can just mess with the parsed token list and go on.What kind of change does this PR introduce?
Feature
For any code change,
Does this PR introduce a breaking change? (check one)
If yes, please describe the impact and migration path for existing applications:
Related issue, if any:
Tested in the following browsers: