From 221fef57f716bd62ee8a98653653da260f9718c5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 02:33:17 +0000 Subject: [PATCH 1/6] Create draft PR for #714 From bcee9929ed256078c763ab5040faaf72071452ae Mon Sep 17 00:00:00 2001 From: Kim Da Eun Date: Wed, 25 Sep 2024 17:53:51 +0900 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20playwright=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EB=B0=8F=20custom=20reporter=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/.gitignore | 4 + frontend/e2e/example.spec.ts | 18 ++ frontend/e2e/slack-reporter.ts | 319 +++++++++++++++++++++++++++++++++ frontend/package-lock.json | 60 +++++++ frontend/package.json | 4 +- frontend/playwright.config.ts | 70 ++++++++ frontend/src/env.d.ts | 1 + 7 files changed, 475 insertions(+), 1 deletion(-) create mode 100644 frontend/e2e/example.spec.ts create mode 100644 frontend/e2e/slack-reporter.ts create mode 100644 frontend/playwright.config.ts diff --git a/frontend/.gitignore b/frontend/.gitignore index fba10303e..9c9e79733 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -8,3 +8,7 @@ storybook-static # Sentry Config File .env.sentry-build-plugin +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/frontend/e2e/example.spec.ts b/frontend/e2e/example.spec.ts new file mode 100644 index 000000000..54a906a4e --- /dev/null +++ b/frontend/e2e/example.spec.ts @@ -0,0 +1,18 @@ +import { test, expect } from '@playwright/test'; + +test('has title', async ({ page }) => { + await page.goto('https://playwright.dev/'); + + // Expect a title "to contain" a substring. + await expect(page).toHaveTitle(/Playwright/); +}); + +test('get started link', async ({ page }) => { + await page.goto('https://playwright.dev/'); + + // Click the get started link. + await page.getByRole('link', { name: 'Get started' }).click(); + + // Expects page to have a heading with the name of Installation. + await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible(); +}); diff --git a/frontend/e2e/slack-reporter.ts b/frontend/e2e/slack-reporter.ts new file mode 100644 index 000000000..3c791b10c --- /dev/null +++ b/frontend/e2e/slack-reporter.ts @@ -0,0 +1,319 @@ +/* eslint-disable class-methods-use-this */ +import type { Reporter, FullConfig, Suite, TestCase, TestResult, FullResult } from '@playwright/test/reporter'; + +const getSlackMessage = ({ + all, + passed, + failed, + skipped, + duration, + result, +}: { + all: string; + passed: string; + failed: string; + skipped: string; + duration: string; + result: string; +}) => ({ + blocks: [ + { + type: 'header', + text: { + type: 'plain_text', + text: 'πŸƒ ν…ŒμŠ€νŠΈ 싀행이 μ‹œμž‘λ˜μ—ˆμŠ΅λ‹ˆλ‹€: ', + emoji: true, + }, + }, + { + type: 'rich_text', + elements: [ + { + type: 'rich_text_section', + elements: [], + }, + { + type: 'rich_text_list', + style: 'bullet', + elements: [ + { + type: 'rich_text_section', + elements: [ + { + type: 'text', + text: 'μ‹€ν–‰ μ‹œκ°: ', + }, + { + type: 'text', + text: `${new Date().toLocaleDateString('ko-KR', { + year: 'numeric', + month: 'long', + day: 'numeric', + hour: 'numeric', + minute: 'numeric', + second: 'numeric', + hour12: true, + })}`, + }, + ], + }, + { + type: 'rich_text_section', + elements: [ + { + type: 'text', + text: 'ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€ 수: ', + }, + { + type: 'text', + text: all, + }, + ], + }, + ], + }, + ], + }, + { + type: 'divider', + }, + { + type: 'rich_text', + elements: [ + { + type: 'rich_text_section', + elements: [ + { + type: 'text', + text: 'SUMMARY', + style: { + bold: true, + }, + }, + ], + }, + ], + }, + { + type: 'rich_text', + elements: [ + { + type: 'rich_text_list', + style: 'bullet', + indent: 0, + border: 0, + elements: [ + { + type: 'rich_text_section', + elements: [ + { + type: 'emoji', + name: 'hourglass', + unicode: '231b', + style: { + bold: true, + }, + }, + { + type: 'text', + text: ' ν…ŒμŠ€νŠΈ μ‹€ν–‰ μ‹œκ°„: ', + style: { + bold: true, + }, + }, + { + type: 'text', + text: duration, + }, + ], + }, + { + type: 'rich_text_section', + elements: [ + { + type: 'emoji', + name: 'package', + unicode: '1f4e6', + style: { + bold: true, + }, + }, + { + type: 'text', + text: ' ν…ŒμŠ€νŠΈ κ²°κ³Ό: ', + style: { + bold: true, + }, + }, + ], + }, + ], + }, + { + type: 'rich_text_list', + style: 'bullet', + indent: 1, + border: 0, + elements: [ + { + type: 'rich_text_section', + elements: [ + { + type: 'emoji', + name: 'white_check_mark', + unicode: '2705', + }, + { + type: 'text', + text: ' 성곡: ', + }, + { + type: 'text', + text: passed, + }, + ], + }, + { + type: 'rich_text_section', + elements: [ + { + type: 'emoji', + name: 'x', + unicode: '274c', + }, + { + type: 'text', + text: ' μ‹€νŒ¨: ', + }, + { + type: 'text', + text: failed, + }, + ], + }, + { + type: 'rich_text_section', + elements: [ + { + type: 'emoji', + name: 'fast_forward', + unicode: '23e9', + }, + { + type: 'text', + text: ' κ±΄λ„ˆλœ€: ', + }, + { + type: 'text', + text: skipped, + }, + ], + }, + ], + }, + ], + }, + { + type: 'divider', + }, + { + type: 'rich_text', + elements: [ + { + type: 'rich_text_section', + elements: [ + { + type: 'text', + text: result, + }, + ], + }, + ], + }, + ], +}); + +class MyReporter implements Reporter { + all = 0; + + passed = 0; + + failed = 0; + + skipped = 0; + + failsMessage = ''; + + onBegin(_: FullConfig, suite: Suite) { + this.all = suite.allTests().length; + } + + onTestEnd(test: TestCase, result: TestResult) { + switch (result.status) { + case 'failed': + case 'timedOut': + this.addFailMessage(`❌ ν…ŒμŠ€νŠΈ μ‹€νŒ¨: ${test.title}\n>${result.error?.message}`); + this.failed += 1; + break; + case 'skipped': + this.addFailMessage(`⚠️ ν…ŒμŠ€νŠΈ κ±΄λ„ˆλœ€: ${test.title}`); + this.skipped += 1; + break; + case 'passed': + this.passed += 1; + break; + default: + break; + } + } + + async onEnd(result: FullResult) { + const blockKit = await this.getBlockKit(result); + const webhookUrl = await process.env.SLACK_WEBHOOK_URL; + + if (!webhookUrl) { + console.error('SLACK_WEBHOOK_URL ν™˜κ²½ λ³€μˆ˜κ°€ μ„€μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.'); + return; + } + + try { + const response = await fetch(webhookUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(blockKit), + }); + + if (!response.ok) { + console.error('Slack λ©”μ‹œμ§€ 전솑 μ‹€νŒ¨:', response.statusText); + } else { + console.log('Slack λ©”μ‹œμ§€ 전솑 성곡'); + } + } catch (error) { + console.error('Slack λ©”μ‹œμ§€ 전솑 쀑 μ—λŸ¬ λ°œμƒ:', error); + } + } + + private addFailMessage(message: string) { + this.failsMessage += `\n${message}`; + } + + private async getBlockKit(result: FullResult) { + const { duration } = result; + const minutes = Math.floor(duration / 6000); + const seconds = ((duration % 60000) / 1000).toFixed(0); + + const resultBlockKit = getSlackMessage({ + all: `${this.all}`, + passed: `${this.passed}개`, + failed: `${this.failed}개`, + skipped: `${this.skipped}개`, + duration: `${minutes}λΆ„ ${seconds}초`, + result: `${this.failsMessage ? `ν…ŒμŠ€νŠΈ μ‹€νŒ¨ ❌\n${this.failsMessage}` : 'πŸ‘ λͺ¨λ“  ν…ŒμŠ€νŠΈκ°€ μ„±κ³΅μ μœΌλ‘œ ν†΅κ³Όν–ˆμŠ΅λ‹ˆλ‹€!'}`, + }); + + return resultBlockKit; + } +} +export default MyReporter; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1ddbc85b8..df1b7c7b6 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -24,6 +24,7 @@ "@chromatic-com/storybook": "^1.6.1", "@eslint/eslintrc": "^3.1.0", "@eslint/js": "^9.6.0", + "@playwright/test": "^1.47.2", "@storybook/addon-essentials": "^8.2.1", "@storybook/addon-interactions": "^8.2.1", "@storybook/addon-links": "^8.2.1", @@ -3801,6 +3802,21 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@playwright/test": { + "version": "1.47.2", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.47.2.tgz", + "integrity": "sha512-jTXRsoSPONAs8Za9QEQdyjFn+0ZQFjCiIztAIF6bi1HqhBzG9Ma7g1WotyiGqFSBRZjIEqMdT8RUlbk1QVhzCQ==", + "dev": true, + "dependencies": { + "playwright": "1.47.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@remix-run/router": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.18.0.tgz", @@ -18996,6 +19012,50 @@ "node": ">=8" } }, + "node_modules/playwright": { + "version": "1.47.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.47.2.tgz", + "integrity": "sha512-nx1cLMmQWqmA3UsnjaaokyoUpdVaaDhJhMoxX2qj3McpjnsqFHs516QAKYhqHAgOP+oCFTEOCOAaD1RgD/RQfA==", + "dev": true, + "dependencies": { + "playwright-core": "1.47.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.47.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.47.2.tgz", + "integrity": "sha512-3JvMfF+9LJfe16l7AbSmU555PaTl2tPyQsVInqm3id16pdDfvZ8TTZ/pyzmkbDrZTQefyzU7AIHlZqQnxpqHVQ==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/polished": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index f4e150650..5818ff86d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -5,7 +5,8 @@ "test": "jest", "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'", "storybook": "storybook dev -p 6006", - "build-storybook": "storybook build" + "build-storybook": "storybook build", + "e2e": "npx playwright test" }, "dependencies": { "@emotion/react": "^11.11.4", @@ -27,6 +28,7 @@ "@chromatic-com/storybook": "^1.6.1", "@eslint/eslintrc": "^3.1.0", "@eslint/js": "^9.6.0", + "@playwright/test": "^1.47.2", "@storybook/addon-essentials": "^8.2.1", "@storybook/addon-interactions": "^8.2.1", "@storybook/addon-links": "^8.2.1", diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts new file mode 100644 index 000000000..c5b61df34 --- /dev/null +++ b/frontend/playwright.config.ts @@ -0,0 +1,70 @@ +import { defineConfig, devices } from '@playwright/test'; + +import dotenv from 'dotenv'; +import path from 'path'; + +dotenv.config({ path: path.resolve(__dirname, '.env.local') }); + +export default defineConfig({ + testDir: './e2e', + fullyParallel: true, + // reporter: [['./e2e/slack-reporter.ts'], ['html'], ['list']], + reporter: [['html'], ['list']], + + use: { + /* `await page.goto('/')`와 같은 μ•‘μ…˜μ—μ„œ μ‚¬μš©ν•  κΈ°λ³Έ URL μ„€μ • */ + baseURL: process.env.DOMAIN_URL, + trace: 'on-first-retry', + }, + + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] }, + }, + + /* μ†ŒμŠ€ μ½”λ“œμ— test.onlyλ₯Ό 남겨둔 경우, CIμ—μ„œ λΉŒλ“œλ₯Ό μ‹€νŒ¨ μ²˜λ¦¬ν•©λ‹ˆλ‹€. */ + // forbidOnly: !!process.env.CI, + /* CI ν™˜κ²½μ—μ„œλ§Œ μž¬μ‹œλ„ μ„€μ • */ + // retries: process.env.CI ? 2 : 0, + /* CI ν™˜κ²½μ—μ„œ 병렬 ν…ŒμŠ€νŠΈ μ‹€ν–‰ λΉ„ν™œμ„±ν™” */ + // workers: process.env.CI ? 1 : undefined, + + /* λͺ¨λ°”일 λ·°ν¬νŠΈμ— λŒ€ν•œ ν…ŒμŠ€νŠΈ */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* λΈŒλžœλ””λ“œ λΈŒλΌμš°μ €μ— λŒ€ν•œ ν…ŒμŠ€νŠΈ */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* ν…ŒμŠ€νŠΈλ₯Ό μ‹œμž‘ν•˜κΈ° 전에 둜컬 개발 μ„œλ²„ μ‹€ν–‰ */ + // webServer: { + // command: 'npm run start', + // url: 'http://127.0.0.1:3000', + // reuseExistingServer: !process.env.CI, + // }, +}); diff --git a/frontend/src/env.d.ts b/frontend/src/env.d.ts index 3818afe95..0529e78de 100644 --- a/frontend/src/env.d.ts +++ b/frontend/src/env.d.ts @@ -8,5 +8,6 @@ declare namespace NodeJS { PROD_URL: string; DEV_URL: string; DOMAIN_URL: string; + SLACK_WEBHOOK_URL: string; } } From 3e60e858285f73f697d4bd564c18e85d850b79d2 Mon Sep 17 00:00:00 2001 From: Kim Da Eun Date: Wed, 25 Sep 2024 18:27:58 +0900 Subject: [PATCH 3/6] =?UTF-8?q?chore:=20jest=EA=B0=80=20playwright=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=AC=B4=EC=8B=9C=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/jest.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/jest.config.js b/frontend/jest.config.js index 67c692f16..b415373b0 100644 --- a/frontend/jest.config.js +++ b/frontend/jest.config.js @@ -22,6 +22,7 @@ module.exports = { testEnvironmentOptions: { customExportConditions: [''], }, + testPathIgnorePatterns: ['/e2e/'], setupFilesAfterEnv: ['/setupTests.ts'], testMatch: ['**/__tests__/**/*.+(ts|tsx|js)', '**/?(*.)+(spec|test).+(ts|tsx|js)'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], From e100bdd63e7cce5d56eb6750db07411a99ebef78 Mon Sep 17 00:00:00 2001 From: Kim Da Eun Date: Wed, 25 Sep 2024 19:01:15 +0900 Subject: [PATCH 4/6] =?UTF-8?q?chore:=20slack=20=EB=A9=94=EC=84=B8?= =?UTF-8?q?=EC=A7=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/e2e/slack-reporter.ts | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/frontend/e2e/slack-reporter.ts b/frontend/e2e/slack-reporter.ts index 3c791b10c..8c7ce0ac3 100644 --- a/frontend/e2e/slack-reporter.ts +++ b/frontend/e2e/slack-reporter.ts @@ -1,5 +1,6 @@ /* eslint-disable class-methods-use-this */ import type { Reporter, FullConfig, Suite, TestCase, TestResult, FullResult } from '@playwright/test/reporter'; +import path from 'path'; const getSlackMessage = ({ all, @@ -21,7 +22,7 @@ const getSlackMessage = ({ type: 'header', text: { type: 'plain_text', - text: 'πŸƒ ν…ŒμŠ€νŠΈ 싀행이 μ‹œμž‘λ˜μ—ˆμŠ΅λ‹ˆλ‹€: ', + text: 'πŸƒ E2E ν…ŒμŠ€νŠΈκ°€ μ‹€ν–‰λ˜μ—ˆμŠ΅λ‹ˆλ‹€: ', emoji: true, }, }, @@ -249,14 +250,22 @@ class MyReporter implements Reporter { } onTestEnd(test: TestCase, result: TestResult) { + const testDuration = `${(result.duration / 1000).toFixed(1)}s`; + const fileName = path.basename(test.location.file); + const testTitle = test.title; + switch (result.status) { case 'failed': case 'timedOut': - this.addFailMessage(`❌ ν…ŒμŠ€νŠΈ μ‹€νŒ¨: ${test.title}\n>${result.error?.message}`); + this.addFailMessage( + `✘ ${fileName}:${test.location.line}:${test.location.column} β€Ί ${testTitle}(${testDuration})`, + ); this.failed += 1; break; case 'skipped': - this.addFailMessage(`⚠️ ν…ŒμŠ€νŠΈ κ±΄λ„ˆλœ€: ${test.title}`); + this.addFailMessage( + `⚠️ ${fileName}:${test.location.line}:${test.location.column} β€Ί ${testTitle}(${testDuration})`, + ); this.skipped += 1; break; case 'passed': @@ -301,16 +310,14 @@ class MyReporter implements Reporter { private async getBlockKit(result: FullResult) { const { duration } = result; - const minutes = Math.floor(duration / 6000); - const seconds = ((duration % 60000) / 1000).toFixed(0); const resultBlockKit = getSlackMessage({ all: `${this.all}`, passed: `${this.passed}개`, failed: `${this.failed}개`, skipped: `${this.skipped}개`, - duration: `${minutes}λΆ„ ${seconds}초`, - result: `${this.failsMessage ? `ν…ŒμŠ€νŠΈ μ‹€νŒ¨ ❌\n${this.failsMessage}` : 'πŸ‘ λͺ¨λ“  ν…ŒμŠ€νŠΈκ°€ μ„±κ³΅μ μœΌλ‘œ ν†΅κ³Όν–ˆμŠ΅λ‹ˆλ‹€!'}`, + duration: `${(duration / 1000).toFixed(1)}s`, + result: `${this.failsMessage ? `ν†΅κ³Όν•˜μ§€ λͺ»ν•œ ν…ŒμŠ€νŠΈ\n${this.failsMessage}` : 'πŸ‘ λͺ¨λ“  ν…ŒμŠ€νŠΈκ°€ μ„±κ³΅μ μœΌλ‘œ ν†΅κ³Όν–ˆμŠ΅λ‹ˆλ‹€!'}`, }); return resultBlockKit; From 6ba45d3a099548e6ca22ee93a054ab0af7700deb Mon Sep 17 00:00:00 2001 From: Kim Da Eun Date: Wed, 25 Sep 2024 19:02:56 +0900 Subject: [PATCH 5/6] =?UTF-8?q?chore:=20=EB=9D=84=EC=96=B4=EC=93=B0?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/e2e/slack-reporter.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/e2e/slack-reporter.ts b/frontend/e2e/slack-reporter.ts index 8c7ce0ac3..444602723 100644 --- a/frontend/e2e/slack-reporter.ts +++ b/frontend/e2e/slack-reporter.ts @@ -258,13 +258,13 @@ class MyReporter implements Reporter { case 'failed': case 'timedOut': this.addFailMessage( - `✘ ${fileName}:${test.location.line}:${test.location.column} β€Ί ${testTitle}(${testDuration})`, + `✘ ${fileName}:${test.location.line}:${test.location.column} β€Ί ${testTitle} (${testDuration})`, ); this.failed += 1; break; case 'skipped': this.addFailMessage( - `⚠️ ${fileName}:${test.location.line}:${test.location.column} β€Ί ${testTitle}(${testDuration})`, + `⚠️ ${fileName}:${test.location.line}:${test.location.column} β€Ί ${testTitle} (${testDuration})`, ); this.skipped += 1; break; From a9948801d3e3a08258506dd688923075ed513210 Mon Sep 17 00:00:00 2001 From: Kim Da Eun Date: Thu, 26 Sep 2024 11:03:27 +0900 Subject: [PATCH 6/6] =?UTF-8?q?chore:=20package-lock.json=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/package-lock.json | 143 +++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index df1b7c7b6..5d675a671 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -79,6 +79,7 @@ "storybook": "^8.2.1", "storybook-addon-remix-react-router": "^3.0.0", "typescript-eslint": "^7.16.0", + "webpack-bundle-analyzer": "^4.10.2", "webpack-cli": "^5.1.4", "webpack-dev-server": "^5.0.4" } @@ -3817,6 +3818,12 @@ "node": ">=18" } }, + "node_modules/@polka/url": { + "version": "1.0.0-next.28", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", + "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", + "dev": true + }, "node_modules/@remix-run/router": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.18.0.tgz", @@ -9291,6 +9298,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "dev": true + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -9739,6 +9752,12 @@ "webpack": "^4 || ^5" } }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -12568,6 +12587,21 @@ "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dev": true, + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", @@ -15428,6 +15462,15 @@ "pathe": "^1.1.2" } }, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -18690,6 +18733,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "bin": { + "opener": "bin/opener-bin.js" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -20448,6 +20500,20 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "dev": true, + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -21434,6 +21500,15 @@ "node": ">=0.6" } }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/tough-cookie": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", @@ -22168,6 +22243,74 @@ } } }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", + "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/webpack-cli": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz",