picocms / Pico

Pico is a stupidly simple, blazing fast, flat file CMS.
http://picocms.org/
MIT License
3.81k stars 616 forks source link

Page with lots of plain HTML takes too long to load #624

Closed ohnonot closed 2 years ago

ohnonot commented 2 years ago

PicoCMS is 2.1.4, on Debian stable w. NGINX.

Performance is OK for ~150 blog pages.

There is however this one page that has +200kB of already syntax-highlighted HTML in it, that takes ~1.5s longer to load than "normal" pages.
I tried with cache en/disabled, single or all plugins en/disabled, a different theme... it's always the same.
That same page will load in less than 100ms if it's served on its own, without pico (i.e. save the page as rendered by pico).

Comparison (Firefox web inspector, page only, no assets):

I can shave off .1s with caching and for each plugin disabled, but the largest part of the loading time (1.5s) always remains.

The page is built like this:

Why would this take so long? Shouldn't Pico just ignore the \

...\
and shovel the HTML out as-is? What is it doing? Can I tell it to stop?
I feel like I'm missing something obvious here...

edit:
No PHP or server errors.

edit2:
Just for giggles, I wrapped the html in \

...\
which results in it not being displayed at all. This decreases loading times, but only by ~.5s, strangely. :confused:

edit3:
disabling parsedown extra also decreases loading times by ~.4s, but again, there's still too much activity around the large block of HTML, when there should be none.

edit4:
simply wrapping the html in a \

...\
seems to have the same effect as \
...\
, both rendering- and time-wise.

PhrozenByte commented 2 years ago

Performance with a lot of pages unfortunately is an ongoing issue for Pico - the 0.3s you see for other pages is not what we strive for. This only happens for websites with a lot of pages. 150 pages is "a lot" in Pico's terms, even though that we know that it definitely is not from a user's perspective, especially for blogs. So, we're very aware that Pico has some issues here and we want to solve them. However, I'm afraid that no solution was implemented yet :unamused:

Anyway, as far as I understand you right, your issue isn't really about the 0.3s for other pages, but about the 1.8s of the problematic page - which I can fully understand, this is unacceptable. However, I'm afraid that we can't do much about its cause: it's an issue with Parsedown, the Markdown parser we use. Parsedown utilizes regular expressions (regex) to parse Markdown contents. This yields great performance for most contents, but performs poorly especially for larger inputs (like +200 kB HTML :wink:). Parsedown Extra makes things worse: Parsedown Extra kinda was the "problem child" from the beginning and implements some things in a rather cumbersome way. To implement <div markdown="0"> it e.g. feeds the Markdown contents into a XML parser. This alone likely already explains the 0.4s gain you see when disabling Parsedown Extra...

Since you don't need Markdown parsing anyway, I'd recommend to not involve Parsedown at all. Depending on your contents there are multiple possible solutions. Am I right in assuming that this +200 kB HTML snippet is highlighted source code? If this is true, I'd suggest making it sort of an asset to include in your pages. The most simple solution is to create a themes/my_theme/snippets/ folder and paste the snippets in small .html files there. You can then add a YAML header with the snippet's filename (e.g. snippet: filename_of_the_snippet) and include it using {{ meta.snippet ? include("snippets/" ~ meta.snippet ~ ".html") }} in your Twig template. This can be further improved with plugins to move the snippets to different locations (e.g. below Pico's assets folder) and such, but I think you get the idea. If you don't want to involve Twig, you could utilize <iframe> to include the snippets in your pages. The snippets are just static HTML pages in separate files again.

If you provide some more info about what exact contents we're talking about and how you plan to manage them, we might find even better solutions :+1:

ohnonot commented 2 years ago

Thank you for the detailed explanation!

Sounds like there's a change away from Parsedown Extra coming up?
Personally I'd be happy to move to something different or feature-lesser if it means better performance and stability (now I think of it there were other small problems with it).

I didn't know embedding snippets is now part of PicoCMS, I was looking for a plugin to do just that and only found one that embeds markdown, which would defeat the purpose.
I haven't tried that yet because I found a caching plugin for PicoCMS - I actually found various versions, but the code is so simple that even I understand what it does, so I threw them all together - it's not a direct answer to my problem (which was indeed only about 1 page), it's even better.

PhrozenByte commented 2 years ago

Sounds like there's a change away from Parsedown Extra coming up?

Not really :see_no_evil: I'm afraid development of Parsedown 2.0 (which was about to resolve a lot of these issues) basically came to a stop. Parsedown still is the fastest solution for most use cases. Parsedown's performance is crucial for us, because we don't use caching by default. Thus there's not really an alternative...

I didn't know embedding snippets is now part of PicoCMS, I was looking for a plugin to do just that and only found one that embeds markdown, which would defeat the purpose. I haven't tried that yet because I found a caching plugin for PicoCMS - I actually found various versions, but the code is so simple that even I understand what it does, so I threw them all together - it's not a direct answer to my problem (which was indeed only about 1 page), it's even better.

It's not really an official feature of Pico, Pico is just flexible enough that you can basically do anything you want :smile:

Glad to hear that you found a even better solution :+1:

ohnonot commented 2 years ago

Am I right in assuming that this +200 kB HTML snippet is highlighted source code? If this is true, I'd suggest making it sort of an asset to include in your pages. The most simple solution is to create a themes/my_theme/snippets/ folder and paste the snippets in small .html files there. You can then add a YAML header with the snippet's filename (e.g. snippet: filename_of_the_snippet) and include it using {{ meta.snippet ? include("snippets/" ~ meta.snippet ~ ".html") }} in your Twig template.

I just wanted to add that this alone has decreased loading times by more than a second.

I still recommend my new & improved Pico Cache plugin!