diff options
| author | tamaina <tamaina@hotmail.co.jp> | 2022-12-30 12:00:50 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-12-30 12:00:50 +0900 |
| commit | 8b46edeccf5a8907afbb871e3eb5b3b8eef967a8 (patch) | |
| tree | 1411e540282c4b0d2365d3a2c7e01902a3403a3a /packages/frontend/src | |
| parent | fix(client): fix position calculation of nested context menu (diff) | |
| download | misskey-8b46edeccf5a8907afbb871e3eb5b3b8eef967a8.tar.gz misskey-8b46edeccf5a8907afbb871e3eb5b3b8eef967a8.tar.bz2 misskey-8b46edeccf5a8907afbb871e3eb5b3b8eef967a8.zip | |
enhance: Proxy custom emojis to reduce image size and accelerate the frontend (#9431)
* fix(server): /emoji to accept `@.` host expression
* fix(client): use MkEmoji for custom emoji in MkEmojiPicker
* change convertToWebp
* nanka iroiro
* remove
* fix
* nearLosslessは労多くして益少なしなのでやめる
* do not cleanup tmp for development
* update sharp.js to 0.31.3
* mixed: true
* fix MkAutocomplete of 912791b3ab
* clean up
* https://github.com/misskey-dev/misskey/pull/9431#discussion_r1059215943
Diffstat (limited to 'packages/frontend/src')
| -rw-r--r-- | packages/frontend/src/components/MkAutocomplete.vue | 31 | ||||
| -rw-r--r-- | packages/frontend/src/components/MkEmojiPicker.vue | 1 | ||||
| -rw-r--r-- | packages/frontend/src/components/MkMediaImage.vue | 2 | ||||
| -rw-r--r-- | packages/frontend/src/components/global/MkAvatar.vue | 2 | ||||
| -rw-r--r-- | packages/frontend/src/components/global/MkEmoji.vue | 2 | ||||
| -rw-r--r-- | packages/frontend/src/pages/user/index.photos.vue | 2 | ||||
| -rw-r--r-- | packages/frontend/src/scripts/get-static-image-url.ts | 19 | ||||
| -rw-r--r-- | packages/frontend/src/scripts/media-proxy.ts | 34 | ||||
| -rw-r--r-- | packages/frontend/src/scripts/url.ts | 5 | ||||
| -rw-r--r-- | packages/frontend/src/widgets/photos.vue | 2 |
10 files changed, 62 insertions, 38 deletions
diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue index 6b1b48e480..d150436fb2 100644 --- a/packages/frontend/src/components/MkAutocomplete.vue +++ b/packages/frontend/src/components/MkAutocomplete.vue @@ -16,12 +16,12 @@ </li> </ol> <ol v-else-if="emojis.length > 0" ref="suggests" class="emojis"> - <li v-for="emoji in emojis" tabindex="-1" @click="complete(type, emoji.emoji)" @keydown="onKeydown"> - <span v-if="emoji.isCustomEmoji" class="emoji"><img :src="`/emoji/${emoji.name}.webp`" :alt="emoji.emoji"/></span> - <span v-else-if="defaultStore.state.emojiStyle != 'native'" class="emoji"><img :src="emoji.url" :alt="emoji.emoji"/></span> - <span v-else class="emoji">{{ emoji.emoji }}</span> + <li v-for="emoji in emojis" tabindex="-1" :key="emoji.emoji" @click="complete(type, emoji.emoji)" @keydown="onKeydown"> + <div class="emoji"> + <MkEmoji :emoji="emoji.emoji" /> + </div> <!-- eslint-disable-next-line vue/no-v-html --> - <span class="name" v-html="emoji.name.replace(q, `<b>${q}</b>`)"></span> + <span class="name" v-html="emoji.name.replace(q ?? '', `<b>${q}</b>`)"></span> <span v-if="emoji.aliasOf" class="alias">({{ emoji.aliasOf }})</span> </li> </ol> @@ -37,7 +37,6 @@ import { markRaw, ref, onUpdated, onMounted, onBeforeUnmount, nextTick, watch } from 'vue'; import contains from '@/scripts/contains'; import { char2twemojiFilePath, char2fluentEmojiFilePath } from '@/scripts/emoji-base'; -import { getStaticImageUrl } from '@/scripts/get-static-image-url'; import { acct } from '@/filters/user'; import * as os from '@/os'; import { MFM_TAGS } from '@/scripts/mfm-tags'; @@ -49,9 +48,13 @@ import { i18n } from '@/i18n'; type EmojiDef = { emoji: string; name: string; + url: string; aliasOf?: string; - url?: string; - isCustomEmoji?: boolean; +} | { + emoji: string; + name: string; + aliasOf?: string; + isCustomEmoji?: true; }; const lib = emojilist.filter(x => x.category !== 'flags'); @@ -87,7 +90,6 @@ for (const x of customEmojis) { emojiDefinitions.push({ name: x.name, emoji: `:${x.name}:`, - url: x.url, isCustomEmoji: true, }); @@ -97,7 +99,6 @@ for (const x of customEmojis) { name: alias, aliasOf: x.name, emoji: `:${x.name}:`, - url: x.url, isCustomEmoji: true, }); } @@ -452,14 +453,20 @@ onBeforeUnmount(() => { > .emojis > li { .emoji { - display: inline-block; + display: flex; margin: 0 4px 0 0; + height: 24px; width: 24px; + justify-content: center; + align-items: center; + font-size: 20px; > img { + height: 24px; width: 24px; - vertical-align: bottom; + object-fit: scale-down; } + } .alias { diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue index e9e265a916..c94da97747 100644 --- a/packages/frontend/src/components/MkEmojiPicker.vue +++ b/packages/frontend/src/components/MkEmojiPicker.vue @@ -81,7 +81,6 @@ import { ref, computed, watch, onMounted } from 'vue'; import * as Misskey from 'misskey-js'; import XSection from '@/components/MkEmojiPicker.section.vue'; import { emojilist, UnicodeEmojiDef, unicodeEmojiCategories as categories } from '@/scripts/emojilist'; -import { getStaticImageUrl } from '@/scripts/get-static-image-url'; import Ripple from '@/components/MkRipple.vue'; import * as os from '@/os'; import { isTouchUsing } from '@/scripts/touch'; diff --git a/packages/frontend/src/components/MkMediaImage.vue b/packages/frontend/src/components/MkMediaImage.vue index 56570eaa05..9912faffe8 100644 --- a/packages/frontend/src/components/MkMediaImage.vue +++ b/packages/frontend/src/components/MkMediaImage.vue @@ -23,7 +23,7 @@ <script lang="ts" setup> import { watch } from 'vue'; import * as misskey from 'misskey-js'; -import { getStaticImageUrl } from '@/scripts/get-static-image-url'; +import { getStaticImageUrl } from '@/scripts/media-proxy'; import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue'; import { defaultStore } from '@/store'; diff --git a/packages/frontend/src/components/global/MkAvatar.vue b/packages/frontend/src/components/global/MkAvatar.vue index 5f3e3c176d..60b8b3b1db 100644 --- a/packages/frontend/src/components/global/MkAvatar.vue +++ b/packages/frontend/src/components/global/MkAvatar.vue @@ -12,7 +12,7 @@ <script lang="ts" setup> import { onMounted, watch } from 'vue'; import * as misskey from 'misskey-js'; -import { getStaticImageUrl } from '@/scripts/get-static-image-url'; +import { getStaticImageUrl } from '@/scripts/media-proxy'; import { extractAvgColorFromBlurhash } from '@/scripts/extract-avg-color-from-blurhash'; import { acct, userPage } from '@/filters/user'; import MkUserOnlineIndicator from '@/components/MkUserOnlineIndicator.vue'; diff --git a/packages/frontend/src/components/global/MkEmoji.vue b/packages/frontend/src/components/global/MkEmoji.vue index bf6be7491d..67e9ef428a 100644 --- a/packages/frontend/src/components/global/MkEmoji.vue +++ b/packages/frontend/src/components/global/MkEmoji.vue @@ -7,7 +7,7 @@ <script lang="ts" setup> import { computed } from 'vue'; -import { getStaticImageUrl } from '@/scripts/get-static-image-url'; +import { getStaticImageUrl } from '@/scripts/media-proxy'; import { char2twemojiFilePath, char2fluentEmojiFilePath } from '@/scripts/emoji-base'; import { defaultStore } from '@/store'; import { getEmojiName } from '@/scripts/emojilist'; diff --git a/packages/frontend/src/pages/user/index.photos.vue b/packages/frontend/src/pages/user/index.photos.vue index b33979a79d..fd975b52bb 100644 --- a/packages/frontend/src/pages/user/index.photos.vue +++ b/packages/frontend/src/pages/user/index.photos.vue @@ -21,7 +21,7 @@ <script lang="ts" setup> import { onMounted } from 'vue'; import * as misskey from 'misskey-js'; -import { getStaticImageUrl } from '@/scripts/get-static-image-url'; +import { getStaticImageUrl } from '@/scripts/media-proxy'; import { notePage } from '@/filters/note'; import * as os from '@/os'; import MkContainer from '@/components/MkContainer.vue'; diff --git a/packages/frontend/src/scripts/get-static-image-url.ts b/packages/frontend/src/scripts/get-static-image-url.ts deleted file mode 100644 index cbd1761983..0000000000 --- a/packages/frontend/src/scripts/get-static-image-url.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { url as instanceUrl } from '@/config'; -import * as url from '@/scripts/url'; - -export function getStaticImageUrl(baseUrl: string): string { - const u = new URL(baseUrl); - if (u.href.startsWith(`${instanceUrl}/proxy/`)) { - // もう既にproxyっぽそうだったらsearchParams付けるだけ - u.searchParams.set('static', '1'); - return u.href; - } - - // 拡張子がないとキャッシュしてくれないCDNがあるのでダミーの名前を指定する - const dummy = `${encodeURIComponent(`${u.host}${u.pathname}`)}.webp`; - - return `${instanceUrl}/proxy/${dummy}?${url.query({ - url: u.href, - static: '1', - })}`; -} diff --git a/packages/frontend/src/scripts/media-proxy.ts b/packages/frontend/src/scripts/media-proxy.ts index aaf7f9e610..bea164e7c8 100644 --- a/packages/frontend/src/scripts/media-proxy.ts +++ b/packages/frontend/src/scripts/media-proxy.ts @@ -1,7 +1,15 @@ -import { query } from '@/scripts/url'; +import { query, appendQuery } from '@/scripts/url'; import { url } from '@/config'; export function getProxiedImageUrl(imageUrl: string, type?: 'preview'): string { + if (imageUrl.startsWith(`${url}/proxy/`) || imageUrl.startsWith('/proxy/')) { + // もう既にproxyっぽそうだったらsearchParams付けるだけ + return appendQuery(imageUrl, query({ + fallback: '1', + ...(type ? { [type]: '1' } : {}), + })); + } + return `${url}/proxy/image.webp?${query({ url: imageUrl, fallback: '1', @@ -13,3 +21,27 @@ export function getProxiedImageUrlNullable(imageUrl: string | null | undefined, if (imageUrl == null) return null; return getProxiedImageUrl(imageUrl, type); } + +export function getStaticImageUrl(baseUrl: string): string { + const u = baseUrl.startsWith('http') ? new URL(baseUrl) : new URL(baseUrl, url); + + if (u.href.startsWith(`${url}/proxy/`)) { + // もう既にproxyっぽそうだったらsearchParams付けるだけ + u.searchParams.set('static', '1'); + return u.href; + } + + if (u.href.startsWith(`${url}/emoji/`)) { + // もう既にemojiっぽそうだったらsearchParams付けるだけ + u.searchParams.set('static', '1'); + return u.href; + } + + // 拡張子がないとキャッシュしてくれないCDNがあるのでダミーの名前を指定する + const dummy = `${encodeURIComponent(`${u.host}${u.pathname}`)}.webp`; + + return `${url}/proxy/${dummy}?${query({ + url: u.href, + static: '1', + })}`; +} diff --git a/packages/frontend/src/scripts/url.ts b/packages/frontend/src/scripts/url.ts index 86735de9f0..b6a997449a 100644 --- a/packages/frontend/src/scripts/url.ts +++ b/packages/frontend/src/scripts/url.ts @@ -1,3 +1,8 @@ +/* objを検査して + * 1. 配列に何も入っていない時はクエリを付けない + * 2. プロパティがundefinedの時はクエリを付けない + * (new URLSearchParams(obj)ではそこまで丁寧なことをしてくれない) + */ export function query(obj: Record<string, any>): string { const params = Object.entries(obj) .filter(([, v]) => Array.isArray(v) ? v.length : v !== undefined) diff --git a/packages/frontend/src/widgets/photos.vue b/packages/frontend/src/widgets/photos.vue index 4ad5324053..65d1de1385 100644 --- a/packages/frontend/src/widgets/photos.vue +++ b/packages/frontend/src/widgets/photos.vue @@ -20,7 +20,7 @@ import { onMounted, onUnmounted, reactive, ref } from 'vue'; import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import { stream } from '@/stream'; -import { getStaticImageUrl } from '@/scripts/get-static-image-url'; +import { getStaticImageUrl } from '@/scripts/media-proxy'; import * as os from '@/os'; import MkContainer from '@/components/MkContainer.vue'; import { defaultStore } from '@/store'; |