Upgrading to Svelte 5 and dependencies that need it. Using enhanced img for local files.

This commit is contained in:
Bradley Shellnut 2024-12-01 19:14:16 -08:00
parent 4b3a1280f6
commit e6a2f8fcb6
16 changed files with 1653 additions and 1779 deletions

11
.gitignore vendored
View file

@ -5,11 +5,14 @@ node_modules
/package /package
.env .env
.env.* .env.*
!.env.example
*.xdp* *.xdp*
!.env.example
vite.config.js.timestamp-* vite.config.js.timestamp-*
vite.config.ts.timestamp-* vite.config.ts.timestamp-*
.vercel
.fleet .output
.idea .idea
.vercel .fleet
# Sentry Config File
.sentryclirc

1
.node-version Normal file
View file

@ -0,0 +1 @@
22

2
.nvmrc
View file

@ -1 +1 @@
v22 22

65
biome.json Normal file
View file

@ -0,0 +1,65 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"vcs": {
"enabled": false,
"clientKind": "git",
"useIgnoreFile": false
},
"files": { "ignoreUnknown": false, "ignore": [] },
"formatter": {
"enabled": true,
"formatWithErrors": false,
"indentStyle": "space",
"indentWidth": 2,
"lineEnding": "lf",
"lineWidth": 150,
"attributePosition": "auto",
"ignore": [
"**/.DS_Store",
"**/node_modules",
"./build",
"./.svelte-kit",
"./package",
"**/.env",
"**/.env.*",
"**/pnpm-lock.yaml",
"**/package-lock.json",
"**/yarn.lock",
"**/paraglide/**"
]
},
"organizeImports": { "enabled": true },
"linter": { "enabled": true, "rules": { "recommended": true } },
"javascript": {
"formatter": {
"jsxQuoteStyle": "single",
"quoteProperties": "asNeeded",
"trailingCommas": "all",
"indentStyle": "space",
"lineEnding": "lf",
"lineWidth": 150,
"semicolons": "always",
"arrowParentheses": "always",
"bracketSpacing": true,
"bracketSameLine": false,
"quoteStyle": "single",
"attributePosition": "auto"
},
"parser": {
"unsafeParameterDecoratorsEnabled": true
}
},
"overrides": [
{
"include": ["*.svelte"],
"linter": {
"rules": {
"style": {
"useConst": "off",
"useImportType": "off"
}
}
}
}
]
}

11
docker-compose.yaml Normal file
View file

@ -0,0 +1,11 @@
version: "3.8"
services:
redis:
image: redis:latest
container_name: personal_website_redis
ports:
- "6379:6379"
volumes:
- redis_data:/data
volumes:
redis_data:

View file

@ -1,6 +1,6 @@
{ {
"name": "personal-website-sveltekit", "name": "personal-website-sveltekit",
"version": "0.0.1", "version": "1.0.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "NODE_OPTIONS=\"--inspect\" vite dev --host", "dev": "NODE_OPTIONS=\"--inspect\" vite dev --host",
@ -10,71 +10,65 @@
"test:ui": "svelte-kit sync && playwright test --ui", "test:ui": "svelte-kit sync && playwright test --ui",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --plugin-search-dir . --check . && eslint .", "lint": "biome lint --error-on-warnings .",
"format": "prettier --plugin-search-dir . --write .", "format": "biome format --write .",
"test:integration": "playwright test", "test:integration": "playwright test",
"test:unit": "vitest" "test:unit": "vitest"
}, },
"packageManager": "pnpm@9.11.0", "packageManager": "pnpm@9.11.0",
"devDependencies": { "devDependencies": {
"@biomejs/biome": "^1.9.4",
"@iconify-icons/material-symbols": "^1.2.58", "@iconify-icons/material-symbols": "^1.2.58",
"@iconify-icons/mdi": "^1.2.48", "@iconify-icons/mdi": "^1.2.48",
"@iconify-icons/radix-icons": "^1.2.9", "@iconify-icons/radix-icons": "^1.2.9",
"@iconify-icons/simple-icons": "^1.2.74", "@iconify-icons/simple-icons": "^1.2.74",
"@melt-ui/pp": "^0.3.2", "@melt-ui/pp": "^0.3.2",
"@playwright/test": "^1.47.2", "@melt-ui/svelte": "^0.86.2",
"@sveltejs/adapter-auto": "^3.2.5", "@playwright/test": "^1.49.0",
"@sveltejs/adapter-node": "^5.2.5", "@sveltejs/adapter-auto": "^3.3.1",
"@sveltejs/adapter-static": "^3.0.5", "@sveltejs/adapter-node": "^5.2.9",
"@sveltejs/enhanced-img": "^0.2.1", "@sveltejs/adapter-static": "^3.0.6",
"@sveltejs/kit": "^2.6.1", "@sveltejs/enhanced-img": "^0.4.1",
"@sveltejs/vite-plugin-svelte": "^3.1.2", "@sveltejs/kit": "^2.9.0",
"@typescript-eslint/eslint-plugin": "^7.18.0", "@sveltejs/vite-plugin-svelte": "^5.0.1",
"@typescript-eslint/parser": "^7.18.0",
"@zerodevx/svelte-img": "^2.1.2", "@zerodevx/svelte-img": "^2.1.2",
"autoprefixer": "^10.4.20", "autoprefixer": "^10.4.20",
"eslint": "^8.57.1",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.44.1",
"iconify-icon": "^2.1.0", "iconify-icon": "^2.1.0",
"just-intersect": "^4.3.0", "just-intersect": "^4.3.0",
"mdsvex": "^0.11.2", "mdsvex": "^0.11.2",
"mdsvex-relative-images": "^1.0.3", "mdsvex-relative-images": "^1.0.3",
"postcss": "^8.4.47", "postcss": "^8.4.49",
"postcss-import": "^16.1.0", "postcss-import": "^16.1.0",
"postcss-load-config": "^5.1.0", "postcss-load-config": "^5.1.0",
"postcss-preset-env": "^9.6.0", "postcss-preset-env": "^9.6.0",
"prettier": "^3.3.3", "sass": "^1.81.0",
"prettier-plugin-svelte": "^3.2.7",
"sass": "^1.79.4",
"satori": "^0.10.14", "satori": "^0.10.14",
"satori-html": "^0.3.2", "satori-html": "^0.3.2",
"scrape-it": "^6.1.2", "scrape-it": "^6.1.3",
"sharp": "^0.33.5", "sharp": "^0.33.5",
"svelte": "^4.2.19", "svelte": "^5.3.1",
"svelte-check": "^3.8.6", "svelte-check": "^4.1.0",
"svelte-meta-tags": "^3.1.4", "svelte-meta-tags": "^4.0.4",
"svelte-preprocess": "^5.1.4", "svelte-preprocess": "^6.0.3",
"svelte-sequential-preprocessor": "^2.0.1", "svelte-sequential-preprocessor": "^2.0.2",
"tslib": "^2.7.0", "tslib": "^2.8.1",
"typescript": "^5.6.2", "typescript": "^5.7.2",
"vanilla-lazyload": "^19.1.3", "vanilla-lazyload": "^19.1.3",
"vite": "^5.4.8", "vite": "^6.0.1",
"vite-imagetools": "^7.0.4", "vite-imagetools": "^7.0.5",
"vitest": "^1.6.0" "vitest": "^1.6.0"
}, },
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"@melt-ui/svelte": "^0.76.3",
"@resvg/resvg-js": "^2.6.2", "@resvg/resvg-js": "^2.6.2",
"@sveltejs/adapter-vercel": "^5.4.4", "@sveltejs/adapter-vercel": "^5.5.0",
"@types/nprogress": "^0.2.3", "@types/nprogress": "^0.2.3",
"@vercel/og": "^0.6.3", "@vercel/og": "^0.6.4",
"bits-ui": "^0.21.15", "bits-ui": "^0.21.16",
"flexsearch": "^0.7.43", "flexsearch": "^0.7.43",
"ioredis": "^5.4.1", "ioredis": "^5.4.1",
"lucide-svelte": "^0.378.0", "lucide-svelte": "^0.462.0",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"svelte-local-storage-store": "^0.6.4" "svelte-local-storage-store": "^0.6.4"
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -5,14 +5,18 @@ import {
WALLABAG_PASSWORD, WALLABAG_PASSWORD,
WALLABAG_URL, WALLABAG_URL,
PAGE_SIZE, PAGE_SIZE,
USE_REDIS_CACHE USE_REDIS_CACHE,
} from '$env/static/private'; } from "$env/static/private";
import intersect from 'just-intersect'; import intersect from "just-intersect";
import type { Article, ArticlePageLoad, WallabagArticle } from '$lib/types/article'; import type {
import { ArticleTag } from '$lib/types/articleTag'; Article,
import type { PageQuery } from '$lib/types/pageQuery'; ArticlePageLoad,
import { URLSearchParams } from 'url'; WallabagArticle,
import { redis } from '$lib/server/redis'; } from "$lib/types/article";
import { ArticleTag } from "$lib/types/articleTag";
import type { PageQuery } from "$lib/types/pageQuery";
import { URLSearchParams } from "url";
import { redis } from "$lib/server/redis";
const base: string = WALLABAG_URL; const base: string = WALLABAG_URL;
@ -29,18 +33,18 @@ export async function fetchArticlesApi(
} }
const pageQuery: PageQuery = { const pageQuery: PageQuery = {
sort: 'updated', sort: "updated",
perPage, perPage,
since: 0, since: 0,
page: Number(queryParams?.page) || 1, page: Number(queryParams?.page) || 1,
tags: 'programming', tags: "programming",
content: 'metadata' content: "metadata",
}; };
const entriesQueryParams = new URLSearchParams({ const entriesQueryParams = new URLSearchParams({
...pageQuery, ...pageQuery,
perPage: `${pageQuery.perPage}`, perPage: `${pageQuery.perPage}`,
since: `${pageQuery.since}`, since: `${pageQuery.since}`,
page: `${pageQuery.page}` page: `${pageQuery.page}`,
}); });
if (USE_REDIS_CACHE) { if (USE_REDIS_CACHE) {
@ -55,35 +59,44 @@ export async function fetchArticlesApi(
} }
const authBody = { const authBody = {
grant_type: 'password', grant_type: "password",
client_id: WALLABAG_CLIENT_ID, client_id: WALLABAG_CLIENT_ID,
client_secret: WALLABAG_CLIENT_SECRET, client_secret: WALLABAG_CLIENT_SECRET,
username: WALLABAG_USERNAME, username: WALLABAG_USERNAME,
password: WALLABAG_PASSWORD password: WALLABAG_PASSWORD,
}; };
const authResponse = await fetch(`${base}/oauth/v2/token`, { const authResponse = await fetch(`${base}/oauth/v2/token`, {
method: 'POST', method: "POST",
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams(authBody) body: new URLSearchParams(authBody),
}); });
const auth = await authResponse.json(); const auth = await authResponse.json();
const pageResponse = await fetch(`${WALLABAG_URL}/api/entries.json?${entriesQueryParams}`, { const pageResponse = await fetch(
method: 'GET', `${WALLABAG_URL}/api/entries.json?${entriesQueryParams}`,
headers: { {
Authorization: `Bearer ${auth.access_token}` method: "GET",
headers: {
Authorization: `Bearer ${auth.access_token}`,
},
} }
}); );
if (!pageResponse.ok) { if (!pageResponse.ok) {
throw new Error(pageResponse.statusText); throw new Error(pageResponse.statusText);
} }
const cacheControl = pageResponse.headers.get('cache-control') || 'no-cache'; const cacheControl = pageResponse.headers.get("cache-control") || "no-cache";
const { _embedded: favoriteArticles, page, pages, total, limit } = await pageResponse.json(); const {
_embedded: favoriteArticles,
page,
pages,
total,
limit,
} = await pageResponse.json();
const articles: Article[] = []; const articles: Article[] = [];
favoriteArticles.items.forEach((article: WallabagArticle) => { favoriteArticles.items.forEach((article: WallabagArticle) => {
@ -94,13 +107,13 @@ export async function fetchArticlesApi(
tags, tags,
title: article.title, title: article.title,
url: new URL(article.url), url: new URL(article.url),
domain_name: article.domain_name?.replace('www.', '') ?? '', domain_name: article.domain_name?.replace("www.", "") ?? "",
hashed_url: article.hashed_url, hashed_url: article.hashed_url,
reading_time: article.reading_time, reading_time: article.reading_time,
preview_picture: article.preview_picture, preview_picture: article.preview_picture,
created_at: new Date(article.created_at), created_at: new Date(article.created_at),
updated_at: new Date(article.updated_at), updated_at: new Date(article.updated_at),
archived_at: article.archived_at ? new Date(article.archived_at) : null archived_at: article.archived_at ? new Date(article.archived_at) : null,
}); });
} }
}); });
@ -111,11 +124,16 @@ export async function fetchArticlesApi(
totalPages: pages, totalPages: pages,
limit, limit,
totalArticles: total, totalArticles: total,
cacheControl cacheControl,
}; };
if (USE_REDIS_CACHE) { if (USE_REDIS_CACHE) {
redis.set(entriesQueryParams.toString(), JSON.stringify(responseData), 'EX', 43200); redis.set(
entriesQueryParams.toString(),
JSON.stringify(responseData),
"EX",
43200
);
} }
return responseData; return responseData;

View file

@ -1,11 +1,15 @@
<script lang="ts"> <script lang="ts">
import type { Article } from "$lib/types/article"; import type { Article } from '$lib/types/article';
import ExternalLink from './ExternalLink.svelte'; import ExternalLink from './ExternalLink.svelte';
export let articles: Article[]; const {
export let totalArticles: number; articles,
export let compact: boolean = false; totalArticles,
export let classes: string[] = []; compact = false,
classes = [],
}: { articles: Article[]; totalArticles: number; compact: boolean; classes: string[] } = $props();
console.log('articles', articles);
</script> </script>
<div> <div>

View file

@ -2,7 +2,7 @@
import type { Album } from "$lib/types/album"; import type { Album } from "$lib/types/album";
import LazyImage from './LazyImage.svelte'; import LazyImage from './LazyImage.svelte';
export let albums: Album[]; const { albums }: { albums: Album[] } = $props();
const displayAlbums = const displayAlbums =
albums?.length > 6 ? albums.slice(0, 6) : albums; albums?.length > 6 ? albums.slice(0, 6) : albums;
@ -10,15 +10,9 @@
album.src = { album.src = {
img: { src: `${album.artwork}`, w: 230, h: 230 }, img: { src: `${album.artwork}`, w: 230, h: 230 },
sources: { sources: {
avif: [ avif: `${album.artwork}`,
{ src: `${album.artwork}`, w: 230, h: 230 }, webp: `${album.artwork}`,
], jpg: `${album.artwork}`
webp: [
{ src: `${album.artwork}`, w: 230, h: 230 },
],
jpg: [
{ src: `${album.artwork}`, w: 230, h: 230 },
]
} }
} }
} }

View file

@ -1,9 +1,9 @@
import type { MetaTagsProps } from 'svelte-meta-tags';
import { PUBLIC_SITE_URL } from '$env/static/public'; import { PUBLIC_SITE_URL } from '$env/static/public';
import type { PageServerLoad } from './$types';
import { fetchBandcampAlbums } from '$lib/util/fetchBandcampAlbums';
import type { Album } from '$lib/types/album'; import type { Album } from '$lib/types/album';
import type { ArticlePageLoad } from '$lib/types/article'; import type { ArticlePageLoad } from '$lib/types/article';
import { fetchBandcampAlbums } from '$lib/util/fetchBandcampAlbums';
import type { MetaTagsProps } from 'svelte-meta-tags';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ fetch, setHeaders, url }) => { export const load: PageServerLoad = async ({ fetch, setHeaders, url }) => {
let baseUrl; let baseUrl;
@ -45,7 +45,7 @@ export const load: PageServerLoad = async ({ fetch, setHeaders, url }) => {
const [albums, articles]: [Album[], ArticlePageLoad] = await Promise.all([ const [albums, articles]: [Album[], ArticlePageLoad] = await Promise.all([
await fetchBandcampAlbums(), await fetchBandcampAlbums(),
(await fetch(`/api/articles?page=1&limit=3`)).json() (await fetch('/api/articles?page=1&limit=3')).json()
]); ]);
setHeaders({ setHeaders({

View file

@ -1,31 +1,21 @@
<script lang="ts"> <script lang="ts">
import type { PageData } from './$types'; import Articles from '$lib/components/Articles.svelte';
import Bandcamp from '$lib/components/Bandcamp.svelte'; import Bandcamp from '$lib/components/Bandcamp.svelte';
import Articles from '$lib/components/Articles.svelte'; import type { Album } from '$lib/types/album';
import type { Album } from '$lib/types/album'; import type { Article, ArticlePageLoad } from '$lib/types/article';
import type { Article, ArticlePageLoad } from '$lib/types/article'; import type { PageData } from './$types';
export let data: PageData; const { data } = $props();
let albums: Album[]; let albums: Album[] = $derived(data.albums);
let articlesData: ArticlePageLoad; let articlesData: ArticlePageLoad = $derived(data.articlesData);
let articles: Article[]; let articles: Article[] = $derived(articlesData.articles);
let totalArticles: number; let totalArticles: number = $derived(articlesData.totalArticles);
$: if (data) { const userNames = {
albums = data.albums; github: 'BradNut',
articlesData = data.articlesData; linkedIn: 'bradley-shellnut',
} email: 'bradleyshellnut@pm.me',
};
$: if (articlesData) {
articles = articlesData.articles;
totalArticles = articlesData.totalArticles;
}
const userNames = {
github: 'BradNut',
linkedIn: 'bradley-shellnut',
email: 'bradleyshellnut@pm.me',
};
</script> </script>
<div class="home"> <div class="home">

View file

@ -9,9 +9,9 @@
import Svelte from '@iconify-icons/simple-icons/svelte'; import Svelte from '@iconify-icons/simple-icons/svelte';
import TypeScript from '@iconify-icons/simple-icons/typescript'; import TypeScript from '@iconify-icons/simple-icons/typescript';
import LazyImage from '$lib/components/LazyImage.svelte'; import LazyImage from '$lib/components/LazyImage.svelte';
import cruise from '$lib/assets/images/cruise.png?as=run:0'; import cruise from '$lib/assets/images/cruise.png?enhanced';
import tortie_derp from '$lib/assets/images/tortie_derp.jpg?as=run'; import tortie_derp from '$lib/assets/images/tortie_derp.jpg?enhanced';
import orange_derp from '$lib/assets/images/orange_derp.jpg?as=run'; import orange_derp from '$lib/assets/images/orange_derp.jpg?enhanced';
import turnip from '$lib/assets/images/turnip.svg'; import turnip from '$lib/assets/images/turnip.svg';
import CourseCard from './CourseCard.svelte'; import CourseCard from './CourseCard.svelte';
import courseData from './course.json'; import courseData from './course.json';
@ -140,7 +140,8 @@
justify-content: center; justify-content: center;
" "
> >
<LazyImage src={cruise} alt="Clip art of a cruise ship. Cruise icons created by C-mo Box - Flaticon" /> <enhanced:img src={cruise} alt="Clip art of a cruise ship. Cruise icons created by C-mo Box - Flaticon" />
<!-- <LazyImage src={cruise} alt="Clip art of a cruise ship. Cruise icons created by C-mo Box - Flaticon" /> -->
<p class="center">Crusin'</p> <p class="center">Crusin'</p>
</div> </div>
</div> </div>
@ -148,11 +149,13 @@
<p>Hanging out with these two cats, Turnip and Taco.</p> <p>Hanging out with these two cats, Turnip and Taco.</p>
<div class="cat-pics"> <div class="cat-pics">
<figure> <figure>
<LazyImage src={tortie_derp} alt="Turnip Cat" /> <enhanced:img src={tortie_derp} alt="Tortie Cat" />
<!-- <LazyImage src={tortie_derp} alt="Turnip Cat" /> -->
<p class="center">Turnip <img class="icon" src={String(turnip)} width="25px" height="25px" alt="Turnip" /></p> <p class="center">Turnip <img class="icon" src={String(turnip)} width="25px" height="25px" alt="Turnip" /></p>
</figure> </figure>
<figure> <figure>
<LazyImage src={orange_derp} alt="Taco Cat" /> <enhanced:img src={orange_derp} alt="Tortie Cat" />
<!-- <LazyImage src={orange_derp} alt="Taco Cat" /> -->
<p class="center">Taco 🌮</p> <p class="center">Taco 🌮</p>
</figure> </figure>
</div> </div>

View file

@ -1,5 +1,5 @@
import SocialImageCard from '$lib/components/socialImageCard.svelte'; import SocialImageCard from "$lib/components/socialImageCard.svelte";
import { componentToPng } from '$root/lib/renderImage'; import { componentToPng } from "$root/lib/renderImage";
const height = 630; const height = 630;
const width = 1200; const width = 1200;
@ -7,22 +7,27 @@ const width = 1200;
/** @type {import('./$types').RequestHandler} */ /** @type {import('./$types').RequestHandler} */
export async function GET({ url }) { export async function GET({ url }) {
try { try {
const faviconImageName = 'b_shell_nut_favicon.png'; const faviconImageName = "b_shell_nut_favicon.png";
const image = `${new URL(url.origin).href}${faviconImageName}`; const image = `${new URL(url.origin).href}${faviconImageName}`;
const header = url.searchParams.get('header') ?? undefined; const header = url.searchParams.get("header") ?? undefined;
const page = url.searchParams.get('page') ?? undefined; const page = url.searchParams.get("page") ?? undefined;
const content = url.searchParams.get('content') ?? ''; const content = url.searchParams.get("content") ?? "";
// @ts-expect-error: Argument of type 'typeof SocialImageCard__SvelteComponent_' is not assignable to parameter of type 'SvelteComponent<any, any, any>' // @ts-expect-error: Argument of type 'typeof SocialImageCard__SvelteComponent_' is not assignable to parameter of type 'SvelteComponent<any, any, any>'
return componentToPng(SocialImageCard, { return componentToPng(
header, SocialImageCard,
page, {
content, header,
image, page,
width: `${width}`, content,
height: `${height}`, image,
url: new URL(url.origin).href width: `${width}`,
}, height, width); height: `${height}`,
url: new URL(url.origin).href,
},
height,
width
);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }

View file

@ -3,8 +3,6 @@ import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
import { preprocessMeltUI } from '@melt-ui/pp'; import { preprocessMeltUI } from '@melt-ui/pp';
import { mdsvex } from 'mdsvex'; import { mdsvex } from 'mdsvex';
import mdsvexConfig from './mdsvex.config.js'; import mdsvexConfig from './mdsvex.config.js';
import relativeImages from 'mdsvex-relative-images';
/** @type {import('@sveltejs/kit').Config} */ /** @type {import('@sveltejs/kit').Config} */
const config = { const config = {

View file

@ -1,21 +1,45 @@
import { sveltekit } from '@sveltejs/kit/vite'; import { sveltekit } from "@sveltejs/kit/vite";
import type { UserConfig } from 'vite'; import { defineConfig } from "vite";
import { imagetools } from '@zerodevx/svelte-img/vite'; import { enhancedImages } from "@sveltejs/enhanced-img";
import { imagetools } from "@zerodevx/svelte-img/vite";
const config: UserConfig = { export default defineConfig({
plugins: [ plugins: [
enhancedImages(),
sveltekit(), sveltekit(),
imagetools({ imagetools({
// By default, directives are `?width=480;1024;1920&format=avif;webp;jpg` // By default, directives are `?width=480;1024;1920&format=avif;webp;jpg`
// Now we change it to generate 5 variants instead - `avif/jpg` formats at `640/1280` + LQIP (Now as:run) // Now we change it to generate 5 variants instead - `avif/jpg` formats at `640/1280` + LQIP (Now as:run)
profiles: { profiles: {
run: new URLSearchParams('?w=300;480;640;1024;1920&format=avif;webp;jpg&as=run:64') run: new URLSearchParams(
} "?w=300;480;640;1024;1920&format=avif;webp;jpg&as=run:64"
}) ),
},
}),
], ],
esbuild: {
target: "es2022",
},
test: { test: {
include: ['src/**/*.{test,spec}.{js,ts}'] include: ["src/**/*.{test,spec}.{js,ts}"],
} mockReset: true,
}; },
css: {
devSourcemap: true,
preprocessorOptions: {
postcss: {
additionalData: `
@custom-media --below_small (width < 400px);
@custom-media --below_med (width < 700px);
@custom-media --below_large (width < 900px);
@custom-media --below_xlarge (width < 1200px);
export default config; @custom-media --above_small (width > 400px);
@custom-media --above_med (width > 700px);
@custom-media --above_large (width > 900px);
@custom-media --above_xlarge (width > 1200px);
`,
},
},
},
});