Skip to content

Page load time: first visit and subsequent visits #2702

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

Open
2 of 12 tasks
xal-0 opened this issue May 7, 2025 · 7 comments
Open
2 of 12 tasks

Page load time: first visit and subsequent visits #2702

xal-0 opened this issue May 7, 2025 · 7 comments

Comments

@xal-0
Copy link

xal-0 commented May 7, 2025

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.

Image

Load optimization laundry list

Don't block rendering

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

  • Add content hash to search index (Load time optimization: download search index asynchronously; make cacheable #2700)

  • Host the official docs somewhere that allows us to set a reasonable
    Cache-Control: max-age

    GitHub pages adds a Cache-Control: max-age=600 header 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):
    Image

    Apologies for including this here but this is one of those things where it
    will drive you nuts once you notice it.

@fingolfin
Copy link
Collaborator

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).

@fingolfin
Copy link
Collaborator

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.

@mortenpi
Copy link
Member

mortenpi commented May 8, 2025

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?

@mortenpi
Copy link
Member

mortenpi commented May 8, 2025

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.

@cormullion
Copy link
Contributor

cormullion commented May 9, 2025

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... :)

@fonsp
Copy link

fonsp commented May 20, 2025

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.

@fonsp
Copy link

fonsp commented May 20, 2025

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants