[dotcom] Delete service worker, cache tldraw assets (#2552)
A few things happening here - Delete our service worker. Turns out that a couple of years back browsers decided that a service worker is no longer required for a PWA so you can just have the manifest and still install on the user's device. - Cache tldraw's assets as part of the dotcom vite asset pipeline. This allows them to participate in the asset coalescing (preserving old versions of asset files so old clients don't stop working when you deploy new versions of things, see https://github.com/tldraw/brivate/pull/3132 for more context). - Add a new 'imports.vite.js' file to the assets package, because we import a bunch of json translation files, and vite imports .json files as parsed json objects instead of string urls, and there's no good way to tell it not to. Even if there was we wouldn't want to impose that config on our users. So another way to tell vite to load any asset as a url string is to append `?url` to the end of the import path. That's what this file does. closes [#2486](https://github.com/tldraw/tldraw/issues/2486) ### Change Type - [x] `minor` — New feature [^1]: publishes a `patch` release, for devDependencies use `internal` [^2]: will not publish a new version ### Release Notes - Fix 'could not load assets' error that we often see on tldraw.com after a deploy
This commit is contained in:
parent
be927df935
commit
ade38247d8
16 changed files with 581 additions and 704 deletions
1
apps/dotcom/.gitignore
vendored
1
apps/dotcom/.gitignore
vendored
|
@ -13,7 +13,6 @@
|
|||
/out/
|
||||
|
||||
# PWA build artifacts
|
||||
/public/*.js
|
||||
/dev-dist
|
||||
|
||||
# production
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
"fast-glob": "^3.3.1",
|
||||
"lazyrepo": "0.0.0-alpha.27",
|
||||
"vite": "^5.0.0",
|
||||
"vite-plugin-pwa": "^0.17.0",
|
||||
"ws": "^8.16.0"
|
||||
},
|
||||
"jest": {
|
||||
|
|
38
apps/dotcom/public/manifest.webmanifest
Normal file
38
apps/dotcom/public/manifest.webmanifest
Normal file
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"name": "tldraw",
|
||||
"short_name": "tldraw",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#ffffff",
|
||||
"lang": "en",
|
||||
"scope": "/",
|
||||
"description": "a very good free whiteboard",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-maskable-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-maskable-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"orientation": "any"
|
||||
}
|
19
apps/dotcom/public/sw.js
Normal file
19
apps/dotcom/public/sw.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Self-destroying service worker
|
||||
// Taken from https://www.benjaminrancourt.ca/how-to-remove-a-service-worker/
|
||||
// Inspired from https://github.com/NekR/self-destroying-sw
|
||||
self.addEventListener("install", (event) => {
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
self.addEventListener("activate", (event) => {
|
||||
self.registration
|
||||
.unregister()
|
||||
.then(() => self.clients.matchAll())
|
||||
.then((clients) => {
|
||||
clients.forEach((client) => {
|
||||
if (client.url && "navigate" in client) {
|
||||
client.navigate(client.url);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,8 +1,7 @@
|
|||
import { Editor, Tldraw } from '@tldraw/tldraw'
|
||||
import { useCallback, useEffect } from 'react'
|
||||
import { useCallback } from 'react'
|
||||
import { assetUrls } from '../utils/assetUrls'
|
||||
import { createAssetFromUrl } from '../utils/createAssetFromUrl'
|
||||
import { isPreviewEnv } from '../utils/env'
|
||||
import { linksUiOverrides } from '../utils/links'
|
||||
import { DebugMenuItems } from '../utils/migration/DebugMenuItems'
|
||||
import { LocalMigration } from '../utils/migration/LocalMigration'
|
||||
|
@ -14,8 +13,6 @@ import { ShareMenu } from './ShareMenu'
|
|||
import { SneakyOnDropOverride } from './SneakyOnDropOverride'
|
||||
import { ThemeUpdater } from './ThemeUpdater/ThemeUpdater'
|
||||
|
||||
const TLDRAW_REDIRECTED_TO_SIGN_IN = 'tldraw-redirected-to-sign-in'
|
||||
|
||||
export function LocalEditor() {
|
||||
const handleUiEvent = useHandleUiEvents()
|
||||
const sharingUiOverrides = useSharing({ isMultiplayer: false })
|
||||
|
@ -25,18 +22,6 @@ export function LocalEditor() {
|
|||
editor.registerExternalAssetHandler('url', createAssetFromUrl)
|
||||
}, [])
|
||||
|
||||
// Redirect to sign in if in preview mode
|
||||
useEffect(() => {
|
||||
if (isPreviewEnv) {
|
||||
const alreadyRedirected = localStorage.getItem(TLDRAW_REDIRECTED_TO_SIGN_IN)
|
||||
// We only want to redirect once so that we can still test the editor
|
||||
if (alreadyRedirected && alreadyRedirected === 'true') return
|
||||
localStorage.setItem(TLDRAW_REDIRECTED_TO_SIGN_IN, 'true')
|
||||
const url = new URL(window.location.href)
|
||||
window.location.assign(`${url.origin}/sign-in`)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="tldraw__editor">
|
||||
<Tldraw
|
||||
|
|
|
@ -80,3 +80,15 @@ createRoot(document.getElementById('root')!).render(
|
|||
<VercelAnalytics debug={false} />
|
||||
</HelmetProvider>
|
||||
)
|
||||
|
||||
try {
|
||||
// we have a dummy service worker that unregisters itself immediately
|
||||
// this was needed to remove the service worker we used to have from the cache
|
||||
// we can remove this if we ever need a service worker again, or if enough time passes that
|
||||
// anybody returning to tldraw.com should not have a service worker running
|
||||
navigator.serviceWorker.register('/sw.js', {
|
||||
scope: '/',
|
||||
})
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
|
|
@ -1,21 +1,7 @@
|
|||
// eslint-disable-next-line import/no-internal-modules
|
||||
import type { AssetUrls } from '@tldraw/assets/types'
|
||||
// eslint-disable-next-line import/no-internal-modules
|
||||
import { getAssetUrlsByMetaUrl } from '@tldraw/assets/urls'
|
||||
import { isProductionEnv } from './env'
|
||||
import { getAssetUrlsByImport } from '@tldraw/assets/imports.vite'
|
||||
|
||||
const _assetUrls = getAssetUrlsByMetaUrl()
|
||||
|
||||
export const assetUrls: AssetUrls = isProductionEnv
|
||||
? _assetUrls
|
||||
: // let's try out shantell sans 'informal' style for a bit on staging/dev
|
||||
{
|
||||
..._assetUrls,
|
||||
fonts: {
|
||||
..._assetUrls.fonts,
|
||||
draw: '/Shantell_Sans-Tldrawish.woff2',
|
||||
},
|
||||
}
|
||||
export const assetUrls = getAssetUrlsByImport()
|
||||
|
||||
let didPreloadIcons = false
|
||||
async function preloadIcons() {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import react from '@vitejs/plugin-react-swc'
|
||||
import { config } from 'dotenv'
|
||||
import { defineConfig } from 'vite'
|
||||
import { VitePWA, VitePWAOptions } from 'vite-plugin-pwa'
|
||||
|
||||
config({
|
||||
path: './.env.local',
|
||||
|
@ -11,57 +10,9 @@ export const getMultiplayerServerURL = () => {
|
|||
return process.env.MULTIPLAYER_SERVER?.replace(/^ws/, 'http') ?? 'http://127.0.0.1:8787'
|
||||
}
|
||||
|
||||
const pwaConfig: Partial<VitePWAOptions> = {
|
||||
registerType: 'autoUpdate',
|
||||
// Make sure the service worker doesn't try to handle API requests
|
||||
workbox: {
|
||||
navigateFallbackDenylist: [/^\/api/],
|
||||
runtimeCaching: [{ handler: 'NetworkFirst', urlPattern: /\/.*/ }],
|
||||
},
|
||||
// Uncomment this to test the PWA install flow locally
|
||||
// devOptions: { enabled: true },
|
||||
manifest: {
|
||||
name: 'tldraw',
|
||||
short_name: 'tldraw',
|
||||
description: 'a very good free whiteboard',
|
||||
|
||||
icons: [
|
||||
{
|
||||
src: '/android-chrome-512x512.png',
|
||||
sizes: '512x512',
|
||||
type: 'image/png',
|
||||
purpose: 'any',
|
||||
},
|
||||
{
|
||||
src: '/android-chrome-maskable-512x512.png',
|
||||
sizes: '512x512',
|
||||
type: 'image/png',
|
||||
purpose: 'any maskable',
|
||||
},
|
||||
{
|
||||
src: '/android-chrome-192x192.png',
|
||||
sizes: '192x192',
|
||||
type: 'image/png',
|
||||
purpose: 'any',
|
||||
},
|
||||
{
|
||||
src: '/android-chrome-maskable-192x192.png',
|
||||
sizes: '192x192',
|
||||
type: 'image/png',
|
||||
purpose: 'any maskable',
|
||||
},
|
||||
],
|
||||
theme_color: '#ffffff',
|
||||
background_color: '#ffffff',
|
||||
start_url: '/',
|
||||
display: 'standalone',
|
||||
orientation: 'any',
|
||||
},
|
||||
}
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react({ tsDecorators: true }), VitePWA(pwaConfig)],
|
||||
plugins: [react({ tsDecorators: true })],
|
||||
publicDir: './public',
|
||||
build: {
|
||||
// output source maps to .map files and include //sourceMappingURL comments in JavaScript files
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue