fix(web): dynamically import wasm module (#16261)

* dynamically import wasm module

* remove unused import
This commit is contained in:
Mert 2025-02-22 21:16:06 +03:00 committed by GitHub
parent e4b6efc1f5
commit 4376fd72b7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 77 additions and 77 deletions

View File

@ -97,7 +97,7 @@
{#each dateGroups as dateGroup, groupIndex (dateGroup.date)} {#each dateGroups as dateGroup, groupIndex (dateGroup.date)}
{@const display = {@const display =
dateGroup.intersecting || !!dateGroup.assets.some((asset) => asset.id === $assetStore.pendingScrollAssetId)} dateGroup.intersecting || !!dateGroup.assets.some((asset) => asset.id === $assetStore.pendingScrollAssetId)}
{@const geometry = dateGroup.geometry} {@const geometry = dateGroup.geometry!}
<div <div
id="date-group" id="date-group"

View File

@ -72,7 +72,7 @@
<div use:resizeObserver={({ height }) => $assetStore.updateBucketDateGroup(bucket, dateGroup, { height })}> <div use:resizeObserver={({ height }) => $assetStore.updateBucketDateGroup(bucket, dateGroup, { height })}>
<div <div
class="flex z-[100] sticky top-[-1px] pt-7 pb-5 h-6 place-items-center text-xs font-medium text-immich-fg bg-immich-bg dark:bg-immich-dark-bg dark:text-immich-dark-fg md:text-sm" class="flex z-[100] sticky top-[-1px] pt-7 pb-5 h-6 place-items-center text-xs font-medium text-immich-fg bg-immich-bg dark:bg-immich-dark-bg dark:text-immich-dark-fg md:text-sm"
style:width={dateGroup.geometry.containerWidth + 'px'} style:width={dateGroup.geometry!.containerWidth + 'px'}
> >
<span class="w-full truncate first-letter:capitalize"> <span class="w-full truncate first-letter:capitalize">
{dateGroup.groupTitle} {dateGroup.groupTitle}
@ -81,8 +81,8 @@
<div <div
class="relative overflow-clip" class="relative overflow-clip"
style:height={dateGroup.geometry.containerHeight + 'px'} style:height={dateGroup.geometry!.containerHeight + 'px'}
style:width={dateGroup.geometry.containerWidth + 'px'} style:width={dateGroup.geometry!.containerWidth + 'px'}
style:visibility={'hidden'} style:visibility={'hidden'}
></div> ></div>
</div> </div>

View File

@ -8,7 +8,7 @@
import type { Viewport } from '$lib/stores/assets.store'; import type { Viewport } from '$lib/stores/assets.store';
import { showDeleteModal } from '$lib/stores/preferences.store'; import { showDeleteModal } from '$lib/stores/preferences.store';
import { deleteAssets } from '$lib/utils/actions'; import { deleteAssets } from '$lib/utils/actions';
import { archiveAssets, cancelMultiselect, getJustifiedLayoutFromAssets } from '$lib/utils/asset-utils'; import { archiveAssets, cancelMultiselect } from '$lib/utils/asset-utils';
import { featureFlags } from '$lib/stores/server-config.store'; import { featureFlags } from '$lib/stores/server-config.store';
import { handleError } from '$lib/utils/handle-error'; import { handleError } from '$lib/utils/handle-error';
import { navigate } from '$lib/utils/navigation'; import { navigate } from '$lib/utils/navigation';
@ -307,14 +307,15 @@
let isTrashEnabled = $derived($featureFlags.loaded && $featureFlags.trash); let isTrashEnabled = $derived($featureFlags.loaded && $featureFlags.trash);
let idsSelectedAssets = $derived(assetInteraction.selectedAssetsArray.map(({ id }) => id)); let idsSelectedAssets = $derived(assetInteraction.selectedAssetsArray.map(({ id }) => id));
let geometry = $derived( let geometry = $derived.by(async () => {
getJustifiedLayoutFromAssets(assets, { const { getJustifiedLayoutFromAssets } = await import('$lib/utils/layout-utils');
return getJustifiedLayoutFromAssets(assets, {
spacing: 2, spacing: 2,
rowWidth: Math.floor(viewport.width),
heightTolerance: 0.15, heightTolerance: 0.15,
rowHeight: 235, rowHeight: 235,
}), rowWidth: Math.floor(viewport.width),
); });
});
$effect(() => { $effect(() => {
if (!lastAssetMouseEvent) { if (!lastAssetMouseEvent) {
@ -350,6 +351,7 @@
{/if} {/if}
{#if assets.length > 0} {#if assets.length > 0}
{#await geometry then geometry}
<div class="relative" style="height: {geometry.containerHeight}px;width: {geometry.containerWidth}px "> <div class="relative" style="height: {geometry.containerHeight}px;width: {geometry.containerWidth}px ">
{#each assets as asset, i} {#each assets as asset, i}
{@const top = geometry.getTop(i)} {@const top = geometry.getTop(i)}
@ -391,6 +393,7 @@
</div> </div>
{/each} {/each}
</div> </div>
{/await}
{/if} {/if}
<!-- Overlay Asset Viewer --> <!-- Overlay Asset Viewer -->

View File

@ -1,7 +1,6 @@
import { locale } from '$lib/stores/preferences.store'; import { locale } from '$lib/stores/preferences.store';
import { getKey } from '$lib/utils'; import { getKey } from '$lib/utils';
import { AssetGridTaskManager } from '$lib/utils/asset-store-task-manager'; import { AssetGridTaskManager } from '$lib/utils/asset-store-task-manager';
import { getJustifiedLayoutFromAssets } from '$lib/utils/asset-utils';
import { generateId } from '$lib/utils/generate-id'; import { generateId } from '$lib/utils/generate-id';
import type { AssetGridRouteSearchParams } from '$lib/utils/navigation'; import type { AssetGridRouteSearchParams } from '$lib/utils/navigation';
import { fromLocalDateTime, splitBucketIntoDateGroups, type DateGroup } from '$lib/utils/timeline-util'; import { fromLocalDateTime, splitBucketIntoDateGroups, type DateGroup } from '$lib/utils/timeline-util';
@ -436,7 +435,7 @@ export class AssetStore {
private async initialLayout(changedWidth: boolean) { private async initialLayout(changedWidth: boolean) {
for (const bucket of this.buckets) { for (const bucket of this.buckets) {
this.updateGeometry(bucket, changedWidth); await this.updateGeometry(bucket, changedWidth);
} }
this.timelineHeight = this.buckets.reduce((accumulator, b) => accumulator + b.bucketHeight, 0); this.timelineHeight = this.buckets.reduce((accumulator, b) => accumulator + b.bucketHeight, 0);
@ -454,7 +453,7 @@ export class AssetStore {
this.emit(false); this.emit(false);
} }
private updateGeometry(bucket: AssetBucket, invalidateHeight: boolean) { private async updateGeometry(bucket: AssetBucket, invalidateHeight: boolean) {
if (invalidateHeight) { if (invalidateHeight) {
bucket.isBucketHeightActual = false; bucket.isBucketHeightActual = false;
bucket.measured = false; bucket.measured = false;
@ -477,6 +476,8 @@ export class AssetStore {
rowHeight: 235, rowHeight: 235,
rowWidth: Math.floor(viewportWidth), rowWidth: Math.floor(viewportWidth),
}; };
// TODO: move this import and make this method sync after https://github.com/sveltejs/kit/issues/7805 is fixed
const { getJustifiedLayoutFromAssets } = await import('$lib/utils/layout-utils');
for (const assetGroup of bucket.dateGroups) { for (const assetGroup of bucket.dateGroups) {
if (!assetGroup.heightActual) { if (!assetGroup.heightActual) {
const unwrappedWidth = (3 / 2) * assetGroup.assets.length * THUMBNAIL_HEIGHT * (7 / 10); const unwrappedWidth = (3 / 2) * assetGroup.assets.length * THUMBNAIL_HEIGHT * (7 / 10);
@ -552,7 +553,7 @@ export class AssetStore {
bucket.assets = assets; bucket.assets = assets;
bucket.dateGroups = splitBucketIntoDateGroups(bucket, get(locale)); bucket.dateGroups = splitBucketIntoDateGroups(bucket, get(locale));
this.maxBucketAssets = Math.max(this.maxBucketAssets, assets.length); this.maxBucketAssets = Math.max(this.maxBucketAssets, assets.length);
this.updateGeometry(bucket, true); await this.updateGeometry(bucket, true);
this.timelineHeight = this.buckets.reduce((accumulator, b) => accumulator + b.bucketHeight, 0); this.timelineHeight = this.buckets.reduce((accumulator, b) => accumulator + b.bucketHeight, 0);
bucket.loaded(); bucket.loaded();
this.notifyListeners({ type: 'loaded', bucket }); this.notifyListeners({ type: 'loaded', bucket });
@ -679,7 +680,7 @@ export class AssetStore {
return bDate.diff(aDate).milliseconds; return bDate.diff(aDate).milliseconds;
}); });
bucket.dateGroups = splitBucketIntoDateGroups(bucket, get(locale)); bucket.dateGroups = splitBucketIntoDateGroups(bucket, get(locale));
this.updateGeometry(bucket, true); void this.updateGeometry(bucket, true);
} }
this.emit(true); this.emit(true);
@ -821,7 +822,7 @@ export class AssetStore {
} }
if (changed) { if (changed) {
bucket.dateGroups = splitBucketIntoDateGroups(bucket, get(locale)); bucket.dateGroups = splitBucketIntoDateGroups(bucket, get(locale));
this.updateGeometry(bucket, true); void this.updateGeometry(bucket, true);
} }
} }

View File

@ -12,7 +12,6 @@ import { downloadRequest, getKey, withError } from '$lib/utils';
import { createAlbum } from '$lib/utils/album-utils'; import { createAlbum } from '$lib/utils/album-utils';
import { getByteUnitString } from '$lib/utils/byte-units'; import { getByteUnitString } from '$lib/utils/byte-units';
import { getFormatter } from '$lib/utils/i18n'; import { getFormatter } from '$lib/utils/i18n';
import { JustifiedLayout, type LayoutOptions } from '@immich/justified-layout-wasm';
import { import {
addAssetsToAlbum as addAssets, addAssetsToAlbum as addAssets,
createStack, createStack,
@ -588,13 +587,3 @@ export const copyImageToClipboard = async (source: HTMLImageElement | string) =>
const blob = source instanceof HTMLImageElement ? await imgToBlob(source) : await urlToBlob(source); const blob = source instanceof HTMLImageElement ? await imgToBlob(source) : await urlToBlob(source);
await navigator.clipboard.write([new ClipboardItem({ [blob.type]: blob })]); await navigator.clipboard.write([new ClipboardItem({ [blob.type]: blob })]);
}; };
export function getJustifiedLayoutFromAssets(assets: AssetResponseDto[], options: LayoutOptions) {
const aspectRatios = new Float32Array(assets.length);
// eslint-disable-next-line unicorn/no-for-loop
for (let i = 0; i < assets.length; i++) {
const { width, height } = getAssetRatio(assets[i]);
aspectRatios[i] = width / height;
}
return new JustifiedLayout(aspectRatios, options);
}

View File

@ -0,0 +1,14 @@
import { getAssetRatio } from '$lib/utils/asset-utils';
// note: it's important that this is not imported in more than one file due to https://github.com/sveltejs/kit/issues/7805
import { JustifiedLayout, type LayoutOptions } from '@immich/justified-layout-wasm';
import type { AssetResponseDto } from '@immich/sdk';
export function getJustifiedLayoutFromAssets(assets: AssetResponseDto[], options: LayoutOptions) {
const aspectRatios = new Float32Array(assets.length);
// eslint-disable-next-line unicorn/no-for-loop
for (let i = 0; i < assets.length; i++) {
const { width, height } = getAssetRatio(assets[i]);
aspectRatios[i] = width / height;
}
return new JustifiedLayout(aspectRatios, options);
}

View File

@ -1,6 +1,6 @@
import type { AssetBucket } from '$lib/stores/assets.store'; import type { AssetBucket } from '$lib/stores/assets.store';
import { locale } from '$lib/stores/preferences.store'; import { locale } from '$lib/stores/preferences.store';
import { JustifiedLayout } from '@immich/justified-layout-wasm'; import type { JustifiedLayout } from '@immich/justified-layout-wasm';
import type { AssetResponseDto } from '@immich/sdk'; import type { AssetResponseDto } from '@immich/sdk';
import { groupBy, memoize, sortBy } from 'lodash-es'; import { groupBy, memoize, sortBy } from 'lodash-es';
import { DateTime } from 'luxon'; import { DateTime } from 'luxon';
@ -13,7 +13,7 @@ export type DateGroup = {
height: number; height: number;
heightActual: boolean; heightActual: boolean;
intersecting: boolean; intersecting: boolean;
geometry: JustifiedLayout; geometry: JustifiedLayout | null;
bucket: AssetBucket; bucket: AssetBucket;
}; };
export type ScrubberListener = ( export type ScrubberListener = (
@ -80,13 +80,6 @@ export function formatGroupTitle(_date: DateTime): string {
return date.toLocaleString(groupDateFormat); return date.toLocaleString(groupDateFormat);
} }
const emptyGeometry = new JustifiedLayout(Float32Array.from([]), {
rowHeight: 1,
heightTolerance: 0,
rowWidth: 1,
spacing: 0,
});
const formatDateGroupTitle = memoize(formatGroupTitle); const formatDateGroupTitle = memoize(formatGroupTitle);
export function splitBucketIntoDateGroups(bucket: AssetBucket, locale: string | undefined): DateGroup[] { export function splitBucketIntoDateGroups(bucket: AssetBucket, locale: string | undefined): DateGroup[] {
@ -104,7 +97,7 @@ export function splitBucketIntoDateGroups(bucket: AssetBucket, locale: string |
height: 0, height: 0,
heightActual: false, heightActual: false,
intersecting: false, intersecting: false,
geometry: emptyGeometry, geometry: null,
bucket, bucket,
}; };
}); });