From bdf1547a42360830c833bfadef3937de3897c1ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Sat, 18 Jul 2026 23:04:21 +0900 Subject: [PATCH 01/23] =?UTF-8?q?refactor(frontend):=20=E3=83=A1=E3=83=87?= =?UTF-8?q?=E3=82=A3=E3=82=A2=E3=83=A1=E3=83=8B=E3=83=A5=E3=83=BC=E3=81=AE?= =?UTF-8?q?=E3=83=A1=E3=83=8B=E3=83=A5=E3=83=BC=E3=83=9C=E3=82=BF=E3=83=B3?= =?UTF-8?q?=E3=81=AE=E3=82=B9=E3=82=BF=E3=82=A4=E3=83=AB=E3=82=92=E7=B5=B1?= =?UTF-8?q?=E4=B8=80=20(#17742)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix * fix * refactor --- .../frontend/src/components/MkMediaImage.vue | 32 +++++++------------ .../frontend/src/components/MkMediaVideo.vue | 24 +++++--------- 2 files changed, 20 insertions(+), 36 deletions(-) diff --git a/packages/frontend/src/components/MkMediaImage.vue b/packages/frontend/src/components/MkMediaImage.vue index 01f449753b..dee6db5e26 100644 --- a/packages/frontend/src/components/MkMediaImage.vue +++ b/packages/frontend/src/components/MkMediaImage.vue @@ -61,8 +61,8 @@ SPDX-License-Identifier: AGPL-3.0-only
| ', + ' | Bundles | ', + 'Modules | ', + 'Entries | ', + 'Imports | ', + 'Size | ', + '|||
|---|---|---|---|---|---|---|---|---|
| Static | ', + 'Dynamic | ', + 'Rendered | ', + 'Gzip | ', + 'Brotli | ', + '||||
| Before | ', + ...summary.map((key) => `${formatNumber(before.summary[key])} | `), + ...metrics.map((key) => `${formatBytes(before.metrics[key])} | `), + '||||||
| After | ', + ...summary.map((key) => `${formatNumber(after.summary[key])} | `), + ...metrics.map((key) => `${formatBytes(after.metrics[key])} | `), + '||||||
| Δ | ', + ...summary.map((key) => `${calcAndFormatDeltaNumber(before.summary[key], after.summary[key], 0)} | `), + ...metrics.map((key) => `${calcAndFormatDeltaBytes(before.metrics[key], after.metrics[key], 1000)} | `), + '||||||
| Δ (%) | ', + ...summary.map((key) => `${calcAndFormatDeltaPercent(before.summary[key], after.summary[key], 0.1)} | `), + ...metrics.map((key) => `${calcAndFormatDeltaPercent(before.metrics[key], after.metrics[key], 0.1)} | `), + '||||||
| + | Bundles | +Modules | +Entries | +Imports | +Size | +|||
|---|---|---|---|---|---|---|---|---|
| Static | +Dynamic | +Rendered | +Gzip | +Brotli | +||||
| Before | +2 | +6 | +1 | +2 | +3 | +21 KB | +6.3 KB | +5.3 KB | +
| After | +2 | +7 | +1 | +3 | +3 | +31 KB | +8.4 KB | +7 KB | +
| Δ | +0 | +$\color{orange}{\text{+1}}$ | +0 | +$\color{orange}{\text{+1}}$ | +0 | +$\color{orange}{\text{+9.8 KB}}$ | +$\color{orange}{\text{+2.1 KB}}$ | +$\color{orange}{\text{+1.8 KB}}$ | +
| Δ (%) | +0% | +$\color{orange}{\text{+16.7\%}}$ | +0% | +$\color{orange}{\text{+50\%}}$ | +0% | +$\color{orange}{\text{+46.7\%}}$ | +$\color{orange}{\text{+33.3\%}}$ | +$\color{orange}{\text{+33.3\%}}$ | +
${value}
`)).toBe('<script>alert(1)</script>
'); + }); + + test('escapes values used in attribute position', () => { + const url = 'x">'; + expect(String(html``)).toBe(''); + }); + + test('leaves the static parts of the template untouched', () => { + expect(String(html`x
`)).toBe('x
'); + }); + + test('renders nullish values as an empty string', () => { + expect(String(html`${null}${undefined}
`)).toBe(''); + }); + + test('does not double-escape nested fragments', () => { + const inner = html`${'a&b'}`; + expect(String(html`${inner}
`)).toBe('a&b
'); + }); + + // 配列をそのまま文字列化するとカンマ区切りで潰れる。実際に過去これで表が壊れた + test('joins arrays without separators instead of stringifying them', () => { + const items = [html`${['', '']}
`)).toBe('<a><b>
'); + }); +}); + +describe('raw', () => { + test('embeds trusted markup without escaping', () => { + expect(String(html``)).toBe(''); + }); + + test('produces a Raw fragment', () => { + expect(raw('x')).toBeInstanceOf(Raw); + expect(html`x`).toBeInstanceOf(Raw); + }); +}); + +describe('joinHtml', () => { + test('joins fragments with the given separator', () => { + expect(String(joinHtml([html`| - | Bundles | -Modules | -Entries | -Imports | -Size | -|||
|---|---|---|---|---|---|---|---|---|
| Static | -Dynamic | -Rendered | -Gzip | -Brotli | -||||
| Before | -2 | -6 | -1 | -2 | -3 | -21 KB | -6.3 KB | -5.3 KB | -
| After | -2 | -7 | -1 | -3 | -3 | -31 KB | -8.4 KB | -7 KB | -
| Δ | -0 | -$\color{orange}{\text{+1}}$ | -0 | -$\color{orange}{\text{+1}}$ | -0 | -$\color{orange}{\text{+9.8 KB}}$ | -$\color{orange}{\text{+2.1 KB}}$ | -$\color{orange}{\text{+1.8 KB}}$ | -
| Δ (%) | -0% | -$\color{orange}{\text{+16.7\%}}$ | -0% | -$\color{orange}{\text{+50\%}}$ | -0% | -$\color{orange}{\text{+46.7\%}}$ | -$\color{orange}{\text{+33.3\%}}$ | -$\color{orange}{\text{+33.3\%}}$ | -
| + | Bundles | +Modules | +Entries | +Imports | +Size | +|||
|---|---|---|---|---|---|---|---|---|
| Static | +Dynamic | +Rendered | +Gzip | +Brotli | +||||
| Base | +2 | +6 | +1 | +2 | +3 | +21 KB | +6.3 KB | +5.3 KB | +
| Head | +2 | +7 | +1 | +3 | +3 | +31 KB | +8.4 KB | +7 KB | +
| Δ | +0 | +$\color{orange}{\text{+1}}$ | +0 | +$\color{orange}{\text{+1}}$ | +0 | +$\color{orange}{\text{+9.8 KB}}$ | +$\color{orange}{\text{+2.1 KB}}$ | +$\color{orange}{\text{+1.8 KB}}$ | +
| Δ (%) | +0% | +$\color{orange}{\text{+16.7\%}}$ | +0% | +$\color{orange}{\text{+50\%}}$ | +0% | +$\color{orange}{\text{+46.7\%}}$ | +$\color{orange}{\text{+33.3\%}}$ | +$\color{orange}{\text{+33.3\%}}$ | +