diff --git a/.env.development b/.env.development index c41c4c5c6..6b499e60d 100644 --- a/.env.development +++ b/.env.development @@ -1,3 +1,4 @@ EP_SESSIONS_API="https://static.europython.eu/programme/ep2025/releases/current/sessions.json" EP_SPEAKERS_API="https://static.europython.eu/programme/ep2025/releases/current/speakers.json" EP_SCHEDULE_API="https://static.europython.eu/programme/ep2025/releases/current/schedule.json" +EP_FAST_BUILD="true" diff --git a/astro.config.mjs b/astro.config.mjs index db8338cfe..31e38d733 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -1,4 +1,5 @@ import path from "path"; +import { loadEnv } from "vite"; import { defineConfig } from "astro/config"; import mdx from "@astrojs/mdx"; import sitemap from "@astrojs/sitemap"; @@ -27,6 +28,15 @@ if (!gitVersion) { } } +const mode = + process.argv.find((arg) => + ["development", "production", "preview"].includes(arg) + ) || "production"; +const fastBuild = loadEnv(mode, process.cwd(), "").EP_FAST_BUILD === "true"; +console.log( + `\x1b[35m[EP]\x1b[0m Fast Build: \x1b[1m\x1b[34m${fastBuild}\x1b[0m` +); + function dontDie() { return { name: "dont-die", @@ -114,23 +124,27 @@ export default defineConfig({ }, integrations: [ mdx(), - sitemap(), - metaTags(), - deleteUnusedImages(), svelte(), serviceWorker({ workbox: { inlineWorkboxRuntime: true }, }), - compress({ - HTML: false, - CSS: false, - SVG: false, - }), - dontDie(), + ...(fastBuild + ? [] + : [ + sitemap(), + metaTags(), + deleteUnusedImages(), + compress({ + HTML: false, + CSS: false, + SVG: false, + }), + dontDie(), + ]), ], output: "static", build: { - minify: true, + ...(fastBuild ? {} : { minify: true }), }, image: { remotePatterns: [{ protocol: "https" }], diff --git a/package.json b/package.json index 145d1f004..6e511eca0 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "date-fns-tz": "^3.2.0", "hastscript": "^9.0.1", "js-yaml": "^4.1.0", + "lite-youtube-embed": "^0.3.3", "marked": "^15.0.12", "nanostores": "^1.0.1", "pagefind": "^1.3.0", @@ -50,7 +51,8 @@ "prettier-plugin-astro": "^0.14.1", "puppeteer": "^24.9.0", "tsx": "^4.19.4", - "typescript": "^5.8.3" + "typescript": "^5.8.3", + "vite": "^6.3.5" }, "prettier": { "proseWrap": "always" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 057eb94ea..7cec73640 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,7 +37,7 @@ importers: version: 0.5.16(tailwindcss@4.1.8) '@tailwindcss/vite': specifier: ^4.1.8 - version: 4.1.8(vite@6.3.4(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1)) + version: 4.1.8(vite@6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1)) astro: specifier: ^5.8.0 version: 5.8.0(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(rollup@2.79.2)(terser@5.39.0)(tsx@4.19.4)(typescript@5.8.3)(yaml@2.7.1) @@ -74,6 +74,9 @@ importers: js-yaml: specifier: ^4.1.0 version: 4.1.0 + lite-youtube-embed: + specifier: ^0.3.3 + version: 0.3.3 marked: specifier: ^15.0.12 version: 15.0.12 @@ -120,6 +123,9 @@ importers: tsx: specifier: ^4.19.4 version: 4.19.4 + vite: + specifier: ^6.3.5 + version: 6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1) packages: @@ -4046,46 +4052,6 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - vite@6.3.4: - resolution: {integrity: sha512-BiReIiMS2fyFqbqNT/Qqt4CVITDU9M9vE+DKcVAsB+ZV0wvTKd+3hMbkpxz1b+NmEDMegpVbisKiAZOnvO92Sw==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - jiti: '>=1.21.0' - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - vite@6.3.5: resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -4540,7 +4506,7 @@ snapshots: '@astrojs/svelte@7.1.0(@types/node@22.13.14)(astro@5.8.0(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(rollup@2.79.2)(terser@5.39.0)(tsx@4.19.4)(typescript@5.8.3)(yaml@2.7.1))(jiti@2.4.2)(lightningcss@1.30.1)(svelte@5.33.12)(terser@5.39.0)(tsx@4.19.4)(typescript@5.8.3)(yaml@2.7.1)': dependencies: - '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.33.12)(vite@6.3.4(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1)) + '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.33.12)(vite@6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1)) astro: 5.8.0(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(rollup@2.79.2)(terser@5.39.0)(tsx@4.19.4)(typescript@5.8.3)(yaml@2.7.1) svelte: 5.33.12 svelte2tsx: 0.7.39(svelte@5.33.12)(typescript@5.8.3) @@ -5754,14 +5720,14 @@ snapshots: '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.33.12)(vite@6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1)))(svelte@5.33.12)(vite@6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1))': dependencies: - '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.33.12)(vite@6.3.4(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1)) + '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.33.12)(vite@6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1)) debug: 4.4.1 svelte: 5.33.12 vite: 6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.33.12)(vite@6.3.4(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1))': + '@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.33.12)(vite@6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1))': dependencies: '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.33.12)(vite@6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1)))(svelte@5.33.12)(vite@6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1)) debug: 4.4.1 @@ -5769,7 +5735,7 @@ snapshots: kleur: 4.1.5 magic-string: 0.30.17 svelte: 5.33.12 - vite: 6.3.4(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1) + vite: 6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1) vitefu: 1.0.6(vite@6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1)) transitivePeerDependencies: - supports-color @@ -5850,12 +5816,12 @@ snapshots: postcss-selector-parser: 6.0.10 tailwindcss: 4.1.8 - '@tailwindcss/vite@4.1.8(vite@6.3.4(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1))': + '@tailwindcss/vite@4.1.8(vite@6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1))': dependencies: '@tailwindcss/node': 4.1.8 '@tailwindcss/oxide': 4.1.8 tailwindcss: 4.1.8 - vite: 6.3.4(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1) + vite: 6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1) '@tootallnate/quickjs-emscripten@0.23.0': {} @@ -6164,8 +6130,8 @@ snapshots: unist-util-visit: 5.0.0 unstorage: 1.16.0 vfile: 6.0.3 - vite: 6.3.4(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1) - vitefu: 1.0.6(vite@6.3.4(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1)) + vite: 6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1) + vitefu: 1.0.6(vite@6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1)) xxhash-wasm: 1.1.0 yargs-parser: 21.1.1 yocto-spinner: 0.2.2 @@ -6264,8 +6230,8 @@ snapshots: unist-util-visit: 5.0.0 unstorage: 1.16.0 vfile: 6.0.3 - vite: 6.3.4(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1) - vitefu: 1.0.6(vite@6.3.4(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1)) + vite: 6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1) + vitefu: 1.0.6(vite@6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1)) xxhash-wasm: 1.1.0 yargs-parser: 21.1.1 yocto-spinner: 0.2.2 @@ -9332,7 +9298,7 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.2 - vite@6.3.4(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1): + vite@6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1): dependencies: esbuild: 0.25.3 fdir: 6.4.4(picomatch@4.0.2) @@ -9349,23 +9315,6 @@ snapshots: tsx: 4.19.4 yaml: 2.7.1 - vite@6.3.4(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1): - dependencies: - esbuild: 0.25.3 - fdir: 6.4.4(picomatch@4.0.2) - picomatch: 4.0.2 - postcss: 8.5.3 - rollup: 4.40.1 - tinyglobby: 0.2.13 - optionalDependencies: - '@types/node': 22.13.14 - fsevents: 2.3.3 - jiti: 2.4.2 - lightningcss: 1.30.1 - terser: 5.39.0 - tsx: 4.19.4 - yaml: 2.7.1 - vite@6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1): dependencies: esbuild: 0.25.3 @@ -9383,13 +9332,9 @@ snapshots: tsx: 4.19.4 yaml: 2.7.1 - vitefu@1.0.6(vite@6.3.4(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1)): - optionalDependencies: - vite: 6.3.4(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1) - - vitefu@1.0.6(vite@6.3.4(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1)): + vitefu@1.0.6(vite@6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1)): optionalDependencies: - vite: 6.3.4(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1) + vite: 6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1) vitefu@1.0.6(vite@6.3.5(@types/node@22.13.14)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1)): optionalDependencies: diff --git a/src/components/InstallPWA.astro b/src/components/InstallPWA.astro index bbcf7b131..df48f0750 100644 --- a/src/components/InstallPWA.astro +++ b/src/components/InstallPWA.astro @@ -29,11 +29,12 @@ + + diff --git a/src/env.d.ts b/src/env.d.ts index db4bfb864..1140d0fac 100644 --- a/src/env.d.ts +++ b/src/env.d.ts @@ -5,6 +5,7 @@ interface ImportMetaEnv { readonly EP_SESSIONS_API: string; readonly EP_SPEAKERS_API: string; readonly EP_SCHEDULE_API: string; + readonly EP_FAST_BUILD: boolean; } interface ImportMeta { diff --git a/src/utils/markdown.ts b/src/utils/markdown.ts new file mode 100644 index 000000000..1a3fe4e52 --- /dev/null +++ b/src/utils/markdown.ts @@ -0,0 +1,30 @@ +import { experimental_AstroContainer } from "astro/container"; +import YouTube from "@ui/YouTube.astro"; + +export async function replaceYouTubeLinks( + markdownContent: string +): Promise { + const youtubeRegex = + /(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)([^\s'"()[\]<>]+)/gi; + + const matches = [...markdownContent.matchAll(youtubeRegex)]; + if (matches.length === 0) return markdownContent; + + const container = await experimental_AstroContainer.create(); + let updatedContent = markdownContent; + + for (const match of matches) { + const fullUrl = match[0]; + const id = match[1]; + + if (!id) continue; + + const html = await container.renderToString(YouTube, { + props: { id, alt: "Embedded YouTube video" }, + }); + + updatedContent = updatedContent.replace(fullUrl, html); + } + + return updatedContent; +}