diff --git a/web/package.json b/web/package.json
index 32b44a4645..259ec22384 100644
--- a/web/package.json
+++ b/web/package.json
@@ -9,7 +9,7 @@
"build:stats": "BUILD_STATS=true vite build",
"package": "svelte-kit package",
"preview": "vite preview",
- "check:svelte": "svelte-check --no-tsconfig --fail-on-warnings --compiler-warnings 'state_referenced_locally:ignore'",
+ "check:svelte": "svelte-check --no-tsconfig --fail-on-warnings",
"check:typescript": "tsc --noEmit",
"check:watch": "pnpm run check:svelte --watch",
"check:code": "pnpm run format && pnpm run lint && pnpm run check:svelte && pnpm run check:typescript",
diff --git a/web/src/lib/components/album-page/AlbumViewer.svelte b/web/src/lib/components/album-page/AlbumViewer.svelte
index 98e251be30..3aa2bab4e2 100644
--- a/web/src/lib/components/album-page/AlbumViewer.svelte
+++ b/web/src/lib/components/album-page/AlbumViewer.svelte
@@ -30,7 +30,7 @@
let { sharedLink }: Props = $props();
- const album = sharedLink.album as AlbumResponseDto;
+ const album = $derived(sharedLink.album as AlbumResponseDto);
let { slideshowState, slideshowNavigation } = slideshowStore;
diff --git a/web/src/lib/components/asset-viewer/ActivityViewer.svelte b/web/src/lib/components/asset-viewer/ActivityViewer.svelte
index b59bdafad8..28e2d2b347 100644
--- a/web/src/lib/components/asset-viewer/ActivityViewer.svelte
+++ b/web/src/lib/components/asset-viewer/ActivityViewer.svelte
@@ -53,7 +53,8 @@
let activityHeight: number = $state(0);
let chatHeight: number = $state(0);
let divHeight = $derived(innerHeight - activityHeight);
- let previousAssetId: string | undefined = $state(assetId);
+ // svelte-ignore state_referenced_locally
+ let previousAssetId = $state(assetId);
let message = $state('');
let isSendingMessage = $state(false);
const isAlbumOwner = $derived(albumUsers[0].user.id === authManager.user.id);
diff --git a/web/src/lib/components/asset-viewer/actions/SetVisibilityAction.svelte b/web/src/lib/components/asset-viewer/actions/SetVisibilityAction.svelte
index 7c7c0a5e5d..db6116821b 100644
--- a/web/src/lib/components/asset-viewer/actions/SetVisibilityAction.svelte
+++ b/web/src/lib/components/asset-viewer/actions/SetVisibilityAction.svelte
@@ -16,7 +16,7 @@
}
let { asset, onAction, preAction }: Props = $props();
- const isLocked = asset.visibility === AssetVisibility.Locked;
+ const isLocked = $derived(asset.visibility === AssetVisibility.Locked);
const toggleLockedVisibility = async () => {
const isConfirmed = await modalManager.showDialog({
diff --git a/web/src/lib/components/assets/thumbnail/VideoThumbnail.svelte b/web/src/lib/components/assets/thumbnail/VideoThumbnail.svelte
index db5ecdefa7..041162239c 100644
--- a/web/src/lib/components/assets/thumbnail/VideoThumbnail.svelte
+++ b/web/src/lib/components/assets/thumbnail/VideoThumbnail.svelte
@@ -29,7 +29,7 @@
class: className,
}: Props = $props();
- let remainingSeconds = $state(durationInSeconds);
+ let remainingSeconds = $derived(durationInSeconds);
let loading = $state(true);
let error = $state(false);
let player: HTMLVideoElement | undefined = $state();
diff --git a/web/src/lib/components/maintenance/MaintenanceBackupsList.svelte b/web/src/lib/components/maintenance/MaintenanceBackupsList.svelte
index fbadcef31c..464d7f3099 100644
--- a/web/src/lib/components/maintenance/MaintenanceBackupsList.svelte
+++ b/web/src/lib/components/maintenance/MaintenanceBackupsList.svelte
@@ -18,7 +18,7 @@
let props: Props = $props();
- let backups = $state(props.backups ?? []);
+ let backups = $derived(props.backups ?? []);
async function reloadBackups() {
const result = await listDatabaseBackups();
diff --git a/web/src/lib/components/pages/SharedLinkPage.svelte b/web/src/lib/components/pages/SharedLinkPage.svelte
index 35a56579d6..1178901c95 100644
--- a/web/src/lib/components/pages/SharedLinkPage.svelte
+++ b/web/src/lib/components/pages/SharedLinkPage.svelte
@@ -31,6 +31,7 @@
const { data }: Props = $props();
+ // svelte-ignore state_referenced_locally
let { sharedLink, passwordRequired, key, slug, meta } = $state(data);
let { title, description } = $state(meta);
let isOwned = $derived(authManager.authenticated && authManager.user.id === sharedLink?.userId);
diff --git a/web/src/lib/components/shared-components/EmptyPlaceholder.svelte b/web/src/lib/components/shared-components/EmptyPlaceholder.svelte
index 78c675c93b..cf9818f3f7 100644
--- a/web/src/lib/components/shared-components/EmptyPlaceholder.svelte
+++ b/web/src/lib/components/shared-components/EmptyPlaceholder.svelte
@@ -14,9 +14,9 @@
let width = $derived(fullWidth ? 'w-full' : 'w-1/2');
- const hoverClasses = onClick
- ? `border dark:border-immich-dark-gray hover:bg-immich-primary/5 dark:hover:bg-immich-dark-primary/25`
- : '';
+ const hoverClasses = $derived(
+ onClick ? `border dark:border-immich-dark-gray hover:bg-immich-primary/5 dark:hover:bg-immich-dark-primary/25` : '',
+ );
diff --git a/web/src/lib/components/shared-components/context-menu/MenuOption.svelte b/web/src/lib/components/shared-components/context-menu/MenuOption.svelte
index dc5a2d7c0f..72d7b0b5f6 100644
--- a/web/src/lib/components/shared-components/context-menu/MenuOption.svelte
+++ b/web/src/lib/components/shared-components/context-menu/MenuOption.svelte
@@ -36,12 +36,15 @@
onClick();
};
- if (shortcut && !shortcutLabel) {
- shortcutLabel = computeShortcutLabel(shortcut);
- }
- const bindShortcutIfSet = shortcut
- ? (n: HTMLElement) => bindShortcut(n, { shortcut, onShortcut: onClick })
- : () => {};
+ $effect(() => {
+ if (shortcut && !shortcutLabel) {
+ shortcutLabel = computeShortcutLabel(shortcut);
+ }
+ });
+
+ const bindShortcutIfSet = $derived(
+ shortcut ? (n: HTMLElement) => bindShortcut(n, { shortcut, onShortcut: onClick }) : () => {},
+ );
diff --git a/web/src/lib/components/shared-components/progress-bar/ProgressBar.svelte b/web/src/lib/components/shared-components/progress-bar/ProgressBar.svelte
index 1ed0cdf9ac..9d85a7c9d1 100644
--- a/web/src/lib/components/shared-components/progress-bar/ProgressBar.svelte
+++ b/web/src/lib/components/shared-components/progress-bar/ProgressBar.svelte
@@ -37,7 +37,7 @@
await play();
};
- let progress = setDuration(duration);
+ let progress = $derived(setDuration(duration));
$effect(() => {
handlePromiseError(onChange(duration));
diff --git a/web/src/lib/components/shared-components/settings/SettingAccordionState.svelte b/web/src/lib/components/shared-components/settings/SettingAccordionState.svelte
index b0deb64316..541a7f8712 100644
--- a/web/src/lib/components/shared-components/settings/SettingAccordionState.svelte
+++ b/web/src/lib/components/shared-components/settings/SettingAccordionState.svelte
@@ -25,7 +25,10 @@
}
let { queryParam, state = writable(getParamValues(queryParam)), children }: Props = $props();
- setAccordionState(state);
+
+ $effect.pre(() => {
+ setAccordionState(state);
+ });
const searchParams = new SvelteURLSearchParams(page.url.searchParams);
diff --git a/web/src/lib/components/shared-components/tree/Breadcrumbs.svelte b/web/src/lib/components/shared-components/tree/Breadcrumbs.svelte
index 20380f60ef..0709ee2ba0 100644
--- a/web/src/lib/components/shared-components/tree/Breadcrumbs.svelte
+++ b/web/src/lib/components/shared-components/tree/Breadcrumbs.svelte
@@ -13,7 +13,7 @@
const { node, getLink, title, icon }: Props = $props();
- const rootLink = getLink('');
+ const rootLink = $derived(getLink(''));
const isRoot = $derived(node.parent === null);
const parentLink = $derived(getLink(node.parent ? node.parent.path : ''));
const parents = $derived(node.parents);
diff --git a/web/src/lib/components/timeline/actions/TimelineKeyboardActions.svelte b/web/src/lib/components/timeline/actions/TimelineKeyboardActions.svelte
index ebb671d491..790ffe7e2b 100644
--- a/web/src/lib/components/timeline/actions/TimelineKeyboardActions.svelte
+++ b/web/src/lib/components/timeline/actions/TimelineKeyboardActions.svelte
@@ -122,7 +122,9 @@
}
});
+ // svelte-ignore state_referenced_locally
const setFocusTo = setFocusToInit.bind(undefined, scrollToAsset, timelineManager);
+ // svelte-ignore state_referenced_locally
const setFocusAsset = setFocusAssetInit.bind(undefined, scrollToAsset);
const handleOpenDateModal = async () => {
diff --git a/web/src/lib/modals/AlbumEditModal.svelte b/web/src/lib/modals/AlbumEditModal.svelte
index 386bf93084..b343ed7920 100644
--- a/web/src/lib/modals/AlbumEditModal.svelte
+++ b/web/src/lib/modals/AlbumEditModal.svelte
@@ -13,7 +13,9 @@
let { album, onClose }: Props = $props();
+ // svelte-ignore state_referenced_locally
let albumName = $state(album.albumName);
+ // svelte-ignore state_referenced_locally
let description = $state(album.description);
const onSubmit = async () => {
diff --git a/web/src/lib/modals/ApiKeyUpdateModal.svelte b/web/src/lib/modals/ApiKeyUpdateModal.svelte
index 7de8032d80..9f143b6872 100644
--- a/web/src/lib/modals/ApiKeyUpdateModal.svelte
+++ b/web/src/lib/modals/ApiKeyUpdateModal.svelte
@@ -20,8 +20,10 @@
? Object.values(Permission).filter((permission) => permission !== Permission.All)
: permissions;
+ // svelte-ignore state_referenced_locally
let name = $state(apiKey.name);
- let selectedPermissions = $state(mapPermissions(apiKey.permissions));
+ // svelte-ignore state_referenced_locally
+ let selectedPermissions = $state(mapPermissions(apiKey.permissions));
const onSubmit = async () => {
const success = await handleUpdateApiKey(apiKey, {
diff --git a/web/src/lib/modals/AssetChangeDateModal.svelte b/web/src/lib/modals/AssetChangeDateModal.svelte
index e35c7d3ac1..2cc69b878c 100644
--- a/web/src/lib/modals/AssetChangeDateModal.svelte
+++ b/web/src/lib/modals/AssetChangeDateModal.svelte
@@ -20,9 +20,11 @@
let { initialDate = DateTime.now(), initialTimeZone, timezoneInput = true, asset, onClose }: Props = $props();
+ // svelte-ignore state_referenced_locally
let selectedDate = $state(initialDate.toFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"));
const timezones = $derived(getTimezones(selectedDate));
+ // svelte-ignore state_referenced_locally
let selectedOption = $state(getPreferredTimeZone(initialDate, initialTimeZone, getTimezones(selectedDate)));
const onSubmit = async () => {
diff --git a/web/src/lib/modals/AssetSelectionChangeDateModal.svelte b/web/src/lib/modals/AssetSelectionChangeDateModal.svelte
index a9eb6692e2..91be7615d5 100644
--- a/web/src/lib/modals/AssetSelectionChangeDateModal.svelte
+++ b/web/src/lib/modals/AssetSelectionChangeDateModal.svelte
@@ -23,6 +23,7 @@
let showRelative = $state(false);
let selectedDuration = $state(0);
+ // svelte-ignore state_referenced_locally
let selectedDate = $state(initialDate.toFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"));
const timezones = $derived(getTimezones(selectedDate));
// svelte-ignore state_referenced_locally
diff --git a/web/src/lib/modals/GeolocationPointPickerModal.svelte b/web/src/lib/modals/GeolocationPointPickerModal.svelte
index 2d9fb5e7a2..b987150cf8 100644
--- a/web/src/lib/modals/GeolocationPointPickerModal.svelte
+++ b/web/src/lib/modals/GeolocationPointPickerModal.svelte
@@ -45,8 +45,11 @@
return { lat: latitude, lng: longitude };
});
- let point = $state(initialPoint ?? assetPoint);
+ // svelte-ignore state_referenced_locally
+ let point = $state(initialPoint ?? assetPoint);
+ // svelte-ignore state_referenced_locally
let zoom = $state(point ? 12.5 : 1);
+ // svelte-ignore state_referenced_locally
let center = $state(point ?? geolocationManager.lastPoint);
$effect(() => {
diff --git a/web/src/lib/modals/LibraryExclusionPatternEditModal.svelte b/web/src/lib/modals/LibraryExclusionPatternEditModal.svelte
index d2fc52a804..f59cfbcff2 100644
--- a/web/src/lib/modals/LibraryExclusionPatternEditModal.svelte
+++ b/web/src/lib/modals/LibraryExclusionPatternEditModal.svelte
@@ -12,6 +12,7 @@
};
const { library, exclusionPattern: oldValue, onClose }: Props = $props();
+ // svelte-ignore state_referenced_locally
let newValue = $state(oldValue);
const onSubmit = async () => {
diff --git a/web/src/lib/modals/LibraryFolderEditModal.svelte b/web/src/lib/modals/LibraryFolderEditModal.svelte
index 53294b29ae..29a9869436 100644
--- a/web/src/lib/modals/LibraryFolderEditModal.svelte
+++ b/web/src/lib/modals/LibraryFolderEditModal.svelte
@@ -13,6 +13,7 @@
const { library, folder: oldValue, onClose }: Props = $props();
+ // svelte-ignore state_referenced_locally
let newValue = $state(oldValue);
const onSubmit = async () => {
diff --git a/web/src/lib/modals/MapSettingsModal.svelte b/web/src/lib/modals/MapSettingsModal.svelte
index 1f08f37770..91380dc85e 100644
--- a/web/src/lib/modals/MapSettingsModal.svelte
+++ b/web/src/lib/modals/MapSettingsModal.svelte
@@ -12,6 +12,7 @@
};
let { settings: initialValues, onClose }: Props = $props();
+ // svelte-ignore state_referenced_locally
let settings = $state(initialValues);
let customDateRange = $state(!!settings.dateAfter || !!settings.dateBefore);
diff --git a/web/src/lib/modals/SearchFilterModal.svelte b/web/src/lib/modals/SearchFilterModal.svelte
index 61dd12ba14..639b2bd54b 100644
--- a/web/src/lib/modals/SearchFilterModal.svelte
+++ b/web/src/lib/modals/SearchFilterModal.svelte
@@ -95,6 +95,7 @@
};
};
+ // svelte-ignore state_referenced_locally
let filter: SearchFilter = $state(asFilter(searchQuery));
const resetForm = () => {
diff --git a/web/src/lib/modals/TagCreateModal.svelte b/web/src/lib/modals/TagCreateModal.svelte
index 268053a4cf..daa33ffb65 100644
--- a/web/src/lib/modals/TagCreateModal.svelte
+++ b/web/src/lib/modals/TagCreateModal.svelte
@@ -12,6 +12,7 @@
const { onClose, baseTag }: Props = $props();
+ // svelte-ignore state_referenced_locally
let tagValue = $state(baseTag?.path ? `${baseTag.path}/` : '');
const onSubmit = async () => {
diff --git a/web/src/lib/modals/TagEditModal.svelte b/web/src/lib/modals/TagEditModal.svelte
index d1d4670644..991e4639ae 100644
--- a/web/src/lib/modals/TagEditModal.svelte
+++ b/web/src/lib/modals/TagEditModal.svelte
@@ -14,6 +14,7 @@
const { tag, onClose }: Props = $props();
+ // svelte-ignore state_referenced_locally
let tagColor = $state(tag.color ?? '');
const onSubmit = async () => {
diff --git a/web/src/routes/(user)/explore/+page.svelte b/web/src/routes/(user)/explore/+page.svelte
index 41ebd6b8ca..99eaed5914 100644
--- a/web/src/routes/(user)/explore/+page.svelte
+++ b/web/src/routes/(user)/explore/+page.svelte
@@ -24,7 +24,7 @@
};
let places = $derived(getFieldItems(data.items, 'exifInfo.city'));
- let people = $state(data.response.people);
+ let people = $derived(data.response.people);
let hasPeople = $derived(data.response.total > 0);
diff --git a/web/src/routes/(user)/people/+page.svelte b/web/src/routes/(user)/people/+page.svelte
index eadc295773..ddaea1864d 100644
--- a/web/src/routes/(user)/people/+page.svelte
+++ b/web/src/routes/(user)/people/+page.svelte
@@ -36,7 +36,7 @@
let searchName = $state('');
let newName = $state('');
let currentPage = $state(1);
- let nextPage = $state(data.people.hasNextPage ? 2 : null);
+ let nextPage = $derived(data.people.hasNextPage ? 2 : null);
let personMerge1 = $state();
let personMerge2 = $state();
let potentialMergePeople: PersonResponseDto[] = $state([]);
diff --git a/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/UnmergeFaceSelector.svelte b/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/UnmergeFaceSelector.svelte
index 4296ed7e5f..d97e840098 100644
--- a/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/UnmergeFaceSelector.svelte
+++ b/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/UnmergeFaceSelector.svelte
@@ -1,4 +1,5 @@