-
Notifications
You must be signed in to change notification settings - Fork 207
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
Fix \require to properly handle retries in dependencies. (mathjax/MathJax#3170) #1050
Conversation
Viewing without whitespace differences may make the changes clearer. |
This is a random question that I've been meaning to ask - apologies for abusing this PR to do so: Is it correct that an extension doesn't have to do anything beyond importing another extension to indicate that it has a dependency? (IIRC in v2 we had to do some extra legwork to alert MathJax to such dependencies.) |
Unfortunately, no. The dependencies are defined in the Also unfortunately, it is not possible for the the extension's component file to define the dependencies itself, because those have to be in place before the extension is loaded (so that the dependencies will be loaded first). It would be possible, I suppose, to have a small <script>
MathJax = {
...
}
</script>
<script src="<URL-fo-extension>/def.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/mathjax/tex-svg.js"></script> where if (!window.MathJax) window.MathJax = {};
if (!MathJax.loader) MathJax.loader = {};
if (!MathJax.loader.dependencies) MathJax.loader.dependencies = {};
MathJax.loader.dependencies['[path]/extension'] = ['input/tex-base', '[tex]/dep1', '[tex]/dep2']; where The if (!MathJax.loader.paths) MathJax.loader.paths = {};
if (!MathJax.loader.paths['path']) {
MathJax.loader.paths['path'] = '<URL-to-extension>';
}
if (!MathJax.tex) MathJax.tex = {};
if (!MathJax.tex.packages) MathJax.tex.packages = {};
if (Array.isArray(MathJax.tex.packages)) {
MathJax.tex.packages.push('[path]/extension');
} else {
if (!MathJax.tex.packages['[+]']) MathJax.tex.packages['[+]'] = [];
MathJax.tex.packages['[+]'].push('[path]/extension');
} to configure the loading of the extension and adding it to the the package list. (This code is untested, so it might need tweaking.) That way, the user only needs to load This does mean there is an extra (synchronous) file download, which is not great, but you could use The reason that the dependencies must be loaded first is that this is needed if an extension shares code with another extension. For example, if extension A has a class |
Thanks for clarifying, Davide. I'm sorry for making you write up such a complete response. There's never been a problem in production so I stopped worrying about it some time ago. |
No problem. Since you are running your code server-side, and not through webpacked components in the browser, you don't need to worry about the dependencies, as there is no |
Right I was actually thinking of client-side use. The specific situation is just far less complex so the dependencies always load first anyway. |
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.
lgtm.
When
\require{}
is used to load an extension, then if the extension has preprocessors, that means the the expression needs to be re-typeset so that the preprocessors will be run. This is handled by callingmathjax.retryAfter()
during theRegisterExtension()
function.If the extension has other extensions as dependencies, then they may also cause re-typesetting if they have preprocessors. That means the
RegisterDependencies()
function may throw aretry
error, which stops the processing of the dependencies, and prevents the remainder of theRegisterExtension()
function from completing.This occurs, for example, when
\require{textcomp}
is processed, astextcomp
depends ontextmacros
, and the latter has preprocessors, soretryAfter()
is called when thetextmacros
dependency is registered. That means theRegisterExtension()
for thetextcomp
will be interrupted at theRegisterDependencies()
call, and the rest won't be processed. Becausetextcomp
has already been pushed onto therequired
array, the retype setting will not run the main code forRegisterExtension
, andtextcomp
won't be properly added to the configuration. That means that the macros won't be defined, leading to unexpected errors reporting undefined macros.This PR resolves the problem by trapping the
retry
errors in theRegisterDependencies()
function and returning eithernull
if there were none, or a promise that resolves when all the dependencies are loaded. TheRegisterExtension
function then either waits for these those promises and adds the main extension, restarting the typesetting after that, or if there are no dependency promises, it adds the extension immediately and continues processing the expression. To make that easier, the main part ofRegisterExtension
has been broken out into a newProcessExtension()
function that can be called in either situation.Resolves issue mathjax/MathJax#3170.