2024-01-16 14:38:05 +00:00
|
|
|
import glob from 'fast-glob'
|
|
|
|
import { mkdirSync, writeFileSync } from 'fs'
|
|
|
|
import { exec } from '../../../scripts/lib/exec'
|
|
|
|
import { Config } from './vercel-output-config'
|
|
|
|
|
|
|
|
import { config } from 'dotenv'
|
2024-02-26 12:30:35 +00:00
|
|
|
import json5 from 'json5'
|
2024-01-16 14:38:05 +00:00
|
|
|
import { nicelog } from '../../../scripts/lib/nicelog'
|
2024-02-26 12:30:35 +00:00
|
|
|
|
|
|
|
import { T } from '@tldraw/validate'
|
|
|
|
|
|
|
|
// We load the list of routes that should be forwarded to our SPA's index.html here.
|
|
|
|
// It uses a jest snapshot file because deriving the set of routes from our
|
|
|
|
// react-router config works fine in our test environment, but is tricky to get running in this
|
|
|
|
// build script environment for various reasons (no global React, tsx being weird about decorators, etc).
|
|
|
|
function loadSpaRoutes() {
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
|
|
const routesJson = require('../src/__snapshots__/routes.test.tsx.snap')['the_routes 1']
|
|
|
|
const routes = T.arrayOf(
|
|
|
|
T.object({
|
|
|
|
reactRouterPattern: T.string,
|
|
|
|
vercelRouterPattern: T.string,
|
|
|
|
})
|
|
|
|
).validate(json5.parse(routesJson))
|
|
|
|
return routes.map((route) => ({
|
|
|
|
check: true,
|
|
|
|
src: route.vercelRouterPattern,
|
|
|
|
dest: '/index.html',
|
|
|
|
}))
|
|
|
|
}
|
Make Vercel URL rewrites precise (#2913)
### The problem
Right now we use a catchall path in Vercel routing config to rewrite all
requests that don't match existing assets to `/index.html`, which is
needed for client side routing to work. This, however, messes up 404
errors for truly non-existing files which won't be handled by the SPA,
because they get redirected to index.html.
Even worse, this interacts very poorly with caching. Normally if we
request a non-existent file, then put the file in place, and request the
file again, we'll get 404 the first time and the actual file the second
time. However, in our case we instead return `/index.html` after the
first attempt and cache that response, making it impossible to correct a
missing file without cache flush.
### The solution
One way to fix this is to make the regex in Vercel config precise, so
that they only match our SPA routes. However, it can be dangerous,
because this means we'll need to manually update the config with new SPA
routes every time we add any. This PR tests that regexes we're using in
Vercel match all routes that we set in the SPA router.
### Potential future improvements
It's very possible to generate Vercel's config from React Router routing
objects, but at the moment it's not done because that would require
importing most of dotcom during the build phase, which seem to cause
errors.
### Change Type
- [x] `internal` — Any other changes that don't affect the published
package[^2]
### Test Plan
1. Might need a light smoke test after deployment to dotcom.
- [x] End to end tests
2024-02-22 18:25:45 +00:00
|
|
|
|
2024-01-16 14:38:05 +00:00
|
|
|
config({
|
|
|
|
path: './.env.local',
|
|
|
|
})
|
|
|
|
|
|
|
|
nicelog('The multiplayer server is', process.env.MULTIPLAYER_SERVER)
|
|
|
|
|
|
|
|
async function build() {
|
2024-02-26 12:30:35 +00:00
|
|
|
// make sure we have the latest routes
|
|
|
|
await exec('yarn', ['test', 'src/routes.test.tsx'])
|
|
|
|
const spaRoutes = loadSpaRoutes()
|
2024-01-16 14:38:05 +00:00
|
|
|
await exec('vite', ['build', '--emptyOutDir'])
|
|
|
|
await exec('yarn', ['run', '-T', 'sentry-cli', 'sourcemaps', 'inject', 'dist/assets'])
|
|
|
|
// Clear output static folder (in case we are running locally and have already built the app once before)
|
|
|
|
await exec('rm', ['-rf', '.vercel/output'])
|
|
|
|
mkdirSync('.vercel/output', { recursive: true })
|
|
|
|
await exec('cp', ['-r', 'dist', '.vercel/output/static'])
|
|
|
|
await exec('rm', ['-rf', ...glob.sync('.vercel/output/static/**/*.js.map')])
|
Make Vercel URL rewrites precise (#2913)
### The problem
Right now we use a catchall path in Vercel routing config to rewrite all
requests that don't match existing assets to `/index.html`, which is
needed for client side routing to work. This, however, messes up 404
errors for truly non-existing files which won't be handled by the SPA,
because they get redirected to index.html.
Even worse, this interacts very poorly with caching. Normally if we
request a non-existent file, then put the file in place, and request the
file again, we'll get 404 the first time and the actual file the second
time. However, in our case we instead return `/index.html` after the
first attempt and cache that response, making it impossible to correct a
missing file without cache flush.
### The solution
One way to fix this is to make the regex in Vercel config precise, so
that they only match our SPA routes. However, it can be dangerous,
because this means we'll need to manually update the config with new SPA
routes every time we add any. This PR tests that regexes we're using in
Vercel match all routes that we set in the SPA router.
### Potential future improvements
It's very possible to generate Vercel's config from React Router routing
objects, but at the moment it's not done because that would require
importing most of dotcom during the build phase, which seem to cause
errors.
### Change Type
- [x] `internal` — Any other changes that don't affect the published
package[^2]
### Test Plan
1. Might need a light smoke test after deployment to dotcom.
- [x] End to end tests
2024-02-22 18:25:45 +00:00
|
|
|
|
2024-01-16 14:38:05 +00:00
|
|
|
writeFileSync(
|
|
|
|
'.vercel/output/config.json',
|
|
|
|
JSON.stringify(
|
|
|
|
{
|
|
|
|
version: 3,
|
|
|
|
routes: [
|
|
|
|
// rewrite api calls to the multiplayer server
|
|
|
|
{
|
|
|
|
src: '^/api(/(.*))?$',
|
|
|
|
dest: `${
|
|
|
|
process.env.MULTIPLAYER_SERVER?.replace(/^ws/, 'http') ?? 'http://127.0.0.1:8787'
|
|
|
|
}$1`,
|
|
|
|
check: true,
|
|
|
|
},
|
|
|
|
// cache static assets immutably
|
|
|
|
{
|
|
|
|
src: '^/assets/(.*)$',
|
|
|
|
headers: { 'Cache-Control': 'public, max-age=31536000, immutable' },
|
|
|
|
},
|
|
|
|
// serve static files
|
|
|
|
{
|
2024-02-06 13:31:02 +00:00
|
|
|
handle: 'miss',
|
2024-01-16 14:38:05 +00:00
|
|
|
},
|
|
|
|
// finally handle SPA routing
|
Make Vercel URL rewrites precise (#2913)
### The problem
Right now we use a catchall path in Vercel routing config to rewrite all
requests that don't match existing assets to `/index.html`, which is
needed for client side routing to work. This, however, messes up 404
errors for truly non-existing files which won't be handled by the SPA,
because they get redirected to index.html.
Even worse, this interacts very poorly with caching. Normally if we
request a non-existent file, then put the file in place, and request the
file again, we'll get 404 the first time and the actual file the second
time. However, in our case we instead return `/index.html` after the
first attempt and cache that response, making it impossible to correct a
missing file without cache flush.
### The solution
One way to fix this is to make the regex in Vercel config precise, so
that they only match our SPA routes. However, it can be dangerous,
because this means we'll need to manually update the config with new SPA
routes every time we add any. This PR tests that regexes we're using in
Vercel match all routes that we set in the SPA router.
### Potential future improvements
It's very possible to generate Vercel's config from React Router routing
objects, but at the moment it's not done because that would require
importing most of dotcom during the build phase, which seem to cause
errors.
### Change Type
- [x] `internal` — Any other changes that don't affect the published
package[^2]
### Test Plan
1. Might need a light smoke test after deployment to dotcom.
- [x] End to end tests
2024-02-22 18:25:45 +00:00
|
|
|
...spaRoutes,
|
|
|
|
// react router will handle drawing the 404 page
|
2024-01-16 14:38:05 +00:00
|
|
|
{
|
2024-02-06 13:31:02 +00:00
|
|
|
check: true,
|
2024-01-16 14:38:05 +00:00
|
|
|
src: '.*',
|
|
|
|
dest: '/index.html',
|
Make Vercel URL rewrites precise (#2913)
### The problem
Right now we use a catchall path in Vercel routing config to rewrite all
requests that don't match existing assets to `/index.html`, which is
needed for client side routing to work. This, however, messes up 404
errors for truly non-existing files which won't be handled by the SPA,
because they get redirected to index.html.
Even worse, this interacts very poorly with caching. Normally if we
request a non-existent file, then put the file in place, and request the
file again, we'll get 404 the first time and the actual file the second
time. However, in our case we instead return `/index.html` after the
first attempt and cache that response, making it impossible to correct a
missing file without cache flush.
### The solution
One way to fix this is to make the regex in Vercel config precise, so
that they only match our SPA routes. However, it can be dangerous,
because this means we'll need to manually update the config with new SPA
routes every time we add any. This PR tests that regexes we're using in
Vercel match all routes that we set in the SPA router.
### Potential future improvements
It's very possible to generate Vercel's config from React Router routing
objects, but at the moment it's not done because that would require
importing most of dotcom during the build phase, which seem to cause
errors.
### Change Type
- [x] `internal` — Any other changes that don't affect the published
package[^2]
### Test Plan
1. Might need a light smoke test after deployment to dotcom.
- [x] End to end tests
2024-02-22 18:25:45 +00:00
|
|
|
status: 404,
|
2024-01-16 14:38:05 +00:00
|
|
|
},
|
|
|
|
],
|
|
|
|
overrides: {},
|
|
|
|
} satisfies Config,
|
|
|
|
null,
|
|
|
|
2
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
build()
|