merge: 장수일람 렌더링 성능 개선을 통합한다
This commit is contained in:
@@ -130,6 +130,18 @@ const generals = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const pyaScaleGenerals = Array.from({ length: 845 }, (_, index) => {
|
||||||
|
const source = generals[index % generals.length]!;
|
||||||
|
return {
|
||||||
|
...source,
|
||||||
|
id: index + 1,
|
||||||
|
name: `성능장수${index + 1}`,
|
||||||
|
ownerName: null,
|
||||||
|
picture: `performance/general-${index + 1}.png`,
|
||||||
|
imageServer: 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const npcGenerals = [
|
const npcGenerals = [
|
||||||
{
|
{
|
||||||
id: 10,
|
id: 10,
|
||||||
@@ -187,7 +199,8 @@ const install = async (
|
|||||||
page: Page,
|
page: Page,
|
||||||
mode: 'general' | 'no-general' | 'error-after-load' = 'general',
|
mode: 'general' | 'no-general' | 'error-after-load' = 'general',
|
||||||
accessPages: string[] = [],
|
accessPages: string[] = [],
|
||||||
requestedOperations: string[] = []
|
requestedOperations: string[] = [],
|
||||||
|
directoryRows = generals
|
||||||
) => {
|
) => {
|
||||||
let generalDirectoryCalls = 0;
|
let generalDirectoryCalls = 0;
|
||||||
await page.addInitScript((profile) => {
|
await page.addInitScript((profile) => {
|
||||||
@@ -260,7 +273,9 @@ const install = async (
|
|||||||
}
|
}
|
||||||
const sort = parseSort(route);
|
const sort = parseSort(route);
|
||||||
const rows =
|
const rows =
|
||||||
sort === 8 ? [...generals].sort((left, right) => left.killturn - right.killturn) : generals;
|
sort === 8
|
||||||
|
? [...directoryRows].sort((left, right) => left.killturn - right.killturn)
|
||||||
|
: directoryRows;
|
||||||
return response({ sort, generals: rows });
|
return response({ sort, generals: rows });
|
||||||
}
|
}
|
||||||
if (operation === 'public.getNpcList') {
|
if (operation === 'public.getNpcList') {
|
||||||
@@ -307,6 +322,48 @@ const installAccessBoundary = async (page: Page, accessPages: string[]) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
test('PYA-scale general directory mounts only the active responsive layout and defers portraits', async (
|
||||||
|
{ page },
|
||||||
|
testInfo
|
||||||
|
) => {
|
||||||
|
const requestedPortraits = new Set<string>();
|
||||||
|
page.on('request', (request) => {
|
||||||
|
if (request.url().includes('/performance/general-')) {
|
||||||
|
requestedPortraits.add(request.url());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await page.setViewportSize({ width: 1200, height: 900 });
|
||||||
|
await install(page, 'general', [], [], pyaScaleGenerals);
|
||||||
|
await page.goto('general-list');
|
||||||
|
|
||||||
|
await expect(page.locator('.general-table tbody tr[data-general-id]')).toHaveCount(845);
|
||||||
|
await expect(page.locator('.general-card-list [data-general-card-id]')).toHaveCount(0);
|
||||||
|
await expect(page.locator('.general-icon')).toHaveCount(845);
|
||||||
|
await expect(page.locator('.general-icon').first()).toHaveAttribute('loading', 'lazy');
|
||||||
|
await expect(page.locator('.general-icon').first()).toHaveAttribute('decoding', 'async');
|
||||||
|
await page.waitForTimeout(250);
|
||||||
|
expect(requestedPortraits.size).toBeLessThan(100);
|
||||||
|
const desktopMetrics = await page.evaluate(() => ({
|
||||||
|
domNodes: document.querySelectorAll('*').length,
|
||||||
|
documentHeight: document.documentElement.scrollHeight,
|
||||||
|
}));
|
||||||
|
await writeFile(
|
||||||
|
testInfo.outputPath('pya-scale-desktop-metrics.json'),
|
||||||
|
`${JSON.stringify({ ...desktopMetrics, requestedPortraits: requestedPortraits.size }, null, 2)}\n`
|
||||||
|
);
|
||||||
|
await page.screenshot({ path: testInfo.outputPath('pya-scale-desktop.png') });
|
||||||
|
|
||||||
|
await page.setViewportSize({ width: 500, height: 844 });
|
||||||
|
await expect(page.locator('.general-table')).toHaveCount(0);
|
||||||
|
await expect(page.locator('.general-card-list [data-general-card-id]')).toHaveCount(845);
|
||||||
|
await expect(page.locator('.general-icon')).toHaveCount(845);
|
||||||
|
await page.screenshot({ path: testInfo.outputPath('pya-scale-mobile.png') });
|
||||||
|
|
||||||
|
await page.setViewportSize({ width: 1200, height: 900 });
|
||||||
|
await expect(page.locator('.general-table tbody tr[data-general-id]')).toHaveCount(845);
|
||||||
|
await expect(page.locator('.general-card-list')).toHaveCount(0);
|
||||||
|
});
|
||||||
|
|
||||||
test('nation and general directories preserve the fixed legacy Chromium geometry', async ({ page }) => {
|
test('nation and general directories preserve the fixed legacy Chromium geometry', async ({ page }) => {
|
||||||
const accessPages: string[] = [];
|
const accessPages: string[] = [];
|
||||||
await install(page, 'general', accessPages);
|
await install(page, 'general', accessPages);
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { resolveGeneralIconUrl, useDefaultGeneralIcon } from '../../utils/generalIcon';
|
import { resolveGeneralIconUrl, useDefaultGeneralIcon } from '../../utils/generalIcon';
|
||||||
import { formatOfficerLevelText } from '../../utils/nationFormat';
|
import { formatOfficerLevelText } from '../../utils/nationFormat';
|
||||||
import { getNpcColor } from '../../utils/npcColor';
|
import { getNpcColor } from '../../utils/npcColor';
|
||||||
@@ -29,6 +31,26 @@ const props = withDefaults(
|
|||||||
|
|
||||||
const emit = defineEmits<{ sort: [value: number] }>();
|
const emit = defineEmits<{ sort: [value: number] }>();
|
||||||
|
|
||||||
|
const narrowViewportQuery =
|
||||||
|
typeof window !== 'undefined' && typeof window.matchMedia === 'function'
|
||||||
|
? window.matchMedia('(max-width: 600px)')
|
||||||
|
: null;
|
||||||
|
const narrowViewport = ref(narrowViewportQuery?.matches ?? false);
|
||||||
|
const renderCardLayout = computed(() => props.layout === 'card' || narrowViewport.value);
|
||||||
|
const updateNarrowViewport = (event: MediaQueryListEvent): void => {
|
||||||
|
narrowViewport.value = event.matches;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (!narrowViewportQuery) return;
|
||||||
|
narrowViewport.value = narrowViewportQuery.matches;
|
||||||
|
narrowViewportQuery.addEventListener('change', updateNarrowViewport);
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
narrowViewportQuery?.removeEventListener('change', updateNarrowViewport);
|
||||||
|
});
|
||||||
|
|
||||||
const headers: ReadonlyArray<Header> = [
|
const headers: ReadonlyArray<Header> = [
|
||||||
{ label: '얼 굴' },
|
{ label: '얼 굴' },
|
||||||
{ label: '이 름', sort: 0 },
|
{ label: '이 름', sort: 0 },
|
||||||
@@ -71,7 +93,7 @@ const sortHelp = (header: Header): string =>
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<table class="directory-table general-table legacy-bg0" :class="{ 'layout-card': layout === 'card' }">
|
<table v-if="!renderCardLayout" class="directory-table general-table legacy-bg0">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col style="width: 64px" />
|
<col style="width: 64px" />
|
||||||
<col style="width: 140px" />
|
<col style="width: 140px" />
|
||||||
@@ -134,6 +156,8 @@ const sortHelp = (header: Header): string =>
|
|||||||
class="general-icon"
|
class="general-icon"
|
||||||
width="64"
|
width="64"
|
||||||
height="64"
|
height="64"
|
||||||
|
loading="lazy"
|
||||||
|
decoding="async"
|
||||||
:src="resolveGeneralIconUrl(general)"
|
:src="resolveGeneralIconUrl(general)"
|
||||||
alt=""
|
alt=""
|
||||||
@error="useDefaultGeneralIcon"
|
@error="useDefaultGeneralIcon"
|
||||||
@@ -208,7 +232,7 @@ const sortHelp = (header: Header): string =>
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div class="general-card-list" :class="{ 'layout-card': layout === 'card' }">
|
<div v-if="renderCardLayout" class="general-card-list" :class="{ 'layout-card': layout === 'card' }">
|
||||||
<div v-if="loading" class="general-card-loading legacy-bg0">불러오는 중...</div>
|
<div v-if="loading" class="general-card-loading legacy-bg0">불러오는 중...</div>
|
||||||
<article
|
<article
|
||||||
v-for="general in generals"
|
v-for="general in generals"
|
||||||
@@ -229,6 +253,8 @@ const sortHelp = (header: Header): string =>
|
|||||||
class="general-icon"
|
class="general-icon"
|
||||||
width="64"
|
width="64"
|
||||||
height="64"
|
height="64"
|
||||||
|
loading="lazy"
|
||||||
|
decoding="async"
|
||||||
:src="resolveGeneralIconUrl(general)"
|
:src="resolveGeneralIconUrl(general)"
|
||||||
alt=""
|
alt=""
|
||||||
@error="useDefaultGeneralIcon"
|
@error="useDefaultGeneralIcon"
|
||||||
|
|||||||
Reference in New Issue
Block a user