diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index d42848b2f..2501089b1 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -45,6 +45,7 @@
"@typescript-eslint/eslint-plugin": "^6.2.0",
"@typescript-eslint/parser": "^6.2.0",
"babel-plugin-react-require": "^4.0.0",
+ "compression-webpack-plugin": "^10.0.0",
"copy-webpack-plugin": "^11.0.0",
"cross-env": "^7.0.3",
"cypress": "^12.17.3",
@@ -67,6 +68,7 @@
"typescript": "^5.1.6",
"url-loader": "^4.1.1",
"webpack": "^5.88.1",
+ "webpack-bundle-analyzer": "^4.9.1",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1"
}
@@ -3528,6 +3530,12 @@
"node": ">= 8"
}
},
+ "node_modules/@polka/url": {
+ "version": "1.0.0-next.21",
+ "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz",
+ "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==",
+ "dev": true
+ },
"node_modules/@radix-ui/number": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz",
@@ -9425,6 +9433,79 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/compression-webpack-plugin": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/compression-webpack-plugin/-/compression-webpack-plugin-10.0.0.tgz",
+ "integrity": "sha512-wLXLIBwpul/ALcm7Aj+69X0pYT3BYt6DdPn3qrgBIh9YejV9Bju9ShhlAsjujLyWMo6SAweFIWaUoFmXZNuNrg==",
+ "dev": true,
+ "dependencies": {
+ "schema-utils": "^4.0.0",
+ "serialize-javascript": "^6.0.0"
+ },
+ "engines": {
+ "node": ">= 14.15.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ },
+ "peerDependencies": {
+ "webpack": "^5.1.0"
+ }
+ },
+ "node_modules/compression-webpack-plugin/node_modules/ajv": {
+ "version": "8.12.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+ "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/compression-webpack-plugin/node_modules/ajv-keywords": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+ "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3"
+ },
+ "peerDependencies": {
+ "ajv": "^8.8.2"
+ }
+ },
+ "node_modules/compression-webpack-plugin/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true
+ },
+ "node_modules/compression-webpack-plugin/node_modules/schema-utils": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz",
+ "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==",
+ "dev": true,
+ "dependencies": {
+ "@types/json-schema": "^7.0.9",
+ "ajv": "^8.9.0",
+ "ajv-formats": "^2.1.1",
+ "ajv-keywords": "^5.1.0"
+ },
+ "engines": {
+ "node": ">= 12.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
"node_modules/compression/node_modules/bytes": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
@@ -10677,6 +10758,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/duplexify": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
@@ -13073,6 +13160,21 @@
"gunzip-maybe": "bin.js"
}
},
+ "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/hamt_plus": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/hamt_plus/-/hamt_plus-1.0.2.tgz",
@@ -15285,6 +15387,24 @@
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
"dev": true
},
+ "node_modules/lodash.escape": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz",
+ "integrity": "sha512-nXEOnb/jK9g0DYMr1/Xvq6l5xMD7GDG55+GSYIYmS0G4tBk/hURD4JR9WCavs04t33WmJx9kCyp9vJ+mr4BOUw==",
+ "dev": true
+ },
+ "node_modules/lodash.flatten": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
+ "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==",
+ "dev": true
+ },
+ "node_modules/lodash.invokemap": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.invokemap/-/lodash.invokemap-4.6.0.tgz",
+ "integrity": "sha512-CfkycNtMqgUlfjfdh2BhKO/ZXrP8ePOX5lEU/g0R3ItJcnuxWDwokMGKx1hWcfOikmyOVx6X9IwWnDGlgKl61w==",
+ "dev": true
+ },
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -15297,6 +15417,18 @@
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
"dev": true
},
+ "node_modules/lodash.pullall": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.pullall/-/lodash.pullall-4.2.0.tgz",
+ "integrity": "sha512-VhqxBKH0ZxPpLhiu68YD1KnHmbhQJQctcipvmFnqIBDYzcIHzf3Zpu0tpeOKtR4x76p9yohc506eGdOjTmyIBg==",
+ "dev": true
+ },
+ "node_modules/lodash.uniqby": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz",
+ "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==",
+ "dev": true
+ },
"node_modules/log-symbols": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
@@ -15754,6 +15886,15 @@
"node": ">=4"
}
},
+ "node_modules/mrmime": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz",
+ "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -16286,6 +16427,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.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
@@ -18404,6 +18554,20 @@
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
},
+ "node_modules/sirv": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz",
+ "integrity": "sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==",
+ "dev": true,
+ "dependencies": {
+ "@polka/url": "^1.0.0-next.20",
+ "mrmime": "^1.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",
@@ -19468,6 +19632,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.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
@@ -20340,6 +20513,88 @@
}
}
},
+ "node_modules/webpack-bundle-analyzer": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.9.1.tgz",
+ "integrity": "sha512-jnd6EoYrf9yMxCyYDPj8eutJvtjQNp8PHmni/e/ulydHBWhT5J3menXt3HEkScsu9YqMAcG4CfFjs3rj5pVU1w==",
+ "dev": true,
+ "dependencies": {
+ "@discoveryjs/json-ext": "0.5.7",
+ "acorn": "^8.0.4",
+ "acorn-walk": "^8.0.0",
+ "commander": "^7.2.0",
+ "escape-string-regexp": "^4.0.0",
+ "gzip-size": "^6.0.0",
+ "is-plain-object": "^5.0.0",
+ "lodash.debounce": "^4.0.8",
+ "lodash.escape": "^4.0.1",
+ "lodash.flatten": "^4.4.0",
+ "lodash.invokemap": "^4.6.0",
+ "lodash.pullall": "^4.2.0",
+ "lodash.uniqby": "^4.7.0",
+ "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/acorn": {
+ "version": "8.10.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
+ "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/webpack-bundle-analyzer/node_modules/acorn-walk": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+ "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.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/ws": {
+ "version": "7.5.9",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
+ "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
+ "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",
@@ -23421,6 +23676,12 @@
}
}
},
+ "@polka/url": {
+ "version": "1.0.0-next.21",
+ "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz",
+ "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==",
+ "dev": true
+ },
"@radix-ui/number": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz",
@@ -27645,6 +27906,57 @@
}
}
},
+ "compression-webpack-plugin": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/compression-webpack-plugin/-/compression-webpack-plugin-10.0.0.tgz",
+ "integrity": "sha512-wLXLIBwpul/ALcm7Aj+69X0pYT3BYt6DdPn3qrgBIh9YejV9Bju9ShhlAsjujLyWMo6SAweFIWaUoFmXZNuNrg==",
+ "dev": true,
+ "requires": {
+ "schema-utils": "^4.0.0",
+ "serialize-javascript": "^6.0.0"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "8.12.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+ "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "ajv-keywords": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+ "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.3"
+ }
+ },
+ "json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true
+ },
+ "schema-utils": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz",
+ "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==",
+ "dev": true,
+ "requires": {
+ "@types/json-schema": "^7.0.9",
+ "ajv": "^8.9.0",
+ "ajv-formats": "^2.1.1",
+ "ajv-keywords": "^5.1.0"
+ }
+ }
+ }
+ },
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -28566,6 +28878,12 @@
"dotenv-defaults": "^2.0.2"
}
},
+ "duplexer": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
+ "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
+ "dev": true
+ },
"duplexify": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
@@ -30393,6 +30711,15 @@
"through2": "^2.0.3"
}
},
+ "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,
+ "requires": {
+ "duplexer": "^0.1.2"
+ }
+ },
"hamt_plus": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/hamt_plus/-/hamt_plus-1.0.2.tgz",
@@ -31993,6 +32320,24 @@
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
"dev": true
},
+ "lodash.escape": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz",
+ "integrity": "sha512-nXEOnb/jK9g0DYMr1/Xvq6l5xMD7GDG55+GSYIYmS0G4tBk/hURD4JR9WCavs04t33WmJx9kCyp9vJ+mr4BOUw==",
+ "dev": true
+ },
+ "lodash.flatten": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
+ "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==",
+ "dev": true
+ },
+ "lodash.invokemap": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.invokemap/-/lodash.invokemap-4.6.0.tgz",
+ "integrity": "sha512-CfkycNtMqgUlfjfdh2BhKO/ZXrP8ePOX5lEU/g0R3ItJcnuxWDwokMGKx1hWcfOikmyOVx6X9IwWnDGlgKl61w==",
+ "dev": true
+ },
"lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -32005,6 +32350,18 @@
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
"dev": true
},
+ "lodash.pullall": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.pullall/-/lodash.pullall-4.2.0.tgz",
+ "integrity": "sha512-VhqxBKH0ZxPpLhiu68YD1KnHmbhQJQctcipvmFnqIBDYzcIHzf3Zpu0tpeOKtR4x76p9yohc506eGdOjTmyIBg==",
+ "dev": true
+ },
+ "lodash.uniqby": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz",
+ "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==",
+ "dev": true
+ },
"log-symbols": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
@@ -32341,6 +32698,12 @@
"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
"dev": true
},
+ "mrmime": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz",
+ "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==",
+ "dev": true
+ },
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -32730,6 +33093,12 @@
"is-wsl": "^2.2.0"
}
},
+ "opener": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
+ "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
+ "dev": true
+ },
"optionator": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
@@ -34317,6 +34686,17 @@
}
}
},
+ "sirv": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz",
+ "integrity": "sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==",
+ "dev": true,
+ "requires": {
+ "@polka/url": "^1.0.0-next.20",
+ "mrmime": "^1.0.0",
+ "totalist": "^3.0.0"
+ }
+ },
"sisteransi": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
@@ -35155,6 +35535,12 @@
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
"dev": true
},
+ "totalist": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
+ "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
+ "dev": true
+ },
"tough-cookie": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
@@ -35827,6 +36213,58 @@
}
}
},
+ "webpack-bundle-analyzer": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.9.1.tgz",
+ "integrity": "sha512-jnd6EoYrf9yMxCyYDPj8eutJvtjQNp8PHmni/e/ulydHBWhT5J3menXt3HEkScsu9YqMAcG4CfFjs3rj5pVU1w==",
+ "dev": true,
+ "requires": {
+ "@discoveryjs/json-ext": "0.5.7",
+ "acorn": "^8.0.4",
+ "acorn-walk": "^8.0.0",
+ "commander": "^7.2.0",
+ "escape-string-regexp": "^4.0.0",
+ "gzip-size": "^6.0.0",
+ "is-plain-object": "^5.0.0",
+ "lodash.debounce": "^4.0.8",
+ "lodash.escape": "^4.0.1",
+ "lodash.flatten": "^4.4.0",
+ "lodash.invokemap": "^4.6.0",
+ "lodash.pullall": "^4.2.0",
+ "lodash.uniqby": "^4.7.0",
+ "opener": "^1.5.2",
+ "picocolors": "^1.0.0",
+ "sirv": "^2.0.3",
+ "ws": "^7.3.1"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "8.10.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
+ "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
+ "dev": true
+ },
+ "acorn-walk": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+ "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
+ "dev": true
+ },
+ "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
+ },
+ "ws": {
+ "version": "7.5.9",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
+ "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
+ "dev": true,
+ "requires": {}
+ }
+ }
+ },
"webpack-cli": {
"version": "5.1.4",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 179207559..60be48b5d 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -71,6 +71,7 @@
"@typescript-eslint/eslint-plugin": "^6.2.0",
"@typescript-eslint/parser": "^6.2.0",
"babel-plugin-react-require": "^4.0.0",
+ "compression-webpack-plugin": "^10.0.0",
"copy-webpack-plugin": "^11.0.0",
"cross-env": "^7.0.3",
"cypress": "^12.17.3",
@@ -93,10 +94,12 @@
"typescript": "^5.1.6",
"url-loader": "^4.1.1",
"webpack": "^5.88.1",
+ "webpack-bundle-analyzer": "^4.9.1",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1"
},
"msw": {
"workerDirectory": "public"
- }
+ },
+ "sideEffects": false
}
diff --git a/frontend/src/assets/index.d.ts b/frontend/src/assets/index.d.ts
index c096f73d8..f9a456f5c 100644
--- a/frontend/src/assets/index.d.ts
+++ b/frontend/src/assets/index.d.ts
@@ -6,3 +6,5 @@ declare module '*.svg' {
}
declare module '*.png';
+
+declare module '*.jpg';
diff --git a/frontend/src/assets/jpg/sample-trip-image.jpg b/frontend/src/assets/jpg/sample-trip-image.jpg
new file mode 100644
index 000000000..527e8da0e
Binary files /dev/null and b/frontend/src/assets/jpg/sample-trip-image.jpg differ
diff --git a/frontend/src/assets/jpg/sample-trip-image_mobile.jpg b/frontend/src/assets/jpg/sample-trip-image_mobile.jpg
new file mode 100644
index 000000000..9ec58426b
Binary files /dev/null and b/frontend/src/assets/jpg/sample-trip-image_mobile.jpg differ
diff --git a/frontend/src/assets/png/sample-trip-image.png b/frontend/src/assets/png/sample-trip-image.png
deleted file mode 100644
index a937bc6f2..000000000
Binary files a/frontend/src/assets/png/sample-trip-image.png and /dev/null differ
diff --git a/frontend/src/assets/png/sample-trip-image_mobile.png b/frontend/src/assets/png/sample-trip-image_mobile.png
deleted file mode 100644
index e80c70520..000000000
Binary files a/frontend/src/assets/png/sample-trip-image_mobile.png and /dev/null differ
diff --git a/frontend/src/components/myPage/EditUserProfileForm/EditUserProfileForm.style.ts b/frontend/src/components/myPage/EditUserProfileForm/EditUserProfileForm.style.ts
index 7f71eb80e..16c83f304 100644
--- a/frontend/src/components/myPage/EditUserProfileForm/EditUserProfileForm.style.ts
+++ b/frontend/src/components/myPage/EditUserProfileForm/EditUserProfileForm.style.ts
@@ -36,6 +36,10 @@ export const deleteButtonStyling = css({
color: Theme.color.gray700,
},
+
+ '&:focus': {
+ boxShadow: 'none',
+ },
});
export const modalContentStyling = css({
diff --git a/frontend/src/pages/IntroPage/IntroPage.tsx b/frontend/src/pages/IntroPage/IntroPage.tsx
index 5cbe9f5f6..34034b825 100644
--- a/frontend/src/pages/IntroPage/IntroPage.tsx
+++ b/frontend/src/pages/IntroPage/IntroPage.tsx
@@ -15,8 +15,8 @@ import { mediaQueryMobileState } from '@store/mediaQuery';
import { PATH } from '@constants/path';
-import SampleTripImage from '@assets/png/sample-trip-image.png';
-import SampleTripImageMobile from '@assets/png/sample-trip-image_mobile.png';
+import SampleTripImage from '@assets/jpg/sample-trip-image.jpg';
+import SampleTripImageMobile from '@assets/jpg/sample-trip-image_mobile.jpg';
const IntroPage = () => {
const navigate = useNavigate();
diff --git a/frontend/src/router/AppRouter.tsx b/frontend/src/router/AppRouter.tsx
index e0af1bc84..826dd5e55 100644
--- a/frontend/src/router/AppRouter.tsx
+++ b/frontend/src/router/AppRouter.tsx
@@ -5,23 +5,16 @@ import { RouterProvider, createBrowserRouter } from 'react-router-dom';
import { useRecoilValue } from 'recoil';
-import ExpensePage from '@pages/ExpensePage/ExpensePage';
import ExpensePageSkeleton from '@pages/ExpensePage/ExpensePageSkeleton';
-import IntroPage from '@pages/IntroPage/IntroPage';
-import LogInPage from '@pages/LogInPage/LogInPage';
-import MyPage from '@pages/MyPage/MyPage';
import NotFoundPage from '@pages/NotFoundPage/NotFoundPage';
import RedirectPage from '@pages/RedirectPage/RedirectPage';
-import SharedPage from '@pages/SharedPage/SharedPage';
-import TripCreatePage from '@pages/TripCreatePage/TripCreatePage';
-import TripEditPage from '@pages/TripEditPage/TripEditPage';
-import TripPage from '@pages/TripPage/TripPage';
import TripPageSkeleton from '@pages/TripPage/TripPageSkeleton';
-import TripsPage from '@pages/TripsPage/TripsPage';
import TripsPageSkeleton from '@pages/TripsPage/TripsPageSkeleton';
import { isLoggedInState } from '@store/auth';
+import * as Lazy from '@router/lazy';
+
import { PATH } from '@constants/path';
const AppRouter = () => {
@@ -37,17 +30,17 @@ const AppRouter = () => {
path: '',
element: isLoggedIn ? (
}>
-
+
) : (
-
+
),
},
{
path: PATH.TRIP(':tripId'),
element: (
}>
-
+
),
},
@@ -55,19 +48,23 @@ const AppRouter = () => {
path: PATH.EDIT_TRIP(':tripId'),
element: (
}>
-
+
),
},
{
path: PATH.CREATE_TRIP,
- element: ,
+ element: (
+
+
+
+ ),
},
{
path: PATH.EXPENSE(':tripId'),
element: (
}>
-
+
),
},
@@ -77,13 +74,17 @@ const AppRouter = () => {
},
{
path: PATH.LOGIN,
- element: ,
+ element: (
+
+
+
+ ),
},
{
path: PATH.MY_PAGE,
element: (
LOADING}>
-
+
),
},
@@ -91,7 +92,7 @@ const AppRouter = () => {
path: PATH.SHARE(':code'),
element: (
}>
-
+
),
},
diff --git a/frontend/src/router/lazy.ts b/frontend/src/router/lazy.ts
new file mode 100644
index 000000000..14f81ed95
--- /dev/null
+++ b/frontend/src/router/lazy.ts
@@ -0,0 +1,35 @@
+import { lazy } from 'react';
+
+export const ExpensePage = lazy(
+ () => import(/* webpackChunkName: "ExpensePage" */ '@pages/ExpensePage/ExpensePage')
+);
+
+export const IntroPage = lazy(
+ () => import(/* webpackChunkName: "IntroPage" */ '@pages/IntroPage/IntroPage')
+);
+
+export const LogInPage = lazy(
+ () => import(/* webpackChunkName: "LogInPage" */ '@pages/LogInPage/LogInPage')
+);
+
+export const MyPage = lazy(() => import(/* webpackChunkName: "MyPage" */ '@pages/MyPage/MyPage'));
+
+export const SharedPage = lazy(
+ () => import(/* webpackChunkName: "SharedPage" */ '@pages/SharedPage/SharedPage')
+);
+
+export const TripCreatePage = lazy(
+ () => import(/* webpackChunkName: "TripCreatePage" */ '@pages/TripCreatePage/TripCreatePage')
+);
+
+export const TripEditPage = lazy(
+ () => import(/* webpackChunkName: "TripEditPage" */ '@pages/TripEditPage/TripEditPage')
+);
+
+export const TripPage = lazy(
+ () => import(/* webpackChunkName: "TripPage" */ '@pages/TripPage/TripPage')
+);
+
+export const TripsPage = lazy(
+ () => import(/* webpackChunkName: "TripsPage" */ '@pages/TripsPage/TripsPage')
+);
diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json
index 034f18491..150747da7 100644
--- a/frontend/tsconfig.json
+++ b/frontend/tsconfig.json
@@ -3,7 +3,8 @@
"outDir": "./dist",
"target": "ES2015",
"skipLibCheck": true,
- "module": "commonjs",
+ "module": "esnext",
+ "moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js
index 72a8ab856..c04f79ad0 100644
--- a/frontend/webpack.config.js
+++ b/frontend/webpack.config.js
@@ -1,7 +1,10 @@
+/* eslint-disable @typescript-eslint/no-var-requires */
const HtmlWebpackPlugin = require('html-webpack-plugin');
const Dotenv = require('dotenv-webpack');
const path = require('path');
const webpack = require('webpack');
+const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
+const CompressionPlugin = require('compression-webpack-plugin');
const prod = process.env.NODE_ENV === 'production';
@@ -15,10 +18,13 @@ const plugins = [
}),
new webpack.HotModuleReplacementPlugin(),
new Dotenv(),
+ new BundleAnalyzerPlugin(),
+ new CompressionPlugin(),
];
if (!prod) {
const CopyPlugin = require('copy-webpack-plugin');
+
plugins.push(
new CopyPlugin({
patterns: [{ from: 'public/mockServiceWorker.js', to: '' }],
@@ -51,16 +57,18 @@ module.exports = {
use: ['url-loader'],
},
{
- test: /\.png$/i,
+ test: /\.(png|jpg)$/i,
issuer: /\.[jt]sx?$/,
use: ['url-loader'],
},
],
},
+
output: {
path: path.join(__dirname, '/dist'),
- filename: 'bundle.js',
+ filename: '[name].[chunkhash].bundle.js',
publicPath: '/',
+ clean: true,
},
devServer: {
@@ -90,4 +98,10 @@ module.exports = {
},
},
plugins,
+
+ optimization: {
+ splitChunks: {
+ chunks: 'all',
+ },
+ },
};