Add defer-attributes to all javascripts if possible. Deferring javascript-loading and execution makes the browser start HTML-parsing, rendering and painting.
So some static interim content may be shown pretty early in (or even before) the discourse booting process. This should do for a faster user-perceived page loading speed on first page load.
As of Chrome 88 this is luckily not true anymore!
Didn’t know about this either until now. :))
"Before this change, an element being removed caused it to no longer be considered a valid LCP candidate. […] After this change, an element being removed is still considered a valid LCP candidate. "
“The change to include content which is later removed from the DOM as possible largest contentful paints will improve Largest Contentful Paint times on sites which have images [for Discourse:text elements] of the same size inserted multiple times. This is a common pattern for carousels, as well as some JavaScript frameworks which do server-side rendering.”
0s-2s - blank screen:
WebPageTest ignores defer for JavaScript and downloads all the JavaScripts before doing a first paint - this works correctly on a real device.
2.5s - LCP: static content from server-rendering
3.5s - Visual Change: logo loaded
6.5s - Visual Change: content from EmberJs rendering
7s - Visual complete
PageSpeed Insights
Largest Contentful Paint element
PageSpeed correctly identifies the static text-node from server-rendering as FCP LCP element: div.row > div.topic-body > div.post > p
Note on First Input Delay: Here I clicked on background immediately when the static content was first visible. Add my reaction time on top of this FID.
Extra note on percentiles below the bars in these graphs:
The percentiles are not that relevant as they only compare the meassured values with the origin values. The origin is a TYPO3 webpage with a subfolder install of Discourse.
I totally agree Discourse is very slow JS Heavy web-app, if we can defer CSS/JS FILES, it will hugely help speed up LCP, FCP, FID,CLS.
Would really help to see this getting live, we and many other people are facing this issue. All discourse sites are failing at Core Web Vitals. If we server a fast STATIC HTML page to users 1st time and or defer all JS/CSS logic in 1st initial load, and this way we can speed up all pages and pass CWV scores! excited to see this live on core discourse update.
All discourse sites Google rankings are declining due to sites not passing Core Web Vitals.
We’re open to experimenting with this in core. The ‘flash’ of differently-styled content can be a little disconcerting, so we’d like to start with it behind a default-disabled “experimental” site setting to start with. That way, Site admins can choose to enable it if they want to.
Are you able to try adding a site setting in your PR @rrit? It would also be good to add some RSpec tests to verify the behaviour with the setting enabled / disabled.
Doesn’t that means that we can simply put a fullscreen spinner (that has 100% width and 100% height) on the page rendered by the server, and replace it by the Ember app when it finally boots to get an extremely low LCP?
We could make this spinner a SVG that mimics the Discourse UI so the transition is smoother and less FOUC-like.
I had to disable defer tag for QUnit Test Runner: app/views/qunit/index.html.erb
Before QUnit Tests did still run with the feature flag "javascript defer" = false. And now the tests run also with "javascript defer" = true.
For text elements, only the size of their text nodes is considered (the smallest rectangle that encompasses all text nodes).
For all elements, any margin, padding, or border applied via CSS is not considered.
That’s why the static text-node must be rendered exactly the same size as the EmberJs text-node.
Or even slightly bigger by increasing the line-height.
E.g. if the width of the text-nodes doesn’t match, there are a lot of geometric cases introduced by different linebreaks where the static text-node becomes smaller than the EmberJs-one.
In the POC there are two features combined - shall we split them into two experimental feature flags?
JavaScript with defer-tag (feature flag in settings dashbord) (hidden feature flag as a container rebuild or theme cache flush is needed for this) ← Fix: hot-switching with cache
Showing static content in topic view (feature flag in settings dashbord)
Of course the full impact on LCP is only accomplished by using both: FCP: static content
There might be Discourse instances where plugins or theme components fail on the JS defering. By splitting these feature, they can have a small gain on the static content without defering JS: FCP: static content without JS defer
Let’s wait another 7-14 days to hopefully see more improvements for mobile pages as the values are averaged over the last 28 days - only 12 days counting with the POC applied right now.
@rrit 사이트에 있는 데이터를 공유해 주셔서 감사합니다! 내부에서 이 문제에 대해 논의해 보았고, 안타깝게도 현재로서는 Discourse 코어에 이 기능을 추가하지 않을 예정입니다.
공유해 주신 Web Vital 지표는 매우 인상적이지만, ‘크롤러 뷰’ 콘텐츠가 잠시 노출되는 현상은 좋은 사용자 경험을 제공하지 않습니다. 적용하신 스타일링 변경 사항은 확실히 도움이 되지만, 커스텀 스타일링이 있는 모든 Discourse 사이트마다 조정이 필요할 것입니다.
우리의 장기적인 목표는 Ember FastBoot와 같은 기술을 사용하여 진정한 서버 측 렌더링을 구현하는 것입니다. 이론적으로 이는 여러분이 측정한 것과 동일한 통계적 개선 효과를 제공하면서도 매끄러운 사용자 경험을 제공할 것입니다. 우리는 이 목표를 향해 노력을 집중하고 싶습니다.
그러나 Discourse는 확장성이 매우 뛰어나므로, 여러분의 아이디어를 Discourse 플러그인으로 구현한 후 Customization > Plugin 채널에서 공유하는 것이 충분히 가능할 것이라고 생각합니다.
코어 PR에서 가장 큰 변경 사항은 스크립트 태그에 defer 속성을 추가한 것입니다. 플러그인에서 이 모든 부분을 오버라이드하는 것은 매우 어려울 것입니다. 그러나 미들웨어 기반 접근 방식을 사용하면 동일한 결과를 달성할 수 있다고 생각합니다. 유사한 문제를 설명하는 블로그 포스트를 찾았습니다:
이 기술을 사용하면 text/html 응답을 확인하고, 이를 파싱한 후 필요한 곳에 defer 속성을 추가하는 미들웨어를 작성할 수 있습니다.
플러그인에서 미들웨어를 추가하는 방법은 다음과 같습니다:
# name: my-plugin
# about: My plugin description
# version: 1.0
# url: https://example.org
require_relative "lib/script_defer_middleware"
on(:after_initializers) do
Rails.configuration.middleware.use(ScriptDeferMiddleware)
end
플러그인 기반 접근 방식에서 장애물에 부딪히면 여기에 게시해 주세요. 기꺼이 올바른 방향으로 안내해 드리겠습니다.