Grant Application: swap.cow.fi performance - prerender html

Grant Title

Grant Application: swap.cow.fi performance - prerender html

Author(s)

Senior UI Developer - Konstantin Barabanov: ( crutch12 (Konstantin Barabanov) · GitHub )
Main Point of Contact - Telegram: Contact @criitch

Experiences and qualifications

  • 8+ years of web development experience (one year with web3 projects)
  • have a lot of experience with react/vue apps optimization, SSR and MF usage
  • already did some contributions to swap.cow.fi repo (see issues)
  • more info about me is available here (rus.) and on github

Grant Description

Currently, the swap app renders most content at runtime, which may lead to slower first paint and FOUC (flash of unstyled content). By prerendering the main elements, users can experience faster loads.

I want to implement partial prerendering for the swap app’s index.html at build time, similar to SSR/SSG. The goal is to render the <Main> component (without routes) along with app’s styled <style> tags, improving initial load performance and enabling better theming support.

These changes will affect output index.html file, but won’t require SSR server. So this approach is similar to SSG, but since we use <HashRouter>, we don’t want to prerender routes (pages), only “main layout”.

Features/tasks:

  • Prerender index.html at build time
  • Keep same build time and bundle size (no server.entry.js required)
  • Mock any required browser api during prerender
  • Render <Main> component without route-specific content
  • Include styled <style> tags for non-page components
  • Optimize theme usage for dark/light modes, so user could see correct styles immediately
  • Provide empty i18n messages during prerender (e.g. whitespace placeholders)
  • Provide prefetched i18n messages during client render (currently,i18n Provider rerenders the whole application after messages fetching, so we have extra rerender)
  • No hydration needed, just recreate #root dom node when client is ready (make sure there is no manual manipulation with #root)

Expected impact:

  • Faster first paint and perceived performance
  • Improved user experience with instant styled content
  • Better foundation for future SSR-like features

We don’t need SSR server, thus it’s still possible to host it with IPFS.

Type of Grant

Milestones-based

Milestones

Milestones Title Duration Funding request
Milestone 0 Proof of Concept (PoC), prepare PageSpeed Insights reports COMPLETED 500 xDAI
Milestone 1 Mock any required browser API during prerender 0.5d 0
Milestone 2 Setup vite config for prerendering 1d 0
Milestone 3 Adapt components to be used in ssr-like mode (and skip unwanted) 1d 0
Milestone 4 Render client application with prefetched i18n messages 0.5d 0
Milestone 5 Provide i18n messages during prerender 0.5d 0
Milestone 6 UI light/dark theme adaption for prerendered components 1d 0
Milestone 7 Adapt another ui apps to use modified libs components 1d 0
Milestone 8 Testing 1d 0
Milestone 9 Update contribution docs 0.1d 0
Milestone 10 Provide PR 0d 800 xDAI
Milestone 11 Fix found related problems unknown 0

Length

I’m ready to start as soon as the grant is approved. I’m not gonna work full time on it, but believe I can complete it in ~2 weeks after approve.

Funding Request

1,300 xDAI for the whole feature.

Gnosis Chain Address

0xd26ecc4457eb51cde9a5d44d316b3e83d60f2efb

Other Information

I’ve already did a prototype (PoC) and will provide PageSpeed Insights reports in the first comment.

As you can see, such metrics as First Contentful Paint, Speed Index, Largest Contentful Paint are multiple times lower with partial prerendering feature.

I don’t host prototype anywhere, but can share temporal link with anyone on demand.

Terms and Conditions

By submitting this grant application, I acknowledge and agree to be bound by the CoW DAO Participation Agreement and the CoW DAO Grant Agreement Terms.

PageSpeed Insights reports, made in same conditions with temporal web servers

Without prerender feature:

With prerender feature:

Reports screenshots:

You can also check temporal links, while they are alive:

UPD: deployed to vercel

Thanks @crutch12 !
I think this is a good idea and will enhance users’ experience!

I’m not sure about funding, from my perspective this task is about 5-6 hours, so it supposed to be ~500$.

Thanks @shoom3301 for weighing in on this. We will reconsider.

@crutch12 After some discussion with regards to the time taken if done by the internal team, the Grants Committee would be unwilling at the current quoted price in that it would make more sense for this to be done by the internal team as opposed to an external contributor. Can you please revise accordingly and make sure that the application is in accordance with the template.

mfw.

Thanks for reply, @shoom3301

Just wanted to say, that PoC took me much more time than 5-6 hours.

Main problems were

  • source files are not adapted for ssr environment and you have to mock (or change) it for every error case
  • moreover some components use restricted api (e.g. createPortal) or just can’t be rendered in ssr (e.g. then update the state during initial render), so ReactServer.renderToString fails with different errors
  • vite doesn’t allow reuse browser.entry.js files for ssr build, so I had to write own plugin and mock a lot of browser’s environment, to make it work. At first I couldn’t use vite-prerender-plugin because it swallows the error, but then, when I adapted src file to work in ssr, I finally could migrate to the plugin
  • initial render resulted
    html, so I had to debug which component returns null and how can we fix it (the fix is - preload i18n messages before render)
  • theme usage. for Layout components we can’t use isDarkMode, we should (1) detect preffered dark/light mode before render and (2) replace runtime logic with css selectors (e.g. .dark-theme & { background: var(${UI.COLOR_PAPER_DARKER}))
  • i18n usage. we have to detect and load messages before initial render
  • it also took time to think over different locales prerender and handle it with service worker, but decided to postpone it’s implementation
  • react 19 has a bug, that it doesn’t allow to close node.js process because of how renderToString work (see here: Plugin causes Vite to hang indefinitely after build with React 19.0.0 · Issue #3 · preactjs/vite-prerender-plugin · GitHub)

Since it’s production build, it’s not that easy to inspect the build/runtime problems immediately :melting_face:

Thank you for the clarification @crutch12 !
Sorry, I don’t think the feature is worth it for now, because swap.cow.fi is a reach SPA and not required to have such advanced optimisations.
Anyway, thanks for proposing! I see you have another application, which looks very good to me!

@mfw78 thanks for reply

Could you explain please, what do you mean?
I can reconsider the quoted price, but I don’t really understand comment about template.
Are there some issues in the application?

It’s just a general comment to make sure it’s correct (we have had issues where grants get to snapshot and they aren’t in accordance with the template, and we have to then get them to resubmit etc). It’s more just a common reminder than any specific comment on the application itself.