Documenter.jl
Documenter.jl copied to clipboard
Page load time: first visit and subsequent visits
Even with fast internet, https://docs.julialang.org/ can take several seconds on first load, and almost as long for subsequent loads. This issue will attempt to summarize the ways we can improve this.
Load optimization laundry list
Don't block rendering
- [x] Don't block waiting for search index (#2700)
- [ ] Don't block waiting for fontawesome, other font CSS
- [ ] Remove require.min.js entirely (#2158)
- [ ] Don't block for various other "info" scripts (
siteinfo.js,versions.js) - [ ] Rendering should not block while loading themes that are not in use.
- [ ] Set
font-display: swap;for all fonts
Reduce size of assets
-
[ ] Don't pull in all of fontawesome (260 KiB) for just a handful of icons (consider using svg with
<symbol>definitions) -
[ ] Font subsetting
We pull in JuliaMono (almost 1 MiB) for good Unicode coverage, but most pages have only ASCII. The CDN we use should serve properly subset fonts so only the necessary parts are downloaded. (Example: Lato from Google Fonts).
-
[ ] Render math before serving
Could be undesirable to pull in KaTeX and a JavaScript interpreter as a depdency of Documenter.jl, but it's entirely possible to render all the math while building the docs and avoid the KaTeX script dependency entirely.
Cache more
-
[x] Add content hash to search index (#2700)
-
[ ] Host the official docs somewhere that allows us to set a reasonable
Cache-Control: max-ageGitHub pages adds a
Cache-Control: max-age=600header to everything. This hurts return visits to the docs more than almost anything els: if it has been more than 10 minutes since your last visit, we must validate everything in the cache. Unfortunately this is also something we have no control over.
Other random nits
-
[ ] Don't synthesize bold Lato
Compare synthesized bold on the left, real bold on the right (Chromium macOS):
Apologies for including this here but this is one of those things where it will drive you nuts once you notice it.
Thanks for looking into this!
Regarding fontawesome, I guess one could resurrect PR #2657 for partial progress towards getting rid of it. I can do that if there is interest (still have it in my local git repo).
Regarding Host the official docs: if this is in reference to https://docs.julialang.org/ then this is out of scope for this repository and should be raised on the main Julia repository.
On the topic of "font subsetting": are you suggesting we should split the JuliaMono into separate font files, for each class of symbols and serve them separately? And then the browser could only fetch the relevant .woff2 files, depending on what characters it actually needs to render on the page? I.e. for the sake of argument, if the page doesn't have any characters from the cyrillic Unicode range, then it will never try to download the juliamono-cyrillic.woff2 subset?
If so, this also seems like an upstream ask for https://github.com/cormullion/juliamono, to ensure that JuliaMono is distributed in a split way?
Don't block for various other "info" scripts (
siteinfo.js,versions.js)
I'm not against this necessarily, but these are really tiny files, so I am not sure it's worth the effort. If we do make these load async, we'd also have to make some of the UI (version selector and outdated docs warning) also wait for these to load.
Render math before serving
We already have an opt-in feature to do this for code highlighting. I think it might be good to have this as an opt-in feature for math-heavy manuals.
Rendering should not block while loading themes that are not in use.
This is a very reasonable idea, but I am not sure how easy it is to do, given our slightly complex theme switching mechanic. Any ideas if can inject the async attribute dynamically after the fact? But if it can be done, it would be great.
When Fons was developing Pluto.jl, he asked for a reduced-glyph subset of JuliaMono. This is still released as
https://github.com/cormullion/juliamono/blob/master/webfonts/JuliaMono-RegularLatin.woff2
and
https://github.com/cormullion/juliamono/blob/master/webfonts/JuliaMono-BoldLatin.woff2
These have 630 glyphs each and are about 27KB.
I think his idea was to have this font downloaded initially, and then have the full version downloaded later. I don't know how or whether he did it though.
I suppose you could do font subsetting by making Documenter.jl generate a list of all used Unicode glyphs as part of the build process, and then conflate them into a set of ranges suitable for writing out as a custom CSS rule:
@font-face {
unicode-range: U+0000-00FF, U+02BB-02BC,...;
}
If so, this also seems like an upstream ask for https://github.com/cormullion/juliamono, to ensure that JuliaMono is distributed in a split way?
This is unlikely to happen... :)
In Pluto we optimized the JuliaMono font loading quite a bit, in the end we settled on this:
editor.css
@import url("./fonts/juliamono.css");
:root {
--julia-mono-font-stack: JuliaMono, Menlo, "Roboto Mono", "Lucida Sans Typewriter", "Source Code Pro", monospace;
}
an-element-that-uses-juliamono {
font-family: var(--julia-mono-font-stack);
}
fonts/juliamono.css
@font-face {
font-family: JuliaMono;
src: url("https://cdn.jsdelivr.net/gh/cormullion/[email protected]/webfonts/JuliaMono-RegularLatin.woff2") format("woff2");
font-display: swap;
font-weight: 400;
unicode-range: U+00-7F; /* Basic Latin characters */
}
@font-face {
font-family: JuliaMono;
src: url("https://cdn.jsdelivr.net/gh/cormullion/[email protected]/webfonts/JuliaMono-BoldLatin.woff2") format("woff2");
font-display: swap;
font-weight: 700;
unicode-range: U+00-7F; /* Basic Latin characters */
}
@font-face {
font-family: JuliaMono;
src: url("https://cdn.jsdelivr.net/gh/cormullion/[email protected]/webfonts/JuliaMono-Regular.woff2") format("woff2");
font-display: swap;
font-weight: 400;
}
@font-face {
font-family: JuliaMono;
src: url("https://cdn.jsdelivr.net/gh/cormullion/[email protected]/webfonts/JuliaMono-Bold.woff2") format("woff2");
font-display: swap;
font-weight: 700;
}
@font-face {
font-family: JuliaMono;
src: url("https://cdn.jsdelivr.net/gh/cormullion/[email protected]/webfonts/JuliaMono-RegularItalic.woff2") format("woff2");
font-display: swap;
font-weight: 400;
font-style: italic;
}
Swap
The most important optimization is font-display: swap together with a fine-tuned fallback font stack. We spent some time on Windows, Mac and Linux finding fallback fonts that look very close to JuliaMono, resulting in --julia-mono-font-stack.
Subset
The regular and bold typefaces have a latin subset. If you have a page that only uses glyphs from this subset, the browser will only load the latin woff2 files which are much smaller.
Good CDN
We use jsdelivr with version-pinning to get good caching across pages. I think we also preload/prefetch the juliamono woff2 files from our index page.
Btw @xal-0 thanks for your work, this is a really good list, spot on! I think the performance and look of the Julia doc pages is super important, it reflects the quality of our work.