Remix is fast by default, but with a few edits to root.tsx, you can make it even faster!
For a refresher on Core Web Vitals, check out the free course from WebPageTest:
There's no magic here: Remix simply makes it easy to implement good practices that would work on any website.
Unblocking CSS
In Remix, we usually add CSS as stylesheet links:
import
styles
from
"~/styles/dashboard.css"
;
export
const
links
:
LinksFunction
=
(
)
=>
{
return
[
{
rel
:
"stylesheet"
,
href
:
styles
}
]
}
However, doing this makes stylesheets a render-blocking resource:
By default, HTML rendering is paused until CSS stylesheets have streamed in!
Fix this behavior by linking the stylesheets as preloaded resources first:
Link types: preload
This ensures they are available earlier and are less likely to block the page's render, improving performance.
Your updated links export should look something like this:
import
styles
from
"~/styles/dashboard.css"
;
export
const
links
:
LinksFunction
=
(
)
=>
{
return
[
{
rel
:
"preload"
,
href
:
styles
,
as
:
"style"
}
,
{
rel
:
"stylesheet"
,
href
:
styles
}
,
]
}
How the links export looks on Nalu's app/root.tsx file:
import
tailwindStylesheetUrl
from
"~/styles/tailwind.css"
;
import
fonts
from
"~/styles/fonts.css"
;
import
rootStyles
from
"~/styles/root.css"
;
import
balloonCSS
from
"~/styles/balloon.min.css"
;
export
const
links
:
LinksFunction
=
(
)
=>
{
return
[
{
rel
:
"preload"
,
href
:
tailwindStylesheetUrl
,
as
:
"style"
}
,
{
rel
:
"preload"
,
href
:
fonts
,
as
:
"style"
}
,
{
rel
:
"preload"
,
href
:
rootStyles
,
as
:
"style"
}
,
{
rel
:
"preload"
,
href
:
balloonCSS
,
as
:
"style"
}
,
//Preload CSS to makes it nonblocking
{
rel
:
"stylesheet"
,
href
:
tailwindStylesheetUrl
}
,
{
rel
:
"stylesheet"
,
href
:
fonts
}
,
{
rel
:
"stylesheet"
,
href
:
rootStyles
}
,
{
rel
:
"stylesheet"
,
href
:
balloonCSS
}
,
]
;
}
;
Preconnecting resources
Everything hosted outside your app's domain requires a separate handshake, but you can speed up that process with preconnect links.
WPT Report provides a list of content domains used by your website.
Based on the report, we can add the following to app/root.tsx:
export
const
links
:
LinksFunction
=
(
)
=>
{
return
[
//Pre-connect CDN to improve first bits
{
rel
:
"preconnect"
,
href
:
"https://core-cdn.nalu.wiki"
}
,
{
rel
:
"preconnect"
,
href
:
"https://wiki-cdn.nalu.wiki"
}
,
{
rel
:
"preconnect"
,
href
:
"https://clerk.nalu.wiki"
}
,
{
rel
:
"preconnect"
,
href
:
"https://fonts.gstatic.com"
,
crossOrigin
:
"anonymous"
}
,
]
}
The crossOrigin attribute is necessary when loading third-party fonts, see Michael Crenshaw article for details.
Preconnects are not free.
Don't pre-connect to domains unless it'll be used within 10 seconds of request!
Third-Party Scripts
Third-Party Scripts really slow you down. Delete them if you can!
Try the following if that's not an option:
- Light Alternatives: On Nalu, we used self-hosted Plausible.js for analytics instead of Google Analytics.
- Off-load the Work: Move long-running script to a Web Worker with Partytown to unblock your site's main JS thread.
- Defer: Add defer tag to the <script> to lower its Browser priority.
How analytics look on Nalu:
<
script
defer
data-domain
=
"nalu.wiki"
src
=
"https://a.nalu.media/js/plausible.js"
/
>
Additionally, we also add third-party domains (see above) to further reduce the impact on our users.
Optimizing Fonts
Optimizing Fonts is an important topic that deserves a follow-up article:
Further Reading
Web Optimization could easily be a developer's full-time job. Hopefully, these tips will help clear some low-hanging fruits.
- Web Performance Course by WebPageTest
- Optimziing Third Party Scripts by Google
- Creating font subsets by Markos Konstantopoulos
I'll like to acknowledge Sergio Xalambrà and Tiger Abrodi for their help and support in the development of this post.
Hang out with these cool people on the Remix Discord!
What is Nalu?
Nalu is a wiki engine built on Remix and MDX.