assets: preload fonts (#3927)

Looking at the waterfall of fonts/images/etc. we wanted the "Loading
assets..." bit to commence earlier so it's not fighting for bandwidth
with the icons loading all at the same time.

This writes to the index.html file to start preloading the fonts we
need.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [x] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [x] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know


### Release Notes

- Perf: improve font loading timing on dotcom.

---------

Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
This commit is contained in:
Mime Čuvalo 2024-06-16 17:02:34 +01:00 committed by GitHub
parent 6d2f963f91
commit cbf7c2c605
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 59 additions and 9 deletions

View file

@ -27,6 +27,10 @@
<link rel="apple-touch-icon" sizes="167x167" href="/apple-touch-icon-167x167.svg" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.svg" />
<!-- $PRELOADED_FONTS -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:url" content="https://www.tldraw.com/" />
<meta name="twitter:title" content="tldraw" />

View file

@ -1,5 +1,5 @@
import glob from 'fast-glob'
import { mkdirSync, writeFileSync } from 'fs'
import { mkdirSync, readFileSync, writeFileSync } from 'fs'
import { exec } from '../../../scripts/lib/exec'
import { Config } from './vercel-output-config'
@ -56,6 +56,32 @@ async function build() {
await exec('cp', ['-r', 'dist', '.vercel/output/static'])
await exec('rm', ['-rf', ...glob.sync('.vercel/output/static/**/*.js.map')])
// Add fonts to preload into index.html
const assetsList = (await exec('ls', ['-1', 'dist/assets'])).split('\n').filter(Boolean)
const fontsToPreload = [
'Shantell_Sans-Tldrawish',
'IBMPlexSerif-Medium',
'IBMPlexSans-Medium',
'IBMPlexMono-Medium',
]
const indexHtml = await readFileSync('.vercel/output/static/index.html', 'utf8')
await writeFileSync(
'.vercel/output/static/index.html',
indexHtml.replace(
'<!-- $PRELOADED_FONTS -->',
fontsToPreload
.map(
(font) => `<link
rel="preload"
href="/assets/${assetsList.find((a) => a.startsWith(font))}"
as="font"
type="font/woff2"
/>`
)
.join('\n')
)
)
const multiplayerServerUrl = getMultiplayerServerURL() ?? 'http://localhost:8787'
writeFileSync(

View file

@ -1,6 +1,7 @@
import {
ContextMenu,
DefaultContextMenuContent,
DefaultSpinner,
ErrorScreen,
LoadingScreen,
TldrawEditor,
@ -38,7 +39,11 @@ export default function ExplodedExample() {
}
if (!assetLoading.done) {
return <LoadingScreen>Loading assets...</LoadingScreen>
return (
<LoadingScreen>
<DefaultSpinner />
</LoadingScreen>
)
}
return (

View file

@ -1,6 +1,6 @@
import { throttle } from 'lodash'
import { useLayoutEffect, useState } from 'react'
import { Tldraw, createTLStore, getSnapshot, loadSnapshot } from 'tldraw'
import { DefaultSpinner, Tldraw, createTLStore, getSnapshot, loadSnapshot } from 'tldraw'
import 'tldraw/tldraw.css'
// There's a guide at the bottom of this file!
@ -52,7 +52,9 @@ export default function PersistenceExample() {
if (loadingState.status === 'loading') {
return (
<div className="tldraw__editor">
<h2>Loading...</h2>
<h2>
<DefaultSpinner />
</h2>
</div>
)
}

View file

@ -3,6 +3,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'
import {
DefaultHelpMenu,
DefaultHelpMenuContent,
DefaultSpinner,
Editor,
ErrorBoundary,
TLComponents,
@ -90,7 +91,9 @@ export const TldrawWrapper = () => {
}, [setTldrawInnerProps])
return tldrawInnerProps === null ? (
<FullPageMessage>Loading</FullPageMessage>
<FullPageMessage>
<DefaultSpinner />
</FullPageMessage>
) : (
<TldrawInner {...tldrawInnerProps} />
)

View file

@ -3,8 +3,8 @@ export function DefaultSpinner() {
return (
<svg width={16} height={16} viewBox="0 0 16 16">
<g strokeWidth={2} fill="none" fillRule="evenodd">
<circle strokeOpacity={0.25} cx={8} cy={8} r={7} stroke="var(--color-text-1)" />
<path strokeLinecap="round" d="M15 8c0-4.5-4.5-7-7-7" stroke="var(--color-text-1)">
<circle strokeOpacity={0.25} cx={8} cy={8} r={7} stroke="currentColor" />
<path strokeLinecap="round" d="M15 8c0-4.5-4.5-7-7-7" stroke="currentColor">
<animateTransform
attributeName="transform"
type="rotate"

View file

@ -1,6 +1,7 @@
import {
DEFAULT_SUPPORTED_IMAGE_TYPES,
DEFAULT_SUPPORT_VIDEO_TYPES,
DefaultSpinner,
Editor,
ErrorScreen,
Expand,
@ -130,7 +131,11 @@ export function Tldraw(props: TldrawProps) {
return <ErrorScreen>Could not load assets. Please refresh the page.</ErrorScreen>
}
if (!preloadingComplete) {
return <LoadingScreen>Loading assets...</LoadingScreen>
return (
<LoadingScreen>
<DefaultSpinner />
</LoadingScreen>
)
}
return (

View file

@ -1,4 +1,5 @@
import {
DefaultSpinner,
Editor,
ErrorScreen,
LoadingScreen,
@ -175,7 +176,11 @@ export const TldrawImage = memo(function TldrawImage(props: TldrawImageProps) {
}
if (!preloadingComplete) {
return <LoadingScreen>Loading assets...</LoadingScreen>
return (
<LoadingScreen>
<DefaultSpinner />
</LoadingScreen>
)
}
return (