Website engineering: Rewrite CommandlineHighlight plugin #6429
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
WORK-IN-PROGRESS
Honestly I didn't envision this change become so big. There is a quite some more work to be done before this PR is ready so it may take some time. I'm opening this now to gather feedback and start the discussion around the open questions I'm encountering.
If you want to review the code, note that I am most likely going to rewrite some of these commits before the PR is marked as ready.
What's the problem this PR addresses?
In the website build chain, we have a custom
CommandLineHighlight
remark plugin that superchargesyarn
calls with syntax highlighting, documentation links, and tooltips using command metadata generated directly from our TS sources.The plugin parses the command as given in the MDX source, resolve the yarn command being invoked, do some processing on the command metadata, but then it mostly just dumps the data as a React component in JSX (something like this). Then, that component needs more runtime client-side logic to determine what is what so as to correctly render various parts of the command.
IMO this implementation has some maintainablility issues:
These combined makes this system very difficult to extend and/or work with. In fact, this whole rewrite started as I was trying to make it correctly parse and highlight some commands used in the website like
yarn node --inspect $(yarn bin jest)
and wasn't able to make it work under the original implementation.How did you fix it?
Rewrote the whole remark plugin. Under this new plugin, the React components are "dumb" -- they have minimal logic and does little more than styling. The vast majority of the data processing happens at build-time in the remark plugin.
The main "visible" change is that many more things are recognized and processed as commandlines out-of-the-box, without authoring the MDX in special ways. On the other hand, if something isn't recognized and processed as intended, there are many escape hatches to force the plugin to process it certain ways. And, if everything else fails, it is much easier than before to write JSX to get the desired rendering because the React components are "dumb".
Commandline Recognition
The old plugin recognizes the following as commandline:
yarn
commandyarn
commandThe new plugin is able to process much more stuff, so it needs a better heuristic to reduce false positive and false negatives
commandline
is the specified language or appears in the metastring. This makes code block highlighting fully opt-in.yarn
, there are a few commonly-used commands on the website (e.g.node
) that will be recognized.And there are a few escape hatches for this:
<code>
elements instead of markdown inline code. The plugin only processes the latterMore Commandline Forms and Syntaxes
YARN_IGNORE_PATH=1 node --prof packages/yarnpkg-cli/bundles/yarn.js
yarn exec env | grep COREPACK_ROOT
yarn node --inspect $(yarn bin jest)
.yarn add <package>
. Taken literally, these are syntax errors because angled brackets are parsed as redirection. The new plugin treats words surrounded by angled brackets as a simple argument and can correctly style them.Bare options
A number of places needs styling for "bare options". Take the following paragraph as an example
Here, the "
--update
" refers to a flag of theyarn patch
command. Ideally it should have a tooltip describing it, just as it would have in`yarn patch --update`
. In the old plugin that can be done by writing`yarn patch ! --update`
in the MDX, but the new plugin uses a simple heuristic to avoid the need to do so: When a flag is mentioned, the command for it is almost always also mentioned nearby. So when the new plugin sees a bare option, it will check if it is a flag for the command definition that was used most recently while processing that file. If it isn't, it will try again with the next definition used.This resolves the majority of cases, and most of the rest can be fixed by rewording the documentation to include the command.
Open Questions
What should be the syntax to force inline code to be recognized? Currently I use
{/* commandline */}`grep`
but there are a few alternative I'm considering like`grep # commandline`
or using markdown directives:commandline[grep]
It is all well and good to use escape hatches in most MDX files under
docs
andblog
because these are written specifically for the website. Showing the escape hatches used (e.g. JSX) when viewed elsewhere like on GitHub does not matter because the only canonical way to view them is on the website. But there are a few markdown/MDX files where it isn't clear that's the case:`yarn npm audit ! --no-deprecations`
) so I guess that is also intended to be viewed only through the website?yarn explain
so we can't use escape hatches? Butyarn explain
already does not do so well with it (e.g. tryyarn explain YN0002
) so I guess it's fine? 🤷Also, the majority of the cases where the dropping down to JSX is necessary are for distinguishing "implicit yarn run" (e.g.
yarn build
) vs a command that does not exist (e.g.yarn global
,yarn policies set-version
). Is there a way we can reduce the need to do that? E.g. a list of known script names and everything else is by default a false command? Or a list of known false commands? Etc.Lastly, sometimes just saying "writing JSX" isn't a good solution. In particular, commands and options for Yarn commands need the command metadata to provide the tooltips and writing them by hand risk them drifting out of sync. This is especially important for bare options. Of course it generally is good if bare options are accompanied by mentioning the command so the reader can understand better, but what if that isn't the case? Should there be an escape hatch to tell the plugin to inject the metadata? What should that look like?
Checklist