Skip to content

Commit 9ed608d

Browse files
authored
chore(site): move to netlify (#381)
1 parent bfaf93f commit 9ed608d

9 files changed

Lines changed: 2868 additions & 469 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ Pods/
120120
# Vercel
121121
.vercel
122122

123+
# Netlify
124+
.netlify
125+
123126
# -------------------------
124127
# Package Manager Locks
125128
# Keep only one when enforcing workspace consistency

pnpm-lock.yaml

Lines changed: 2787 additions & 356 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

site/astro.config.mjs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@
33
import process from 'node:process';
44

55
import mdx from '@astrojs/mdx';
6+
import netlify from '@astrojs/netlify';
67
import react from '@astrojs/react';
78
import sitemap from '@astrojs/sitemap';
8-
9-
import vercel from '@astrojs/vercel';
10-
119
import sentry from '@sentry/astro';
1210
import tailwindcss from '@tailwindcss/vite';
1311
import { defineConfig, fontProviders } from 'astro/config';
@@ -25,9 +23,9 @@ const SITE_URL = 'https://v10.videojs.org';
2523
export default defineConfig({
2624
site: SITE_URL,
2725
trailingSlash: 'never',
28-
adapter: vercel(),
26+
adapter: netlify(),
2927
redirects: {
30-
// Redirects are configured in vercel.json
28+
// Redirects are configured in netlify.toml
3129
},
3230
integrations: [
3331
sentry({

site/integrations/check-v8-urls.ts

Lines changed: 40 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const V8_URLS = [
3737
'https://videojs.org/blog/the-end-of-html-first/',
3838
'https://videojs.org/blog/video-js-5-11-0-prelease/',
3939
'https://videojs.org/blog/video-js-5-s-fluid-mode-and-playlist-picker/',
40-
'https://videojs.org/blog/video-js-5-the-only-thing-thats-changed-is-everything-except-for-like-3-things-that-didn-t-including-the-name/',
40+
"https://videojs.org/blog/video-js-5-the-only-thing-that's-changed-is-everything-except-for-like-3-things-that-didn-t-including-the-name/",
4141
'https://videojs.org/blog/it-s-here-5-0-release-candidates/',
4242
'https://videojs.org/blog/video-js-4-12-the-last-of-the-4-minors/',
4343
'https://videojs.org/blog/video-js-4-9-now-can-join-the-party/',
@@ -178,35 +178,40 @@ interface V8UrlStatus {
178178
status: 'migrated' | 'redirected' | 'needs migration';
179179
}
180180

181-
interface VercelRedirect {
182-
source: string;
183-
destination: string;
184-
statusCode?: number;
185-
permanent?: boolean;
181+
interface NetlifyRedirect {
182+
from: string;
183+
to: string;
184+
status: number;
186185
}
187186

188-
/**
189-
* Check if a pathname matches a Vercel redirect source pattern
190-
* Supports exact matches and :path(.*) wildcard patterns
191-
*/
192-
function matchesVercelPattern(pathname: string, pattern: string): boolean {
193-
// Remove trailing slash for consistent matching
187+
function parseNetlifyToml(content: string): NetlifyRedirect[] {
188+
const redirects: NetlifyRedirect[] = [];
189+
const redirectRegex = /\[\[redirects\]\]\s+from\s*=\s*"([^"]+)"\s+to\s*=\s*"([^"]+)"\s+status\s*=\s*(\d+)/g;
190+
191+
let match: RegExpExecArray | null;
192+
while ((match = redirectRegex.exec(content)) !== null) {
193+
redirects.push({
194+
from: match[1],
195+
to: match[2],
196+
status: parseInt(match[3], 10),
197+
});
198+
}
199+
200+
return redirects;
201+
}
202+
203+
function matchesNetlifyPattern(pathname: string, pattern: string): boolean {
194204
const normalizedPath = pathname.replace(/\/$/, '');
195205
const normalizedPattern = pattern.replace(/\/$/, '');
196206

197-
// Exact match
198207
if (normalizedPattern === normalizedPath) {
199208
return true;
200209
}
201210

202-
// Handle :path(.*) wildcard pattern
203-
// Convert /tags/:path(.*) to a regex that matches /tags/anything
204-
if (normalizedPattern.includes(':path(')) {
205-
const regexPattern = normalizedPattern
206-
.replace(/:[^/]+\(\.\*\)/g, '.*') // :path(.*) -> .*
207-
.replace(/\//g, '\\/'); // Escape slashes
208-
const regex = new RegExp(`^${regexPattern}$`);
209-
return regex.test(normalizedPath);
211+
// Handle * splat pattern (e.g., /tags/* matches /tags/anything)
212+
if (normalizedPattern.endsWith('/*')) {
213+
const prefix = normalizedPattern.slice(0, -2);
214+
return normalizedPath === prefix || normalizedPath.startsWith(`${prefix}/`);
210215
}
211216

212217
return false;
@@ -220,20 +225,18 @@ export default function checkV8Urls(): AstroIntegration {
220225
// Convert URL to file path
221226
const buildDir = fileURLToPath(dir);
222227

223-
// Check for Vercel config files
224-
// buildDir is dist/client/, so go up two levels to site/
225-
const siteDir = resolve(buildDir, '..', '..');
226-
const vercelConfigPath = resolve(siteDir, '.vercel', 'output', 'config.json');
227-
const vercelJsonPath = resolve(siteDir, 'vercel.json');
228+
// buildDir is dist/, so go up one level to site/
229+
const siteDir = resolve(buildDir, '..');
230+
const netlifyTomlPath = resolve(siteDir, 'netlify.toml');
228231

229-
// Read vercel.json redirects if it exists
230-
let vercelJsonRedirects: VercelRedirect[] = [];
231-
if (existsSync(vercelJsonPath)) {
232+
// Read netlify.toml redirects if it exists
233+
let netlifyRedirects: NetlifyRedirect[] = [];
234+
if (existsSync(netlifyTomlPath)) {
232235
try {
233-
const vercelJson = JSON.parse(readFileSync(vercelJsonPath, 'utf-8'));
234-
vercelJsonRedirects = vercelJson.redirects || [];
236+
const content = readFileSync(netlifyTomlPath, 'utf-8');
237+
netlifyRedirects = parseNetlifyToml(content);
235238
} catch {
236-
// Ignore JSON parse errors
239+
// Ignore parse errors
237240
}
238241
}
239242

@@ -254,49 +257,17 @@ export default function checkV8Urls(): AstroIntegration {
254257
if (existsSync(htmlPath1) || existsSync(htmlPath2)) {
255258
status = 'migrated';
256259
} else {
257-
// Check for redirects in vercel.json first
258-
const hasVercelJsonRedirect = vercelJsonRedirects.some((redirect) => {
259-
// Check if redirect has a redirect status code (or permanent flag)
260-
const isRedirect = redirect.statusCode
261-
? redirect.statusCode >= 301 && redirect.statusCode <= 308
262-
: redirect.permanent !== undefined;
263-
260+
// Check for redirects in netlify.toml
261+
const hasNetlifyRedirect = netlifyRedirects.some((redirect) => {
262+
const isRedirect = redirect.status >= 301 && redirect.status <= 308;
264263
if (isRedirect) {
265-
return matchesVercelPattern(pathname, redirect.source);
264+
return matchesNetlifyPattern(pathname, redirect.from);
266265
}
267266
return false;
268267
});
269268

270-
if (hasVercelJsonRedirect) {
269+
if (hasNetlifyRedirect) {
271270
status = 'redirected';
272-
} else {
273-
// Fall back to checking .vercel/output/config.json (adapter-generated)
274-
if (existsSync(vercelConfigPath)) {
275-
try {
276-
const vercelConfig = JSON.parse(readFileSync(vercelConfigPath, 'utf-8'));
277-
const routes = vercelConfig.routes || [];
278-
279-
// Check if this pathname has a redirect (status 301/302/307/308)
280-
const hasRedirect = routes.some((route: any) => {
281-
if (route.status && route.status >= 301 && route.status <= 308) {
282-
// Route has a redirect status code
283-
const src = route.src;
284-
// Match against pathname (src is a regex pattern)
285-
// Simple check: convert pathname to regex pattern
286-
const pathPattern = `^${pathname.replace(/\/$/, '')}$`;
287-
const pathPatternWithSlash = `^${pathname}$`;
288-
return src === pathPattern || src === pathPatternWithSlash;
289-
}
290-
return false;
291-
});
292-
293-
if (hasRedirect) {
294-
status = 'redirected';
295-
}
296-
} catch {
297-
// Ignore JSON parse errors
298-
}
299-
}
300271
}
301272
}
302273

site/netlify.toml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Redirect old theme demo pages to home
2+
[[redirects]]
3+
from = "/city"
4+
to = "/"
5+
status = 308
6+
7+
[[redirects]]
8+
from = "/fantasy"
9+
to = "/"
10+
status = 308
11+
12+
[[redirects]]
13+
from = "/forest"
14+
to = "/"
15+
status = 308
16+
17+
[[redirects]]
18+
from = "/sea"
19+
to = "/"
20+
status = 308
21+
22+
# Redirect old tags pages to blog (no tag filtering in v10)
23+
[[redirects]]
24+
from = "/tags"
25+
to = "/blog"
26+
status = 307
27+
28+
[[redirects]]
29+
from = "/tags/*"
30+
to = "/blog"
31+
status = 307

site/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
"scripts": {
66
"dev": " astro dev",
77
"build": "astro build",
8-
"preview": "echo 'Preview server is not supported on with the Vercel adapter.'",
98
"astro": "astro",
109
"test": "vitest run",
1110
"test:watch": "vitest",
@@ -14,10 +13,10 @@
1413
},
1514
"dependencies": {
1615
"@astrojs/mdx": "^4.3.7",
16+
"@astrojs/netlify": "^6.6.4",
1717
"@astrojs/react": "^4.4.0",
1818
"@astrojs/rss": "^4.0.12",
1919
"@astrojs/sitemap": "^3.6.0",
20-
"@astrojs/vercel": "^8.2.9",
2120
"@base-ui-components/react": "1.0.0-beta.4",
2221
"@nanostores/react": "^1.0.0",
2322
"@pagefind/default-ui": "^1.4.0",

site/sentry.server.config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import * as Sentry from '@sentry/astro';
22

33
Sentry.init({
44
dsn: 'https://6bcdfa6b82da6dd4d7753618a9a69c7c@o43841.ingest.us.sentry.io/4510671167160320',
5-
environment: import.meta.env.VERCEL_ENV || 'development',
5+
environment: import.meta.env.CONTEXT || 'development',
66
enabled: import.meta.env.PROD,
7-
release: import.meta.env.VERCEL_GIT_COMMIT_SHA || import.meta.env.VERCEL_DEPLOYMENT_ID || undefined,
7+
release: import.meta.env.COMMIT_REF || import.meta.env.DEPLOY_ID || undefined,
88
// Adds request headers and IP for users, for more info visit:
99
// https://docs.sentry.io/platforms/javascript/guides/astro/configuration/options/#sendDefaultPii
1010
sendDefaultPii: true,

site/vercel.json

Lines changed: 0 additions & 34 deletions
This file was deleted.

turbo.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"tasks": {
66
"build": {
77
"dependsOn": ["^build"],
8-
"outputs": ["dist/**", ".vercel/output/**"]
8+
"outputs": ["dist/**", ".netlify/**"]
99
},
1010
"dev": {
1111
"cache": false,

0 commit comments

Comments
 (0)