From 721195bd2e6741a1b39d45b2e01f33b86c8b6594 Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 20 Mar 2026 12:17:03 +0900 Subject: [PATCH 01/21] =?UTF-8?q?#001=20=E3=83=93=E3=83=AB=E3=83=89?= =?UTF-8?q?=E8=A8=AD=E5=AE=9A=E3=81=AE=E6=9C=AC=E7=95=AA=E5=8C=96=20+=20?= =?UTF-8?q?=E3=83=9D=E3=83=AA=E3=83=95=E3=82=A3=E3=83=AB=E9=99=A4=E5=8E=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - webpack: mode production, minify, tree shaking 有効化, ソースマップ除去 - babel: IE11→モダンブラウザ, ESモジュール化, React production - entry: 不要なポリフィル除去 (core-js, regenerator-runtime, jquery-binarytransport) - EnvironmentPlugin NODE_ENV を production に修正 main.js: 108MB → 31MB / Score: 2 → 4 --- application/client/babel.config.js | 7 +++---- application/client/package.json | 2 +- application/client/webpack.config.js | 23 +++++++++-------------- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/application/client/babel.config.js b/application/client/babel.config.js index c3c574591a..502104384a 100644 --- a/application/client/babel.config.js +++ b/application/client/babel.config.js @@ -4,16 +4,15 @@ module.exports = { [ "@babel/preset-env", { - targets: "ie 11", - corejs: "3", - modules: "commonjs", + targets: "defaults", + modules: false, useBuiltIns: false, }, ], [ "@babel/preset-react", { - development: true, + development: false, runtime: "automatic", }, ], diff --git a/application/client/package.json b/application/client/package.json index 9f8e80a6a8..af2d3a5156 100644 --- a/application/client/package.json +++ b/application/client/package.json @@ -5,7 +5,7 @@ "license": "MPL-2.0", "author": "CyberAgent, Inc.", "scripts": { - "build": "NODE_ENV=development webpack", + "build": "NODE_ENV=production webpack", "typecheck": "tsc" }, "dependencies": { diff --git a/application/client/webpack.config.js b/application/client/webpack.config.js index 9fae72647f..0ee7565611 100644 --- a/application/client/webpack.config.js +++ b/application/client/webpack.config.js @@ -25,18 +25,15 @@ const config = { ], static: [PUBLIC_PATH, UPLOAD_PATH], }, - devtool: "inline-source-map", + devtool: false, entry: { main: [ - "core-js", - "regenerator-runtime/runtime", - "jquery-binarytransport", path.resolve(SRC_PATH, "./index.css"), path.resolve(SRC_PATH, "./buildinfo.ts"), path.resolve(SRC_PATH, "./index.tsx"), ], }, - mode: "none", + mode: "production", module: { rules: [ { @@ -60,10 +57,9 @@ const config = { }, output: { chunkFilename: "scripts/chunk-[contenthash].js", - chunkFormat: false, filename: "scripts/[name].js", path: DIST_PATH, - publicPath: "auto", + publicPath: "/", clean: true, }, plugins: [ @@ -77,7 +73,7 @@ const config = { BUILD_DATE: new Date().toISOString(), // Heroku では SOURCE_VERSION 環境変数から commit hash を参照できます COMMIT_HASH: process.env.SOURCE_VERSION || "", - NODE_ENV: "development", + NODE_ENV: "production", }), new MiniCssExtractPlugin({ filename: "styles/[name].css", @@ -128,14 +124,13 @@ const config = { }, }, optimization: { - minimize: false, + minimize: true, splitChunks: false, - concatenateModules: false, - usedExports: false, - providedExports: false, - sideEffects: false, + concatenateModules: true, + usedExports: true, + providedExports: true, + sideEffects: true, }, - cache: false, ignoreWarnings: [ { module: /@ffmpeg/, From f744b7784a1f8cf4735e328224d7ae5d0e2f995d Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 20 Mar 2026 17:46:42 +0900 Subject: [PATCH 02/21] =?UTF-8?q?#005-008=20=E3=83=91=E3=83=95=E3=82=A9?= =?UTF-8?q?=E3=83=BC=E3=83=9E=E3=83=B3=E3=82=B9=E7=BD=A0=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - fetchers.ts: async:false 除去(メインスレッドブロック解消) - index.tsx: window.load → DOMContentLoaded(描画開始を早期化) - InfiniteScroll.tsx: 2^18回ループ削除 + passive:true - AspectRatioBox.tsx: 500ms遅延削除 + passive:true Score: 4 → 44 / TBT: 7,530ms → 430ms / CLS: 0.484 → 0 --- .../components/foundation/AspectRatioBox.tsx | 4 ++-- .../components/foundation/InfiniteScroll.tsx | 18 ++++-------------- application/client/src/index.tsx | 2 +- application/client/src/utils/fetchers.ts | 4 ---- 4 files changed, 7 insertions(+), 21 deletions(-) diff --git a/application/client/src/components/foundation/AspectRatioBox.tsx b/application/client/src/components/foundation/AspectRatioBox.tsx index 0ae891963c..83b67f7fe0 100644 --- a/application/client/src/components/foundation/AspectRatioBox.tsx +++ b/application/client/src/components/foundation/AspectRatioBox.tsx @@ -19,10 +19,10 @@ export const AspectRatioBox = ({ aspectHeight, aspectWidth, children }: Props) = const clientWidth = ref.current?.clientWidth ?? 0; setClientHeight((clientWidth / aspectWidth) * aspectHeight); } - setTimeout(() => calcStyle(), 500); + calcStyle(); // ウィンドウサイズが変わるたびに計算する - window.addEventListener("resize", calcStyle, { passive: false }); + window.addEventListener("resize", calcStyle, { passive: true }); return () => { window.removeEventListener("resize", calcStyle); }; diff --git a/application/client/src/components/foundation/InfiniteScroll.tsx b/application/client/src/components/foundation/InfiniteScroll.tsx index 408f24c107..0221fde640 100644 --- a/application/client/src/components/foundation/InfiniteScroll.tsx +++ b/application/client/src/components/foundation/InfiniteScroll.tsx @@ -13,14 +13,9 @@ export const InfiniteScroll = ({ children, fetchMore, items }: Props) => { useEffect(() => { const handler = () => { - // 念の為 2の18乗 回、最下部かどうかを確認する - const hasReached = Array.from(Array(2 ** 18), () => { - return window.innerHeight + Math.ceil(window.scrollY) >= document.body.offsetHeight; - }).every(Boolean); + const hasReached = window.innerHeight + Math.ceil(window.scrollY) >= document.body.offsetHeight; - // 画面最下部にスクロールしたタイミングで、登録したハンドラを呼び出す if (hasReached && !prevReachedRef.current) { - // アイテムがないときは追加で読み込まない if (latestItem !== undefined) { fetchMore(); } @@ -29,19 +24,14 @@ export const InfiniteScroll = ({ children, fetchMore, items }: Props) => { prevReachedRef.current = hasReached; }; - // 最初は実行されないので手動で呼び出す prevReachedRef.current = false; handler(); - document.addEventListener("wheel", handler, { passive: false }); - document.addEventListener("touchmove", handler, { passive: false }); - document.addEventListener("resize", handler, { passive: false }); - document.addEventListener("scroll", handler, { passive: false }); + document.addEventListener("scroll", handler, { passive: true }); + window.addEventListener("resize", handler, { passive: true }); return () => { - document.removeEventListener("wheel", handler); - document.removeEventListener("touchmove", handler); - document.removeEventListener("resize", handler); document.removeEventListener("scroll", handler); + window.removeEventListener("resize", handler); }; }, [latestItem, fetchMore]); diff --git a/application/client/src/index.tsx b/application/client/src/index.tsx index b1833b0af3..871e45920e 100644 --- a/application/client/src/index.tsx +++ b/application/client/src/index.tsx @@ -5,7 +5,7 @@ import { BrowserRouter } from "react-router"; import { AppContainer } from "@web-speed-hackathon-2026/client/src/containers/AppContainer"; import { store } from "@web-speed-hackathon-2026/client/src/store"; -window.addEventListener("load", () => { +document.addEventListener("DOMContentLoaded", () => { createRoot(document.getElementById("app")!).render( diff --git a/application/client/src/utils/fetchers.ts b/application/client/src/utils/fetchers.ts index 92a14f408f..c4615071b6 100644 --- a/application/client/src/utils/fetchers.ts +++ b/application/client/src/utils/fetchers.ts @@ -3,7 +3,6 @@ import { gzip } from "pako"; export async function fetchBinary(url: string): Promise { const result = await $.ajax({ - async: false, dataType: "binary", method: "GET", responseType: "arraybuffer", @@ -14,7 +13,6 @@ export async function fetchBinary(url: string): Promise { export async function fetchJSON(url: string): Promise { const result = await $.ajax({ - async: false, dataType: "json", method: "GET", url, @@ -24,7 +22,6 @@ export async function fetchJSON(url: string): Promise { export async function sendFile(url: string, file: File): Promise { const result = await $.ajax({ - async: false, data: file, dataType: "json", headers: { @@ -43,7 +40,6 @@ export async function sendJSON(url: string, data: object): Promise { const compressed = gzip(uint8Array); const result = await $.ajax({ - async: false, data: compressed, dataType: "json", headers: { From dce842a2aa46f53519185da2c878667f78df688f Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 20 Mar 2026 18:03:23 +0900 Subject: [PATCH 03/21] =?UTF-8?q?#002-003=20gzip=E5=9C=A7=E7=B8=AE=20+=20W?= =?UTF-8?q?ASM/FFmpeg=E5=A4=96=E9=83=A8=E3=83=95=E3=82=A1=E3=82=A4?= =?UTF-8?q?=E3=83=AB=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - サーバーにcompression middlewareを追加(gzip圧縮) - Cache-Control: max-age=0, no-transform / Connection: close ヘッダーを除去 - webpack: asset/bytes → asset/resource でWASM/FFmpegを別ファイルに分離 - convert_image.ts: WASM URLをfetchしてUint8Arrayで渡す方式に変更 - load_ffmpeg.ts: Blob URL生成を廃止し直接URLを渡す方式に変更 - main.js 31MB → 12.3MB、FCP 160.6s → 66.0s (-59%) --- application/client/src/utils/convert_image.ts | 5 +++-- application/client/src/utils/load_ffmpeg.ts | 8 ++----- application/client/webpack.config.js | 5 ++++- application/pnpm-lock.yaml | 22 +++++++++++++++---- application/server/package.json | 2 ++ application/server/src/app.ts | 11 +++------- 6 files changed, 32 insertions(+), 21 deletions(-) diff --git a/application/client/src/utils/convert_image.ts b/application/client/src/utils/convert_image.ts index 9fce086d9c..014fd31681 100644 --- a/application/client/src/utils/convert_image.ts +++ b/application/client/src/utils/convert_image.ts @@ -1,5 +1,5 @@ import { initializeImageMagick, ImageMagick, MagickFormat } from "@imagemagick/magick-wasm"; -import magickWasm from "@imagemagick/magick-wasm/magick.wasm?binary"; +import magickWasmUrl from "@imagemagick/magick-wasm/magick.wasm?binary"; import { dump, insert, ImageIFD } from "piexifjs"; interface Options { @@ -7,7 +7,8 @@ interface Options { } export async function convertImage(file: File, options: Options): Promise { - await initializeImageMagick(magickWasm); + const wasmBinary = await fetch(magickWasmUrl).then((r) => r.arrayBuffer()); + await initializeImageMagick(new Uint8Array(wasmBinary)); const byteArray = new Uint8Array(await file.arrayBuffer()); diff --git a/application/client/src/utils/load_ffmpeg.ts b/application/client/src/utils/load_ffmpeg.ts index f923a3d5a4..e40c942c07 100644 --- a/application/client/src/utils/load_ffmpeg.ts +++ b/application/client/src/utils/load_ffmpeg.ts @@ -4,12 +4,8 @@ export async function loadFFmpeg(): Promise { const ffmpeg = new FFmpeg(); await ffmpeg.load({ - coreURL: await import("@ffmpeg/core?binary").then(({ default: b }) => { - return URL.createObjectURL(new Blob([b], { type: "text/javascript" })); - }), - wasmURL: await import("@ffmpeg/core/wasm?binary").then(({ default: b }) => { - return URL.createObjectURL(new Blob([b], { type: "application/wasm" })); - }), + coreURL: (await import("@ffmpeg/core?binary")).default, + wasmURL: (await import("@ffmpeg/core/wasm?binary")).default, }); return ffmpeg; diff --git a/application/client/webpack.config.js b/application/client/webpack.config.js index 0ee7565611..8c1157d93a 100644 --- a/application/client/webpack.config.js +++ b/application/client/webpack.config.js @@ -51,7 +51,10 @@ const config = { }, { resourceQuery: /binary/, - type: "asset/bytes", + type: "asset/resource", + generator: { + filename: "assets/[hash][ext]", + }, }, ], }, diff --git a/application/pnpm-lock.yaml b/application/pnpm-lock.yaml index 510570f5c9..142746e58d 100644 --- a/application/pnpm-lock.yaml +++ b/application/pnpm-lock.yaml @@ -62,7 +62,7 @@ importers: version: 9.5.0 gifler: specifier: github:themadcreator/gifler#v0.3.0 - version: https://codeload.github.com/themadcreator/gifler/tar.gz/c3259b071c7782f85d4928a5f03d0b378ed003b5 + version: https://codeload.github.com/themadcreator/gifler/tar.gz/89484cb3db174c584a3138e89664f0167a7760c1 image-size: specifier: 2.0.2 version: 2.0.2 @@ -268,6 +268,9 @@ importers: '@tsconfig/strictest': specifier: 2.0.8 version: 2.0.8 + '@types/compression': + specifier: 1.8.1 + version: 1.8.1 '@web-speed-hackathon-2026/server': specifier: workspace:* version: 'link:' @@ -277,6 +280,9 @@ importers: body-parser: specifier: 2.2.0 version: 2.2.0 + compression: + specifier: 1.8.1 + version: 1.8.1 connect-history-api-fallback: specifier: 2.0.0 version: 2.0.0 @@ -1637,6 +1643,9 @@ packages: '@types/common-tags@1.8.4': resolution: {integrity: sha512-S+1hLDJPjWNDhcGxsxEbepzaxWqURP/o+3cP4aa2w7yBXgdcmKGQtZzP8JbyfOd0m+33nh+8+kvxYE2UJtBDkg==} + '@types/compression@1.8.1': + resolution: {integrity: sha512-kCFuWS0ebDbmxs0AXYn6e2r2nrGAb5KwQhknjSPSPgJcGd8+HVSILlUyFhGqML2gk39HcG7D1ydW9/qpYkN00Q==} + '@types/connect-history-api-fallback@1.5.4': resolution: {integrity: sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==} @@ -2667,8 +2676,8 @@ packages: get-tsconfig@4.13.0: resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} - gifler@https://codeload.github.com/themadcreator/gifler/tar.gz/c3259b071c7782f85d4928a5f03d0b378ed003b5: - resolution: {tarball: https://codeload.github.com/themadcreator/gifler/tar.gz/c3259b071c7782f85d4928a5f03d0b378ed003b5} + gifler@https://codeload.github.com/themadcreator/gifler/tar.gz/89484cb3db174c584a3138e89664f0167a7760c1: + resolution: {tarball: https://codeload.github.com/themadcreator/gifler/tar.gz/89484cb3db174c584a3138e89664f0167a7760c1} version: 0.3.0 github-from-package@0.0.0: @@ -6003,6 +6012,11 @@ snapshots: '@types/common-tags@1.8.4': {} + '@types/compression@1.8.1': + dependencies: + '@types/express': 5.0.3 + '@types/node': 22.18.8 + '@types/connect-history-api-fallback@1.5.4': dependencies: '@types/express-serve-static-core': 5.1.0 @@ -7161,7 +7175,7 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 - gifler@https://codeload.github.com/themadcreator/gifler/tar.gz/c3259b071c7782f85d4928a5f03d0b378ed003b5: + gifler@https://codeload.github.com/themadcreator/gifler/tar.gz/89484cb3db174c584a3138e89664f0167a7760c1: dependencies: bluebird: 3.7.2 omggif: 1.0.10 diff --git a/application/server/package.json b/application/server/package.json index 9482575df7..a5467c16ab 100644 --- a/application/server/package.json +++ b/application/server/package.json @@ -14,9 +14,11 @@ }, "dependencies": { "@tsconfig/strictest": "2.0.8", + "@types/compression": "1.8.1", "@web-speed-hackathon-2026/server": "workspace:*", "bcrypt": "6.0.0", "body-parser": "2.2.0", + "compression": "1.8.1", "connect-history-api-fallback": "2.0.0", "express": "5.1.0", "express-session": "1.18.2", diff --git a/application/server/src/app.ts b/application/server/src/app.ts index 671fb424cc..cce288ae73 100644 --- a/application/server/src/app.ts +++ b/application/server/src/app.ts @@ -1,4 +1,5 @@ import bodyParser from "body-parser"; +import compression from "compression"; import Express from "express"; import { apiRouter } from "@web-speed-hackathon-2026/server/src/routes/api"; @@ -9,17 +10,11 @@ export const app = Express(); app.set("trust proxy", true); +app.use(compression()); + app.use(sessionMiddleware); app.use(bodyParser.json()); app.use(bodyParser.raw({ limit: "10mb" })); -app.use((_req, res, next) => { - res.header({ - "Cache-Control": "max-age=0, no-transform", - Connection: "close", - }); - return next(); -}); - app.use("/api/v1", apiRouter); app.use(staticRouter); From 6e8f76ecc26bd748ce6f64cf93f721335bde7eac Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 20 Mar 2026 22:45:06 +0900 Subject: [PATCH 04/21] =?UTF-8?q?#004=20=E9=87=8D=E9=87=8F=E3=83=A9?= =?UTF-8?q?=E3=82=A4=E3=83=96=E3=83=A9=E3=83=AA=E9=99=A4=E5=8E=BB=20+=20?= =?UTF-8?q?=E3=82=B3=E3=83=BC=E3=83=89=E5=88=86=E5=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - moment.js → Intl.DateTimeFormat / Intl.RelativeTimeFormat に置換 (-0.67MB) - lodash → ネイティブJS に置換 (-0.53MB) - standardized-audio-context → ネイティブAudioContext に置換 (-0.52MB) - CrokContainer / SearchContainer / NewPostModalContainer を React.lazy化 - web-llm / negaposi-analyzer-ja を dynamic import化 - main.js 11.89MB → 700KB (94%削減)、FCP 63.6s → 5.2s --- .../direct_message/DirectMessageListPage.tsx | 14 ++++- .../direct_message/DirectMessagePage.tsx | 3 +- .../components/foundation/SoundWaveSVG.tsx | 35 ++++++----- .../src/components/post/CommentItem.tsx | 6 +- .../client/src/components/post/PostItem.tsx | 6 +- .../src/components/timeline/TimelineItem.tsx | 5 +- .../user_profile/UserProfileHeader.tsx | 5 +- .../client/src/containers/AppContainer.tsx | 59 ++++++++++--------- application/client/src/utils/bm25_search.ts | 14 ++--- .../client/src/utils/create_translator.ts | 2 +- .../client/src/utils/negaposi_analyzer.ts | 18 +++--- application/client/webpack.config.js | 1 - 12 files changed, 88 insertions(+), 80 deletions(-) diff --git a/application/client/src/components/direct_message/DirectMessageListPage.tsx b/application/client/src/components/direct_message/DirectMessageListPage.tsx index 5a373e918e..e5164c8318 100644 --- a/application/client/src/components/direct_message/DirectMessageListPage.tsx +++ b/application/client/src/components/direct_message/DirectMessageListPage.tsx @@ -1,4 +1,3 @@ -import moment from "moment"; import { useCallback, useEffect, useState } from "react"; import { Button } from "@web-speed-hackathon-2026/client/src/components/foundation/Button"; @@ -100,7 +99,18 @@ export const DirectMessageListPage = ({ activeUser, newDmModalId }: Props) => { className="text-cax-text-subtle text-xs" dateTime={lastMessage.createdAt} > - {moment(lastMessage.createdAt).locale("ja").fromNow()} + {(() => { + const diff = Date.now() - new Date(lastMessage.createdAt).getTime(); + const rtf = new Intl.RelativeTimeFormat("ja", { numeric: "auto" }); + const sec = Math.round(diff / 1000); + if (sec < 60) return rtf.format(-sec, "second"); + const min = Math.round(diff / 60000); + if (min < 60) return rtf.format(-min, "minute"); + const hr = Math.round(diff / 3600000); + if (hr < 24) return rtf.format(-hr, "hour"); + const day = Math.round(diff / 86400000); + return rtf.format(-day, "day"); + })()} )} diff --git a/application/client/src/components/direct_message/DirectMessagePage.tsx b/application/client/src/components/direct_message/DirectMessagePage.tsx index 098c7d2894..4d896b43fb 100644 --- a/application/client/src/components/direct_message/DirectMessagePage.tsx +++ b/application/client/src/components/direct_message/DirectMessagePage.tsx @@ -1,5 +1,4 @@ import classNames from "classnames"; -import moment from "moment"; import { ChangeEvent, useCallback, @@ -141,7 +140,7 @@ export const DirectMessagePage = ({

{isActiveUserSend && message.isRead && ( 既読 diff --git a/application/client/src/components/foundation/SoundWaveSVG.tsx b/application/client/src/components/foundation/SoundWaveSVG.tsx index d95e63164c..9ab8edea30 100644 --- a/application/client/src/components/foundation/SoundWaveSVG.tsx +++ b/application/client/src/components/foundation/SoundWaveSVG.tsx @@ -1,4 +1,3 @@ -import _ from "lodash"; import { useEffect, useRef, useState } from "react"; interface ParsedData { @@ -9,21 +8,29 @@ interface ParsedData { async function calculate(data: ArrayBuffer): Promise { const audioCtx = new AudioContext(); - // 音声をデコードする const buffer = await audioCtx.decodeAudioData(data.slice(0)); - // 左の音声データの絶対値を取る - const leftData = _.map(buffer.getChannelData(0), Math.abs); - // 右の音声データの絶対値を取る - const rightData = _.map(buffer.getChannelData(1), Math.abs); + const leftData = buffer.getChannelData(0); + const rightData = buffer.getChannelData(1); - // 左右の音声データの平均を取る - const normalized = _.map(_.zip(leftData, rightData), _.mean); - // 100 個の chunk に分ける - const chunks = _.chunk(normalized, Math.ceil(normalized.length / 100)); - // chunk ごとに平均を取る - const peaks = _.map(chunks, _.mean); - // chunk の平均の中から最大値を取る - const max = _.max(peaks) ?? 0; + const len = leftData.length; + const normalized = new Float32Array(len); + for (let i = 0; i < len; i++) { + normalized[i] = (Math.abs(leftData[i]) + Math.abs(rightData[i])) / 2; + } + + const chunkSize = Math.ceil(len / 100); + const peaks: number[] = []; + let max = 0; + for (let i = 0; i < len; i += chunkSize) { + const end = Math.min(i + chunkSize, len); + let sum = 0; + for (let j = i; j < end; j++) { + sum += normalized[j]; + } + const mean = sum / (end - i); + peaks.push(mean); + if (mean > max) max = mean; + } return { max, peaks }; } diff --git a/application/client/src/components/post/CommentItem.tsx b/application/client/src/components/post/CommentItem.tsx index cb5bd38bda..804bb53b2b 100644 --- a/application/client/src/components/post/CommentItem.tsx +++ b/application/client/src/components/post/CommentItem.tsx @@ -1,5 +1,3 @@ -import moment from "moment"; - import { Link } from "@web-speed-hackathon-2026/client/src/components/foundation/Link"; import { TranslatableText } from "@web-speed-hackathon-2026/client/src/components/post/TranslatableText"; import { getProfileImagePath } from "@web-speed-hackathon-2026/client/src/utils/get_path"; @@ -42,8 +40,8 @@ export const CommentItem = ({ comment }: Props) => {

-

diff --git a/application/client/src/components/post/PostItem.tsx b/application/client/src/components/post/PostItem.tsx index 5fa904c91a..f15b35078d 100644 --- a/application/client/src/components/post/PostItem.tsx +++ b/application/client/src/components/post/PostItem.tsx @@ -1,5 +1,3 @@ -import moment from "moment"; - import { Link } from "@web-speed-hackathon-2026/client/src/components/foundation/Link"; import { ImageArea } from "@web-speed-hackathon-2026/client/src/components/post/ImageArea"; import { MovieArea } from "@web-speed-hackathon-2026/client/src/components/post/MovieArea"; @@ -67,8 +65,8 @@ export const PostItem = ({ post }: Props) => { ) : null}

-

diff --git a/application/client/src/components/timeline/TimelineItem.tsx b/application/client/src/components/timeline/TimelineItem.tsx index 21b88980f8..a30418a335 100644 --- a/application/client/src/components/timeline/TimelineItem.tsx +++ b/application/client/src/components/timeline/TimelineItem.tsx @@ -1,4 +1,3 @@ -import moment from "moment"; import { MouseEventHandler, useCallback } from "react"; import { Link, useNavigate } from "react-router"; @@ -76,8 +75,8 @@ export const TimelineItem = ({ post }: Props) => { - -