From c183f59a0ba95f8ebd08b488631fcb0da879f737 Mon Sep 17 00:00:00 2001 From: sliptype Date: Wed, 15 Nov 2023 15:41:28 -0600 Subject: [PATCH 01/74] Add vike --- .circleci/src/commands/@web-commands.yml | 1 + .gitignore | 3 + package-lock.json | 483 +++- packages/web/package.json | 1 + packages/web/pages/index.page.tsx | 16 + packages/web/renderer/PageLayout.tsx | 68 + .../web/renderer/_default.page.client.tsx | 17 + .../web/renderer/_default.page.server.tsx | 28 + packages/web/scripts/workers-site/index.js | 39 +- .../scripts/workers-site/package-lock.json | 1979 ++++++++++++++++- .../web/scripts/workers-site/package.json | 7 +- packages/web/scripts/workers-site/ssr.js | 17 + packages/web/vite.config.ts | 2 + packages/web/wrangler.toml | 4 +- 14 files changed, 2634 insertions(+), 31 deletions(-) create mode 100644 packages/web/pages/index.page.tsx create mode 100644 packages/web/renderer/PageLayout.tsx create mode 100644 packages/web/renderer/_default.page.client.tsx create mode 100644 packages/web/renderer/_default.page.server.tsx create mode 100644 packages/web/scripts/workers-site/ssr.js diff --git a/.circleci/src/commands/@web-commands.yml b/.circleci/src/commands/@web-commands.yml index a5d99720a69..457dd3f7982 100644 --- a/.circleci/src/commands/@web-commands.yml +++ b/.circleci/src/commands/@web-commands.yml @@ -174,6 +174,7 @@ web-deploy-cloudflare: - checkout - attach_workspace: at: ./ + # TODO: Just do npx wrangler - web-install-wrangler # - run: # name: Move sourcemaps diff --git a/.gitignore b/.gitignore index 19f303968c6..08da851d8ac 100644 --- a/.gitignore +++ b/.gitignore @@ -206,3 +206,6 @@ combined-patch-file.txt # Identity packages/identity-service/emailCache + +# CloudFlare +.wrangler \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 1f6433739e2..dae2f030f5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2891,6 +2891,34 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/@brillout/import": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@brillout/import/-/import-0.2.3.tgz", + "integrity": "sha512-1T8WlD75eeFSMrptGy8jiLHmfHgMmSjWvLOIUvHmSVZt+6k0eQqYUoK4KbmE4T9pVLIfxvZSOm2D68VEqKRHRw==" + }, + "node_modules/@brillout/json-serializer": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/@brillout/json-serializer/-/json-serializer-0.5.8.tgz", + "integrity": "sha512-vEuXw30ok+mJfJutOxXKBb4lBJ0HymA7lev9PcYK6W/hzjhCTPk9Bdk85HrcNcKZWRQiwoWtw0F2Di4TRJ7ssQ==" + }, + "node_modules/@brillout/picocolors": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@brillout/picocolors/-/picocolors-1.0.9.tgz", + "integrity": "sha512-Lt/W5JsA75hcDJ2cOAlE4TqSMl6c9K+rXGRo/cU2fApnmhbRcNdkR4UHQDAwtWfZyUKWaxdwSui+jp+74J1pZg==" + }, + "node_modules/@brillout/require-shim": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@brillout/require-shim/-/require-shim-0.1.2.tgz", + "integrity": "sha512-3I4LRHnVZXoSAsEoni5mosq9l6eiJED58d9V954W4CIZ88AUfYBanWGBGbJG3NztaRTpFHEA6wB3Hn93BmmJdg==" + }, + "node_modules/@brillout/vite-plugin-import-build": { + "version": "0.2.20", + "resolved": "https://registry.npmjs.org/@brillout/vite-plugin-import-build/-/vite-plugin-import-build-0.2.20.tgz", + "integrity": "sha512-/bdw1dg+H1nOYSy2PzYInQoZlIFP2uwyaF2GX64fyBqVAEWGopiMlnx294CbysjmP9Z+fJe48TkMzyogkyIDLw==", + "dependencies": { + "@brillout/import": "^0.2.3" + } + }, "node_modules/@certusone/wormhole-sdk": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk/-/wormhole-sdk-0.1.1.tgz", @@ -3232,6 +3260,11 @@ "node": ">=10.0.0" } }, + "node_modules/@cloudflare/workers-types": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-2.2.2.tgz", + "integrity": "sha512-kaMn2rueJ0PL1TYVGknTCh0X0x0d9G+FNXAFep7/4uqecEZoQb/63o6rOmMuiqI09zLuHV6xhKRXinokV/MY9A==" + }, "node_modules/@cnakazawa/watch": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", @@ -45273,7 +45306,6 @@ "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "dev": true, "engines": { "node": ">=8" } @@ -111988,6 +112020,438 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/vike": { + "version": "0.4.146", + "resolved": "https://registry.npmjs.org/vike/-/vike-0.4.146.tgz", + "integrity": "sha512-1vaktcDy/eitSzVaUppKJWu+6vfwxKC4kV6uzAqj3RIK+WgteH3vF6IMZ0jnjjzCpeDRCIByN8PF4c0CtzRfHA==", + "dependencies": { + "@brillout/import": "0.2.3", + "@brillout/json-serializer": "^0.5.8", + "@brillout/picocolors": "^1.0.9", + "@brillout/require-shim": "^0.1.2", + "@brillout/vite-plugin-import-build": "^0.2.20", + "acorn": "^8.8.2", + "cac": "^6.7.14", + "es-module-lexer": "^1.3.0", + "esbuild": "^0.17.18", + "fast-glob": "^3.2.12", + "sirv": "^2.0.2", + "source-map-support": "^0.5.21" + }, + "bin": { + "vike": "node/cli/bin-entry.js" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "react-streaming": ">=0.3.5", + "vite": ">=3.1.0" + }, + "peerDependenciesMeta": { + "react-streaming": { + "optional": true + } + } + }, + "node_modules/vike/node_modules/@esbuild/android-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/android-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/android-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/darwin-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/darwin-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/freebsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/linux-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/linux-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/linux-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/linux-loong64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/linux-mips64el": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/linux-ppc64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/linux-riscv64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/linux-s390x": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/linux-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", + "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/netbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/openbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/sunos-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/win32-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/win32-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/@esbuild/win32-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vike/node_modules/acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/vike/node_modules/esbuild": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", + "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" + } + }, + "node_modules/vike/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==", + "dependencies": { + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/vike/node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "engines": { + "node": ">=6" + } + }, "node_modules/vite": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", @@ -148827,6 +149291,7 @@ "@audius/sdk": "*", "@audius/stems": "*", "@audius/trpc-server": "*", + "@cloudflare/kv-asset-handler": "~0.0.11", "@coinbase/cbpay-js": "1.2.0", "@fingerprintjs/fingerprintjs-pro": "3.5.6", "@hcaptcha/react-hcaptcha": "0.3.6", @@ -148940,6 +149405,7 @@ "type-fest": "2.16.0", "typed-redux-saga": "1.3.1", "typesafe-actions": "5.1.0", + "vike": "^0.4.146", "walletlink": "2.0.3", "wasm-loader": "1.3.0", "web-vitals": "0.2.2", @@ -149023,6 +149489,16 @@ "vitest": "0.34.6" } }, + "packages/web/node_modules/@cloudflare/kv-asset-handler": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.0.12.tgz", + "integrity": "sha512-3XCs9TRhQh/yUs1ST9cIMLB8C5c1JRKcDYTPJbAmcgI0kO2FPCSZz+kyNb9x25DuGQeqOMMwmxHPtiOfTki/Gw==", + "dependencies": { + "@cloudflare/workers-types": "^2.0.0", + "@types/mime": "^2.0.2", + "mime": "^2.4.6" + } + }, "packages/web/node_modules/@humanwhocodes/config-array": { "version": "0.9.5", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", @@ -149543,6 +150019,11 @@ "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-2.2.6.tgz", "integrity": "sha512-+oY0FDTO2GYKEV0YPvSshGq9t7YozVkgvXLty7zogQNuCxBhT9/3INX9Q7H1aRZ4SUDRXAKlJuA4EA5nTt7SNw==" }, + "packages/web/node_modules/@types/mime": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", + "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==" + }, "packages/web/node_modules/@types/node": { "version": "12.12.35", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.35.tgz", diff --git a/packages/web/package.json b/packages/web/package.json index f754252f3b0..02896d3ef20 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -170,6 +170,7 @@ "type-fest": "2.16.0", "typed-redux-saga": "1.3.1", "typesafe-actions": "5.1.0", + "vike": "^0.4.146", "walletlink": "2.0.3", "wasm-loader": "1.3.0", "web-vitals": "0.2.2", diff --git a/packages/web/pages/index.page.tsx b/packages/web/pages/index.page.tsx new file mode 100644 index 00000000000..8efd19ca405 --- /dev/null +++ b/packages/web/pages/index.page.tsx @@ -0,0 +1,16 @@ +import React from 'react' + +export { Page } + +function Page() { + return ( + <> +

Welcome

+ This page is: + + + ) +} diff --git a/packages/web/renderer/PageLayout.tsx b/packages/web/renderer/PageLayout.tsx new file mode 100644 index 00000000000..25e48daf283 --- /dev/null +++ b/packages/web/renderer/PageLayout.tsx @@ -0,0 +1,68 @@ +import React from 'react' + +export { PageLayout } + +function PageLayout({ children }) { + return ( + + + + + Home + + + About + + + {children} + + + ) +} + +function Layout({ children }) { + return ( +
+ {children} +
+ ) +} + +function Sidebar({ children }) { + return ( +
+ {children} +
+ ) +} + +function Content({ children }) { + return ( +
+ {children} +
+ ) +} diff --git a/packages/web/renderer/_default.page.client.tsx b/packages/web/renderer/_default.page.client.tsx new file mode 100644 index 00000000000..7a52bd15247 --- /dev/null +++ b/packages/web/renderer/_default.page.client.tsx @@ -0,0 +1,17 @@ +import React from 'react' + +import { hydrateRoot } from 'react-dom/client' + +import { PageLayout } from './PageLayout' + +export { render } + +async function render(pageContext) { + const { Page, pageProps } = pageContext + hydrateRoot( + document.getElementById('page-view'), + + + + ) +} diff --git a/packages/web/renderer/_default.page.server.tsx b/packages/web/renderer/_default.page.server.tsx new file mode 100644 index 00000000000..4298b10c79b --- /dev/null +++ b/packages/web/renderer/_default.page.server.tsx @@ -0,0 +1,28 @@ +import React from 'react' + +import ReactDOMServer from 'react-dom/server' +import { escapeInject, dangerouslySkipEscape } from 'vike/server' + +import { PageLayout } from './PageLayout' + +export { render } +export { passToClient } + +// See https://vike.dev/data-fetching +const passToClient = ['pageProps'] + +function render(pageContext) { + const { Page, pageProps } = pageContext + const pageHtml = ReactDOMServer.renderToString( + + + + ) + + return escapeInject` + + +
${dangerouslySkipEscape(pageHtml)}
+ + ` +} diff --git a/packages/web/scripts/workers-site/index.js b/packages/web/scripts/workers-site/index.js index e47c490ff71..350dc007dcd 100644 --- a/packages/web/scripts/workers-site/index.js +++ b/packages/web/scripts/workers-site/index.js @@ -1,8 +1,10 @@ import { getAssetFromKV, mapRequestToAsset } from '@cloudflare/kv-asset-handler' +import { handleSsr } from './ssr' + /* globals GA, GA_ACCESS_TOKEN, EMBED, DISCOVERY_NODES, HTMLRewriter */ -const DEBUG = false +const DEBUG = true const BROWSER_CACHE_TTL_SECONDS = 60 * 60 * 24 const discoveryNodes = DISCOVERY_NODES.split(',') @@ -287,27 +289,28 @@ async function handleEvent(event) { } } - const asset = await getAssetFromKV(event, options) - - const rewritten = new HTMLRewriter() - .on('head', new SEOHandlerHead(pathname)) - .on('body', new SEOHandlerBody()) - .transform(asset) - - // Adjust browser cache on assets that don't change frequently and/or - // are given unique hashes when they do. - if ( - pathname.startsWith('/assets') || - pathname.startsWith('/scripts') || - pathname.startsWith('/fonts') - ) { - const response = new Response(rewritten.body, rewritten) + if (!isAssetUrl(event.request.url)) { + const response = await handleSsr(event.request.url) + if (response !== null) return response + } else { + // Adjust browser cache on assets that don't change frequently and/or + // are given unique hashes when they do. + const asset = await getAssetFromKV(event, options) + + const response = new Response(asset.body, asset) response.headers.set('cache-control', BROWSER_CACHE_TTL_SECONDS) return response } - - return rewritten } catch (e) { return new Response(e.message || e.toString(), { status: 500 }) } } + +function isAssetUrl(url) { + const { pathname } = new URL(url) + return ( + pathname.startsWith('/assets') || + pathname.startsWith('/scripts') || + pathname.startsWith('/fonts') + ) +} diff --git a/packages/web/scripts/workers-site/package-lock.json b/packages/web/scripts/workers-site/package-lock.json index 06c6d86eb66..41cc3e1bce3 100644 --- a/packages/web/scripts/workers-site/package-lock.json +++ b/packages/web/scripts/workers-site/package-lock.json @@ -1,33 +1,1994 @@ { - "name": "worker", + "name": "web-workers-site", "version": "1.0.0", - "lockfileVersion": 1, + "lockfileVersion": 3, "requires": true, - "dependencies": { - "@cloudflare/kv-asset-handler": { + "packages": { + "": { + "name": "web-workers-site", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@cloudflare/kv-asset-handler": "~0.0.11", + "@vitejs/plugin-react": "^4.1.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "vike": "^0.4.146", + "vite": "^4.5.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dependencies": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz", + "integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.3.tgz", + "integrity": "sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.2", + "@babel/parser": "^7.23.3", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.3", + "@babel/types": "^7.23.3", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.3.tgz", + "integrity": "sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==", + "dependencies": { + "@babel/types": "^7.23.3", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", + "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz", + "integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", + "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz", + "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.3.tgz", + "integrity": "sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.3", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.3", + "@babel/types": "^7.23.3", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.3.tgz", + "integrity": "sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==", + "dependencies": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@brillout/import": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@brillout/import/-/import-0.2.3.tgz", + "integrity": "sha512-1T8WlD75eeFSMrptGy8jiLHmfHgMmSjWvLOIUvHmSVZt+6k0eQqYUoK4KbmE4T9pVLIfxvZSOm2D68VEqKRHRw==" + }, + "node_modules/@brillout/json-serializer": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/@brillout/json-serializer/-/json-serializer-0.5.8.tgz", + "integrity": "sha512-vEuXw30ok+mJfJutOxXKBb4lBJ0HymA7lev9PcYK6W/hzjhCTPk9Bdk85HrcNcKZWRQiwoWtw0F2Di4TRJ7ssQ==" + }, + "node_modules/@brillout/picocolors": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@brillout/picocolors/-/picocolors-1.0.9.tgz", + "integrity": "sha512-Lt/W5JsA75hcDJ2cOAlE4TqSMl6c9K+rXGRo/cU2fApnmhbRcNdkR4UHQDAwtWfZyUKWaxdwSui+jp+74J1pZg==" + }, + "node_modules/@brillout/require-shim": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@brillout/require-shim/-/require-shim-0.1.2.tgz", + "integrity": "sha512-3I4LRHnVZXoSAsEoni5mosq9l6eiJED58d9V954W4CIZ88AUfYBanWGBGbJG3NztaRTpFHEA6wB3Hn93BmmJdg==" + }, + "node_modules/@brillout/vite-plugin-import-build": { + "version": "0.2.20", + "resolved": "https://registry.npmjs.org/@brillout/vite-plugin-import-build/-/vite-plugin-import-build-0.2.20.tgz", + "integrity": "sha512-/bdw1dg+H1nOYSy2PzYInQoZlIFP2uwyaF2GX64fyBqVAEWGopiMlnx294CbysjmP9Z+fJe48TkMzyogkyIDLw==", + "dependencies": { + "@brillout/import": "^0.2.3" + } + }, + "node_modules/@cloudflare/kv-asset-handler": { "version": "0.0.11", "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.0.11.tgz", "integrity": "sha512-D2kGr8NF2Er//Mx0c4+8FtOHuLrnwOlpC48TbtyxRSegG/Js15OKoqxxlG9BMUj3V/YSqtN8bUU6pjaRlsoSqg==", - "requires": { + "dependencies": { "@cloudflare/workers-types": "^2.0.0", "@types/mime": "^2.0.2", "mime": "^2.4.6" } }, - "@cloudflare/workers-types": { + "node_modules/@cloudflare/workers-types": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-2.0.0.tgz", "integrity": "sha512-SFUPQzR5aV2TBLP4Re+xNX5KfAGArcRGA44OLulBDnfblEf3J+6kFvdJAQwFhFpqru3wImwT1cX0wahk6EeWTw==" }, - "@types/mime": { + "node_modules/@esbuild/android-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", + "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.23", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.23.tgz", + "integrity": "sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==" + }, + "node_modules/@types/babel__core": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.4.tgz", + "integrity": "sha512-mLnSC22IC4vcWiuObSRjrLd9XcBTGf59vUSoq2jkQDJ/QQ8PMI9rSuzE+aEV8karUMbskw07bKYoUJCKTUaygg==", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz", + "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", + "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/mime": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.2.tgz", "integrity": "sha512-4kPlzbljFcsttWEq6aBW0OZe6BDajAmyvr2xknBG92tejQnvdGtT9+kXSZ580DqpxY9qG2xeQVF9Dq0ymUTo5Q==" }, - "mime": { + "node_modules/@vitejs/plugin-react": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.1.1.tgz", + "integrity": "sha512-Jie2HERK+uh27e+ORXXwEP5h0Y2lS9T2PRGbfebiHGlwzDO0dEnd2aNtOR/qjBlPb1YgxwAONeblL1xqLikLag==", + "dependencies": { + "@babel/core": "^7.23.2", + "@babel/plugin-transform-react-jsx-self": "^7.22.5", + "@babel/plugin-transform-react-jsx-source": "^7.22.5", + "@types/babel__core": "^7.20.3", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0" + } + }, + "node_modules/acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001562", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001562.tgz", + "integrity": "sha512-kfte3Hym//51EdX4239i+Rmp20EsLIYGdPkERegTgU19hQWCRhsRFGKHTliUlsry53tv17K7n077Kqa0WJU4ng==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.584", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.584.tgz", + "integrity": "sha512-rXCtDiXCBtfTfEegkthruCvyWZnr1/FCrUGY/nYQiF+lSZDmwQBDxp0rivZxV8trXb6cbgojhcSTW5xsDcHQ8g==" + }, + "node_modules/es-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", + "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==" + }, + "node_modules/esbuild": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", + "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { "version": "2.4.6", "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", - "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==" + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mrmime": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-refresh": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "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==", + "dependencies": { + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vike": { + "version": "0.4.146", + "resolved": "https://registry.npmjs.org/vike/-/vike-0.4.146.tgz", + "integrity": "sha512-1vaktcDy/eitSzVaUppKJWu+6vfwxKC4kV6uzAqj3RIK+WgteH3vF6IMZ0jnjjzCpeDRCIByN8PF4c0CtzRfHA==", + "dependencies": { + "@brillout/import": "0.2.3", + "@brillout/json-serializer": "^0.5.8", + "@brillout/picocolors": "^1.0.9", + "@brillout/require-shim": "^0.1.2", + "@brillout/vite-plugin-import-build": "^0.2.20", + "acorn": "^8.8.2", + "cac": "^6.7.14", + "es-module-lexer": "^1.3.0", + "esbuild": "^0.17.18", + "fast-glob": "^3.2.12", + "sirv": "^2.0.2", + "source-map-support": "^0.5.21" + }, + "bin": { + "vike": "node/cli/bin-entry.js" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "react-streaming": ">=0.3.5", + "vite": ">=3.1.0" + }, + "peerDependenciesMeta": { + "react-streaming": { + "optional": true + } + } + }, + "node_modules/vite": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", + "integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==", + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" } } } diff --git a/packages/web/scripts/workers-site/package.json b/packages/web/scripts/workers-site/package.json index bfa88a666ee..dd6f761e4cc 100644 --- a/packages/web/scripts/workers-site/package.json +++ b/packages/web/scripts/workers-site/package.json @@ -7,6 +7,11 @@ "author": "Ashley Lewis ", "license": "MIT", "dependencies": { - "@cloudflare/kv-asset-handler": "~0.0.11" + "@cloudflare/kv-asset-handler": "~0.0.11", + "@vitejs/plugin-react": "^4.1.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "vike": "^0.4.146", + "vite": "^4.5.0" } } diff --git a/packages/web/scripts/workers-site/ssr.js b/packages/web/scripts/workers-site/ssr.js new file mode 100644 index 00000000000..cc97776d4a2 --- /dev/null +++ b/packages/web/scripts/workers-site/ssr.js @@ -0,0 +1,17 @@ +import { renderPage } from 'vike/server' + +export async function handleSsr(url) { + const pageContextInit = { + urlOriginal: url + } + const pageContext = await renderPage(pageContextInit) + + return new Response('hi') + // const { httpResponse } = pageContext + // if (!httpResponse) { + // return null + // } else { + // const { body, statusCode: status, headers } = httpResponse + // return new Response(body, { headers, status }) + // } +} diff --git a/packages/web/vite.config.ts b/packages/web/vite.config.ts index fa15c31ed65..0b28de4b58f 100644 --- a/packages/web/vite.config.ts +++ b/packages/web/vite.config.ts @@ -4,6 +4,7 @@ import { NodeGlobalsPolyfillPlugin } from '@esbuild-plugins/node-globals-polyfil import react from '@vitejs/plugin-react' import process from 'process/browser' import { visualizer } from 'rollup-plugin-visualizer' +import vike from 'vike/plugin' import { defineConfig, loadEnv } from 'vite' import glslify from 'vite-plugin-glslify' import svgr from 'vite-plugin-svgr' @@ -70,6 +71,7 @@ export default defineConfig(({ mode }) => { plugins: ['@emotion/babel-plugin'] } }), + vike(), ...((analyze ? [ visualizer({ diff --git a/packages/web/wrangler.toml b/packages/web/wrangler.toml index 556ba9f0a63..ba34ff8ffba 100644 --- a/packages/web/wrangler.toml +++ b/packages/web/wrangler.toml @@ -1,10 +1,10 @@ type = "webpack" account_id = "3811365464a8e56b2b27a5590e328e49" workers_dev = true +main = "./scripts/workers-site/index.js" [site] bucket = "./build" -entry-point = "./scripts/workers-site" [env.staging] name = "audius-staging" @@ -23,7 +23,7 @@ name = "audius" vars = { ENVIRONMENT = "production", GA = "https://general-admission.audius.co", EMBED = "https://embed.audius.workers.dev", DISCOVERY_NODES = "https://discoveryprovider.audius.co,https://discoveryprovider2.audius.co,https://discoveryprovider3.audius.co" } # Test environment, replace `test` with subdomain -# Invoke with npx wrangler preview --watch --env test +# Invoke with npx wrangler dev --watch --env test [env.test] name = "test" vars = { ENVIRONMENT = "production", GA = "https://general-admission.audius.co", EMBED = "https://embed.audius.workers.dev", DISCOVERY_NODES = "https://discoveryprovider.audius.co,https://discoveryprovider2.audius.co,https://discoveryprovider3.audius.co" } \ No newline at end of file From 09a6f6c0c5d472836bb0aaa4a7ff372e372b9375 Mon Sep 17 00:00:00 2001 From: sliptype Date: Wed, 15 Nov 2023 15:45:17 -0600 Subject: [PATCH 02/74] Get basic ssr working --- packages/web/package.json | 1 + .../scripts/workers-site/package-lock.json | 1994 ----------------- .../web/scripts/workers-site/package.json | 17 - packages/web/scripts/workers-site/ssr.js | 15 +- packages/web/wrangler.toml | 2 +- 5 files changed, 9 insertions(+), 2020 deletions(-) delete mode 100644 packages/web/scripts/workers-site/package-lock.json delete mode 100644 packages/web/scripts/workers-site/package.json diff --git a/packages/web/package.json b/packages/web/package.json index 02896d3ef20..987a5b55fd8 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -57,6 +57,7 @@ "@audius/sdk": "*", "@audius/stems": "*", "@audius/trpc-server": "*", + "@cloudflare/kv-asset-handler": "0.2.0", "@coinbase/cbpay-js": "1.2.0", "@fingerprintjs/fingerprintjs-pro": "3.5.6", "@hcaptcha/react-hcaptcha": "0.3.6", diff --git a/packages/web/scripts/workers-site/package-lock.json b/packages/web/scripts/workers-site/package-lock.json deleted file mode 100644 index 41cc3e1bce3..00000000000 --- a/packages/web/scripts/workers-site/package-lock.json +++ /dev/null @@ -1,1994 +0,0 @@ -{ - "name": "web-workers-site", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "web-workers-site", - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "@cloudflare/kv-asset-handler": "~0.0.11", - "@vitejs/plugin-react": "^4.1.1", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "vike": "^0.4.146", - "vite": "^4.5.0" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "dependencies": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz", - "integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.3.tgz", - "integrity": "sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.3", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.2", - "@babel/parser": "^7.23.3", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.3", - "@babel/types": "^7.23.3", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.3.tgz", - "integrity": "sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==", - "dependencies": { - "@babel/types": "^7.23.3", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", - "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "dependencies": { - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", - "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", - "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.2", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz", - "integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", - "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz", - "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.3.tgz", - "integrity": "sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==", - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.3", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.3", - "@babel/types": "^7.23.3", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.3.tgz", - "integrity": "sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==", - "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@brillout/import": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@brillout/import/-/import-0.2.3.tgz", - "integrity": "sha512-1T8WlD75eeFSMrptGy8jiLHmfHgMmSjWvLOIUvHmSVZt+6k0eQqYUoK4KbmE4T9pVLIfxvZSOm2D68VEqKRHRw==" - }, - "node_modules/@brillout/json-serializer": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/@brillout/json-serializer/-/json-serializer-0.5.8.tgz", - "integrity": "sha512-vEuXw30ok+mJfJutOxXKBb4lBJ0HymA7lev9PcYK6W/hzjhCTPk9Bdk85HrcNcKZWRQiwoWtw0F2Di4TRJ7ssQ==" - }, - "node_modules/@brillout/picocolors": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@brillout/picocolors/-/picocolors-1.0.9.tgz", - "integrity": "sha512-Lt/W5JsA75hcDJ2cOAlE4TqSMl6c9K+rXGRo/cU2fApnmhbRcNdkR4UHQDAwtWfZyUKWaxdwSui+jp+74J1pZg==" - }, - "node_modules/@brillout/require-shim": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@brillout/require-shim/-/require-shim-0.1.2.tgz", - "integrity": "sha512-3I4LRHnVZXoSAsEoni5mosq9l6eiJED58d9V954W4CIZ88AUfYBanWGBGbJG3NztaRTpFHEA6wB3Hn93BmmJdg==" - }, - "node_modules/@brillout/vite-plugin-import-build": { - "version": "0.2.20", - "resolved": "https://registry.npmjs.org/@brillout/vite-plugin-import-build/-/vite-plugin-import-build-0.2.20.tgz", - "integrity": "sha512-/bdw1dg+H1nOYSy2PzYInQoZlIFP2uwyaF2GX64fyBqVAEWGopiMlnx294CbysjmP9Z+fJe48TkMzyogkyIDLw==", - "dependencies": { - "@brillout/import": "^0.2.3" - } - }, - "node_modules/@cloudflare/kv-asset-handler": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.0.11.tgz", - "integrity": "sha512-D2kGr8NF2Er//Mx0c4+8FtOHuLrnwOlpC48TbtyxRSegG/Js15OKoqxxlG9BMUj3V/YSqtN8bUU6pjaRlsoSqg==", - "dependencies": { - "@cloudflare/workers-types": "^2.0.0", - "@types/mime": "^2.0.2", - "mime": "^2.4.6" - } - }, - "node_modules/@cloudflare/workers-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-2.0.0.tgz", - "integrity": "sha512-SFUPQzR5aV2TBLP4Re+xNX5KfAGArcRGA44OLulBDnfblEf3J+6kFvdJAQwFhFpqru3wImwT1cX0wahk6EeWTw==" - }, - "node_modules/@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", - "cpu": [ - "loong64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", - "cpu": [ - "mips64el" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@polka/url": { - "version": "1.0.0-next.23", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.23.tgz", - "integrity": "sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==" - }, - "node_modules/@types/babel__core": { - "version": "7.20.4", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.4.tgz", - "integrity": "sha512-mLnSC22IC4vcWiuObSRjrLd9XcBTGf59vUSoq2jkQDJ/QQ8PMI9rSuzE+aEV8karUMbskw07bKYoUJCKTUaygg==", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.7", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz", - "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.20.4", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", - "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", - "dependencies": { - "@babel/types": "^7.20.7" - } - }, - "node_modules/@types/mime": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.2.tgz", - "integrity": "sha512-4kPlzbljFcsttWEq6aBW0OZe6BDajAmyvr2xknBG92tejQnvdGtT9+kXSZ580DqpxY9qG2xeQVF9Dq0ymUTo5Q==" - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.1.1.tgz", - "integrity": "sha512-Jie2HERK+uh27e+ORXXwEP5h0Y2lS9T2PRGbfebiHGlwzDO0dEnd2aNtOR/qjBlPb1YgxwAONeblL1xqLikLag==", - "dependencies": { - "@babel/core": "^7.23.2", - "@babel/plugin-transform-react-jsx-self": "^7.22.5", - "@babel/plugin-transform-react-jsx-source": "^7.22.5", - "@types/babel__core": "^7.20.3", - "react-refresh": "^0.14.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0" - } - }, - "node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", - "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001541", - "electron-to-chromium": "^1.4.535", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.13" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001562", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001562.tgz", - "integrity": "sha512-kfte3Hym//51EdX4239i+Rmp20EsLIYGdPkERegTgU19hQWCRhsRFGKHTliUlsry53tv17K7n077Kqa0WJU4ng==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.584", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.584.tgz", - "integrity": "sha512-rXCtDiXCBtfTfEegkthruCvyWZnr1/FCrUGY/nYQiF+lSZDmwQBDxp0rivZxV8trXb6cbgojhcSTW5xsDcHQ8g==" - }, - "node_modules/es-module-lexer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", - "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==" - }, - "node_modules/esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "2.4.6", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", - "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mrmime": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", - "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - }, - "peerDependencies": { - "react": "^18.2.0" - } - }, - "node_modules/react-refresh": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", - "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rollup": { - "version": "3.29.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", - "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=14.18.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "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==", - "dependencies": { - "@polka/url": "^1.0.0-next.20", - "mrmime": "^1.0.0", - "totalist": "^3.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/totalist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", - "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/vike": { - "version": "0.4.146", - "resolved": "https://registry.npmjs.org/vike/-/vike-0.4.146.tgz", - "integrity": "sha512-1vaktcDy/eitSzVaUppKJWu+6vfwxKC4kV6uzAqj3RIK+WgteH3vF6IMZ0jnjjzCpeDRCIByN8PF4c0CtzRfHA==", - "dependencies": { - "@brillout/import": "0.2.3", - "@brillout/json-serializer": "^0.5.8", - "@brillout/picocolors": "^1.0.9", - "@brillout/require-shim": "^0.1.2", - "@brillout/vite-plugin-import-build": "^0.2.20", - "acorn": "^8.8.2", - "cac": "^6.7.14", - "es-module-lexer": "^1.3.0", - "esbuild": "^0.17.18", - "fast-glob": "^3.2.12", - "sirv": "^2.0.2", - "source-map-support": "^0.5.21" - }, - "bin": { - "vike": "node/cli/bin-entry.js" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "react-streaming": ">=0.3.5", - "vite": ">=3.1.0" - }, - "peerDependenciesMeta": { - "react-streaming": { - "optional": true - } - } - }, - "node_modules/vite": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", - "integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==", - "dependencies": { - "esbuild": "^0.18.10", - "postcss": "^8.4.27", - "rollup": "^3.27.1" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - }, - "peerDependencies": { - "@types/node": ">= 14", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", - "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", - "cpu": [ - "loong64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", - "cpu": [ - "mips64el" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", - "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", - "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/esbuild": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", - "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.18.20", - "@esbuild/android-arm64": "0.18.20", - "@esbuild/android-x64": "0.18.20", - "@esbuild/darwin-arm64": "0.18.20", - "@esbuild/darwin-x64": "0.18.20", - "@esbuild/freebsd-arm64": "0.18.20", - "@esbuild/freebsd-x64": "0.18.20", - "@esbuild/linux-arm": "0.18.20", - "@esbuild/linux-arm64": "0.18.20", - "@esbuild/linux-ia32": "0.18.20", - "@esbuild/linux-loong64": "0.18.20", - "@esbuild/linux-mips64el": "0.18.20", - "@esbuild/linux-ppc64": "0.18.20", - "@esbuild/linux-riscv64": "0.18.20", - "@esbuild/linux-s390x": "0.18.20", - "@esbuild/linux-x64": "0.18.20", - "@esbuild/netbsd-x64": "0.18.20", - "@esbuild/openbsd-x64": "0.18.20", - "@esbuild/sunos-x64": "0.18.20", - "@esbuild/win32-arm64": "0.18.20", - "@esbuild/win32-ia32": "0.18.20", - "@esbuild/win32-x64": "0.18.20" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - } - } -} diff --git a/packages/web/scripts/workers-site/package.json b/packages/web/scripts/workers-site/package.json deleted file mode 100644 index dd6f761e4cc..00000000000 --- a/packages/web/scripts/workers-site/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "private": true, - "name": "web-workers-site", - "version": "1.0.0", - "description": "A template for kick starting a Cloudflare Workers project", - "main": "index.js", - "author": "Ashley Lewis ", - "license": "MIT", - "dependencies": { - "@cloudflare/kv-asset-handler": "~0.0.11", - "@vitejs/plugin-react": "^4.1.1", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "vike": "^0.4.146", - "vite": "^4.5.0" - } -} diff --git a/packages/web/scripts/workers-site/ssr.js b/packages/web/scripts/workers-site/ssr.js index cc97776d4a2..1cf434c890a 100644 --- a/packages/web/scripts/workers-site/ssr.js +++ b/packages/web/scripts/workers-site/ssr.js @@ -6,12 +6,11 @@ export async function handleSsr(url) { } const pageContext = await renderPage(pageContextInit) - return new Response('hi') - // const { httpResponse } = pageContext - // if (!httpResponse) { - // return null - // } else { - // const { body, statusCode: status, headers } = httpResponse - // return new Response(body, { headers, status }) - // } + const { httpResponse } = pageContext + if (!httpResponse) { + return null + } else { + const { body, statusCode: status, headers } = httpResponse + return new Response(body, { headers, status }) + } } diff --git a/packages/web/wrangler.toml b/packages/web/wrangler.toml index ba34ff8ffba..190c271c2ee 100644 --- a/packages/web/wrangler.toml +++ b/packages/web/wrangler.toml @@ -1,4 +1,4 @@ -type = "webpack" +compatibility_date = "2023-10-25" account_id = "3811365464a8e56b2b27a5590e328e49" workers_dev = true main = "./scripts/workers-site/index.js" From 528ac4cad5e5d51a36d32f53d2988265b365a642 Mon Sep 17 00:00:00 2001 From: sliptype Date: Thu, 16 Nov 2023 12:15:15 -0600 Subject: [PATCH 03/74] Bypass SSR by default --- .../src/services/audius-backend/solana.ts | 3 +- packages/web/index.html | 50 ++++++++------ packages/web/pages/index.page.route.ts | 3 + packages/web/pages/index.page.tsx | 16 ----- packages/web/renderer/PageLayout.tsx | 68 ------------------- .../web/renderer/_default.page.client.tsx | 29 ++++---- .../web/renderer/_default.page.server.tsx | 37 +++++----- 7 files changed, 68 insertions(+), 138 deletions(-) create mode 100644 packages/web/pages/index.page.route.ts delete mode 100644 packages/web/renderer/PageLayout.tsx diff --git a/packages/common/src/services/audius-backend/solana.ts b/packages/common/src/services/audius-backend/solana.ts index 9af36bcac76..3fb2e8e95b7 100644 --- a/packages/common/src/services/audius-backend/solana.ts +++ b/packages/common/src/services/audius-backend/solana.ts @@ -21,8 +21,6 @@ import { AudiusBackend } from './AudiusBackend' const DEFAULT_RETRY_DELAY = 1000 const DEFAULT_MAX_RETRY_COUNT = 120 -const PLACEHOLDER_SIGNATURE = Buffer.from(new Array(64).fill(0)) - /** * Memo program V1 * https://github.com/solana-labs/solana-program-library/blob/7492e38b8577eef4defb5d02caadf82162887c68/memo/program/src/lib.rs#L16-L21 @@ -477,6 +475,7 @@ export const relayVersionedTransaction = async ( skipPreflight?: boolean } ) => { + const PLACEHOLDER_SIGNATURE = Buffer.from(new Array(64).fill(0)) const libs = await audiusBackendInstance.getAudiusLibsTyped() const decompiledMessage = TransactionMessage.decompile(transaction.message, { addressLookupTableAccounts diff --git a/packages/web/index.html b/packages/web/index.html index b4782c0b9eb..b20b26e5470 100644 --- a/packages/web/index.html +++ b/packages/web/index.html @@ -54,13 +54,6 @@ - - @@ -195,8 +203,12 @@ - diff --git a/packages/web/pages/index.page.route.ts b/packages/web/pages/index.page.route.ts new file mode 100644 index 00000000000..2d1b6370b4c --- /dev/null +++ b/packages/web/pages/index.page.route.ts @@ -0,0 +1,3 @@ +// All routes exported here will skip SSR + +export default '/*' diff --git a/packages/web/pages/index.page.tsx b/packages/web/pages/index.page.tsx index 8efd19ca405..e69de29bb2d 100644 --- a/packages/web/pages/index.page.tsx +++ b/packages/web/pages/index.page.tsx @@ -1,16 +0,0 @@ -import React from 'react' - -export { Page } - -function Page() { - return ( - <> -

Welcome

- This page is: -
    -
  • Rendered to HTML.
  • -
  • Interactive.
  • -
- - ) -} diff --git a/packages/web/renderer/PageLayout.tsx b/packages/web/renderer/PageLayout.tsx deleted file mode 100644 index 25e48daf283..00000000000 --- a/packages/web/renderer/PageLayout.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import React from 'react' - -export { PageLayout } - -function PageLayout({ children }) { - return ( - - - - - Home - - - About - - - {children} - - - ) -} - -function Layout({ children }) { - return ( -
- {children} -
- ) -} - -function Sidebar({ children }) { - return ( -
- {children} -
- ) -} - -function Content({ children }) { - return ( -
- {children} -
- ) -} diff --git a/packages/web/renderer/_default.page.client.tsx b/packages/web/renderer/_default.page.client.tsx index 7a52bd15247..c897f6742ec 100644 --- a/packages/web/renderer/_default.page.client.tsx +++ b/packages/web/renderer/_default.page.client.tsx @@ -1,17 +1,22 @@ -import React from 'react' +// By default, simply render the SPA without SSR -import { hydrateRoot } from 'react-dom/client' +import 'setimmediate' +import { Buffer } from 'buffer' -import { PageLayout } from './PageLayout' +import processBrowser from 'process/browser' +import { createRoot } from 'react-dom/client' -export { render } +import '../src/index.css' -async function render(pageContext) { - const { Page, pageProps } = pageContext - hydrateRoot( - document.getElementById('page-view'), - - - - ) +window.global ||= window +window.Buffer = Buffer +window.process = { ...processBrowser, env: process.env } + +export async function render() { + const container = document.getElementById('root') + const Root = await import('../src/root') + if (container) { + const root = createRoot(container) + root.render() + } } diff --git a/packages/web/renderer/_default.page.server.tsx b/packages/web/renderer/_default.page.server.tsx index 4298b10c79b..4e3a411c144 100644 --- a/packages/web/renderer/_default.page.server.tsx +++ b/packages/web/renderer/_default.page.server.tsx @@ -1,28 +1,23 @@ -import React from 'react' +// By default, don't do any server side rendering +// Just serve the static HTML -import ReactDOMServer from 'react-dom/server' import { escapeInject, dangerouslySkipEscape } from 'vike/server' -import { PageLayout } from './PageLayout' +import indexHtml from '../index.html?raw' -export { render } -export { passToClient } +export function render() { + const pattern = /%(\S+?)%/g + const env = process.env -// See https://vike.dev/data-fetching -const passToClient = ['pageProps'] + // Replace all %VITE_*% with the corresponding environment variable + const html = indexHtml.replace(pattern, (text, key) => { + if (key in env) { + return env[key] + } else { + // TODO: throw warning + return text + } + }) -function render(pageContext) { - const { Page, pageProps } = pageContext - const pageHtml = ReactDOMServer.renderToString( - - - - ) - - return escapeInject` - - -
${dangerouslySkipEscape(pageHtml)}
- - ` + return escapeInject`${dangerouslySkipEscape(html)}` } From 1dc02277fc515c1ced12ecccc7dc25bd8d51fea9 Mon Sep 17 00:00:00 2001 From: sliptype Date: Thu, 16 Nov 2023 15:19:48 -0600 Subject: [PATCH 04/74] Get rendering working on worker --- packages/web/index.html | 1 - packages/web/renderer/_default.page.client.tsx | 2 +- packages/web/scripts/workers-site/index.js | 4 +++- packages/web/wrangler.toml | 3 ++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/web/index.html b/packages/web/index.html index b20b26e5470..54052012a74 100644 --- a/packages/web/index.html +++ b/packages/web/index.html @@ -199,7 +199,6 @@
- diff --git a/packages/web/renderer/_default.page.client.tsx b/packages/web/renderer/_default.page.client.tsx index c897f6742ec..df23b3c42b6 100644 --- a/packages/web/renderer/_default.page.client.tsx +++ b/packages/web/renderer/_default.page.client.tsx @@ -5,6 +5,7 @@ import { Buffer } from 'buffer' import processBrowser from 'process/browser' import { createRoot } from 'react-dom/client' +import Root from '../src/root' import '../src/index.css' @@ -14,7 +15,6 @@ window.process = { ...processBrowser, env: process.env } export async function render() { const container = document.getElementById('root') - const Root = await import('../src/root') if (container) { const root = createRoot(container) root.render() diff --git a/packages/web/scripts/workers-site/index.js b/packages/web/scripts/workers-site/index.js index 350dc007dcd..de0adee8212 100644 --- a/packages/web/scripts/workers-site/index.js +++ b/packages/web/scripts/workers-site/index.js @@ -311,6 +311,8 @@ function isAssetUrl(url) { return ( pathname.startsWith('/assets') || pathname.startsWith('/scripts') || - pathname.startsWith('/fonts') + pathname.startsWith('/fonts') || + pathname.startsWith('/favicons') || + pathname.startsWith('/manifest.json') ) } diff --git a/packages/web/wrangler.toml b/packages/web/wrangler.toml index 190c271c2ee..33d6c106298 100644 --- a/packages/web/wrangler.toml +++ b/packages/web/wrangler.toml @@ -2,9 +2,10 @@ compatibility_date = "2023-10-25" account_id = "3811365464a8e56b2b27a5590e328e49" workers_dev = true main = "./scripts/workers-site/index.js" +node_compat = true [site] -bucket = "./build" +bucket = "./build/client" [env.staging] name = "audius-staging" From f09b03d301b763e9a874a9cce18444d043154cfc Mon Sep 17 00:00:00 2001 From: sliptype Date: Thu, 16 Nov 2023 15:56:31 -0600 Subject: [PATCH 05/74] Resolve a unique page for profile --- packages/web/ssr/PageLayout.tsx | 12 ++++++++++ packages/web/ssr/_default.page.client.tsx | 19 ++++++++++++++++ packages/web/ssr/_default.page.server.tsx | 27 +++++++++++++++++++++++ packages/web/ssr/profile.page.route.tsx | 11 +++++++++ packages/web/ssr/profile.page.server.tsx | 0 5 files changed, 69 insertions(+) create mode 100644 packages/web/ssr/PageLayout.tsx create mode 100644 packages/web/ssr/_default.page.client.tsx create mode 100644 packages/web/ssr/_default.page.server.tsx create mode 100644 packages/web/ssr/profile.page.route.tsx create mode 100644 packages/web/ssr/profile.page.server.tsx diff --git a/packages/web/ssr/PageLayout.tsx b/packages/web/ssr/PageLayout.tsx new file mode 100644 index 00000000000..3f049880f16 --- /dev/null +++ b/packages/web/ssr/PageLayout.tsx @@ -0,0 +1,12 @@ +import React from 'react' + +// import Navigator from 'components/nav/Navigator' +// import Notice from 'components/notice/Notice' + +export function PageLayout({ children }) { + return ( + +
hi
+
+ ) +} diff --git a/packages/web/ssr/_default.page.client.tsx b/packages/web/ssr/_default.page.client.tsx new file mode 100644 index 00000000000..c05d9144be0 --- /dev/null +++ b/packages/web/ssr/_default.page.client.tsx @@ -0,0 +1,19 @@ +// This should hydrate index.html + +import React from 'react' + +import { hydrateRoot } from 'react-dom/client' + +import { PageLayout } from './PageLayout' + +export { render } + +async function render(pageContext) { + const { Page, pageProps } = pageContext + hydrateRoot( + document.getElementById('page-view'), + + + + ) +} diff --git a/packages/web/ssr/_default.page.server.tsx b/packages/web/ssr/_default.page.server.tsx new file mode 100644 index 00000000000..db58769d729 --- /dev/null +++ b/packages/web/ssr/_default.page.server.tsx @@ -0,0 +1,27 @@ +// This should do nothing, just serve the page as-is + +import React from 'react' + +import ReactDOMServer from 'react-dom/server' +import { escapeInject, dangerouslySkipEscape } from 'vike/server' + +import { PageLayout } from './PageLayout' + +// See https://vike.dev/data-fetching +export const passToClient = ['pageProps'] + +export function render(pageContext) { + const { Page, pageProps } = pageContext + const pageHtml = ReactDOMServer.renderToString( + + + + ) + + return escapeInject` + + +
${dangerouslySkipEscape(pageHtml)}
+ + ` +} diff --git a/packages/web/ssr/profile.page.route.tsx b/packages/web/ssr/profile.page.route.tsx new file mode 100644 index 00000000000..0de3dca2ba0 --- /dev/null +++ b/packages/web/ssr/profile.page.route.tsx @@ -0,0 +1,11 @@ +import { resolveRoute } from 'vike/routing' +import { staticRoutes } from 'utils/route' + +export default (pageContext) => { + // Don't render profile page if the route matches any of the static routes + if (staticRoutes.has(pageContext.urlPathname)) { + return false + } + + return resolveRoute('/@handle', pageContext.urlPathname) +} diff --git a/packages/web/ssr/profile.page.server.tsx b/packages/web/ssr/profile.page.server.tsx new file mode 100644 index 00000000000..e69de29bb2d From 803d00e16695ac23112733ce2eba209a7d6a531d Mon Sep 17 00:00:00 2001 From: sliptype Date: Thu, 16 Nov 2023 17:41:48 -0600 Subject: [PATCH 06/74] Begin laying out ssr page --- .../web/renderer/_default.page.client.tsx | 2 +- packages/web/src/app/web-player/WebPlayer.jsx | 2 +- .../{App.module.css => WebPlayer.module.css} | 0 packages/web/ssr/PageLayout.tsx | 21 ++++++++++++++++--- packages/web/ssr/_default.page.client.tsx | 7 +++---- packages/web/ssr/_default.page.server.tsx | 3 ++- packages/web/ssr/profile.page.server.tsx | 0 7 files changed, 25 insertions(+), 10 deletions(-) rename packages/web/src/app/web-player/{App.module.css => WebPlayer.module.css} (100%) delete mode 100644 packages/web/ssr/profile.page.server.tsx diff --git a/packages/web/renderer/_default.page.client.tsx b/packages/web/renderer/_default.page.client.tsx index df23b3c42b6..734e56000b7 100644 --- a/packages/web/renderer/_default.page.client.tsx +++ b/packages/web/renderer/_default.page.client.tsx @@ -5,7 +5,7 @@ import { Buffer } from 'buffer' import processBrowser from 'process/browser' import { createRoot } from 'react-dom/client' -import Root from '../src/root' +import { Root } from '../src/Root' import '../src/index.css' diff --git a/packages/web/src/app/web-player/WebPlayer.jsx b/packages/web/src/app/web-player/WebPlayer.jsx index 66ea19a12ae..d9ba22cab43 100644 --- a/packages/web/src/app/web-player/WebPlayer.jsx +++ b/packages/web/src/app/web-player/WebPlayer.jsx @@ -182,7 +182,7 @@ import { } from 'utils/route' import { getTheme as getSystemTheme } from 'utils/theme/theme' -import styles from './App.module.css' +import styles from './WebPlayer.module.css' const { setTheme } = themeActions const { getTheme } = themeSelectors diff --git a/packages/web/src/app/web-player/App.module.css b/packages/web/src/app/web-player/WebPlayer.module.css similarity index 100% rename from packages/web/src/app/web-player/App.module.css rename to packages/web/src/app/web-player/WebPlayer.module.css diff --git a/packages/web/ssr/PageLayout.tsx b/packages/web/ssr/PageLayout.tsx index 3f049880f16..355d2e576d6 100644 --- a/packages/web/ssr/PageLayout.tsx +++ b/packages/web/ssr/PageLayout.tsx @@ -1,12 +1,27 @@ import React from 'react' -// import Navigator from 'components/nav/Navigator' -// import Notice from 'components/notice/Notice' +import '../src/index.css' + +import styles from '../src/app/web-player/WebPlayer.module.css' +import navStyles from '../src/components/nav/desktop/LeftNav.module.css' +import cn from 'classnames' + +// TODO: CSS vars aren't defined +// TODO: mobile export function PageLayout({ children }) { return ( -
hi
+
+
+
+
+
+ {children} +
+
) } diff --git a/packages/web/ssr/_default.page.client.tsx b/packages/web/ssr/_default.page.client.tsx index c05d9144be0..84ea9317ae8 100644 --- a/packages/web/ssr/_default.page.client.tsx +++ b/packages/web/ssr/_default.page.client.tsx @@ -6,14 +6,13 @@ import { hydrateRoot } from 'react-dom/client' import { PageLayout } from './PageLayout' -export { render } - -async function render(pageContext) { +export async function render(pageContext) { const { Page, pageProps } = pageContext hydrateRoot( document.getElementById('page-view'), - + hi + {/* */} ) } diff --git a/packages/web/ssr/_default.page.server.tsx b/packages/web/ssr/_default.page.server.tsx index db58769d729..38d7903b9e9 100644 --- a/packages/web/ssr/_default.page.server.tsx +++ b/packages/web/ssr/_default.page.server.tsx @@ -14,7 +14,8 @@ export function render(pageContext) { const { Page, pageProps } = pageContext const pageHtml = ReactDOMServer.renderToString( - + hi + {/* */} ) diff --git a/packages/web/ssr/profile.page.server.tsx b/packages/web/ssr/profile.page.server.tsx deleted file mode 100644 index e69de29bb2d..00000000000 From b74d3d0dfb3f2a7f9cbdece43c334b2f574a2d1c Mon Sep 17 00:00:00 2001 From: sliptype Date: Mon, 20 Nov 2023 17:15:37 -0600 Subject: [PATCH 07/74] Fetch track serverside --- packages/web/src/ssr/WebPlayerSkeleton.tsx | 43 +++++++ packages/web/src/ssr/_default.page.client.tsx | 19 +++ .../{ => src}/ssr/_default.page.server.tsx | 21 ++-- .../web/{ => src}/ssr/profile.page.route.tsx | 1 + packages/web/src/ssr/track.page.route.tsx | 9 ++ packages/web/src/ssr/track.page.server.tsx | 27 +++++ packages/web/src/ssr/track.page.tsx | 114 ++++++++++++++++++ packages/web/ssr/PageLayout.tsx | 27 ----- packages/web/ssr/_default.page.client.tsx | 18 --- 9 files changed, 223 insertions(+), 56 deletions(-) create mode 100644 packages/web/src/ssr/WebPlayerSkeleton.tsx create mode 100644 packages/web/src/ssr/_default.page.client.tsx rename packages/web/{ => src}/ssr/_default.page.server.tsx (54%) rename packages/web/{ => src}/ssr/profile.page.route.tsx (99%) create mode 100644 packages/web/src/ssr/track.page.route.tsx create mode 100644 packages/web/src/ssr/track.page.server.tsx create mode 100644 packages/web/src/ssr/track.page.tsx delete mode 100644 packages/web/ssr/PageLayout.tsx delete mode 100644 packages/web/ssr/_default.page.client.tsx diff --git a/packages/web/src/ssr/WebPlayerSkeleton.tsx b/packages/web/src/ssr/WebPlayerSkeleton.tsx new file mode 100644 index 00000000000..89d16b81304 --- /dev/null +++ b/packages/web/src/ssr/WebPlayerSkeleton.tsx @@ -0,0 +1,43 @@ +import React from 'react' + +import '../index.css' + +import cn from 'classnames' + +import AudiusLogoHorizontal from 'assets/img/audiusLogoHorizontal.svg' +import navStyles from 'components/nav/Navigator.module.css' +import leftNavStyles from 'components/nav/desktop/LeftNav.module.css' +import navHeaderStyles from 'components/nav/desktop/NavHeader.module.css' +import { HOME_PAGE } from 'utils/route' + +import styles from '../app/web-player/WebPlayer.module.css' + +const messages = { + homeLink: 'Go to Home' +} + +// TODO: mobile +// TODO: convert to emotion +export function WebPlayerSkeleton({ children }) { + return ( + +
+
+
+ +
+
+ {children} +
+ {/* playbar */} +
+
+
+ ) +} diff --git a/packages/web/src/ssr/_default.page.client.tsx b/packages/web/src/ssr/_default.page.client.tsx new file mode 100644 index 00000000000..8265a39bc4e --- /dev/null +++ b/packages/web/src/ssr/_default.page.client.tsx @@ -0,0 +1,19 @@ +import { Track } from '@audius/sdk' +import { hydrateRoot } from 'react-dom/client' +import { PageContextClient } from 'vike/types' + +import { WebPlayerSkeleton } from './WebPlayerSkeleton' + +// TODO: test hydrate vs render +// TODO: can render skeleton on client and hydrate, then render full app +export async function render( + pageContext: PageContextClient & { pageProps: { track: Track } } +) { + const { Page, pageProps } = pageContext + hydrateRoot( + document.getElementById('page-view'), + + + + ) +} diff --git a/packages/web/ssr/_default.page.server.tsx b/packages/web/src/ssr/_default.page.server.tsx similarity index 54% rename from packages/web/ssr/_default.page.server.tsx rename to packages/web/src/ssr/_default.page.server.tsx index 38d7903b9e9..8ab257eb3cf 100644 --- a/packages/web/ssr/_default.page.server.tsx +++ b/packages/web/src/ssr/_default.page.server.tsx @@ -1,24 +1,23 @@ -// This should do nothing, just serve the page as-is - -import React from 'react' - +import { Track } from '@audius/sdk' import ReactDOMServer from 'react-dom/server' import { escapeInject, dangerouslySkipEscape } from 'vike/server' +import { PageContextServer } from 'vike/types' -import { PageLayout } from './PageLayout' +import { WebPlayerSkeleton } from './WebPlayerSkeleton' -// See https://vike.dev/data-fetching export const passToClient = ['pageProps'] -export function render(pageContext) { +export function render( + pageContext: PageContextServer & { pageProps: { track: Track } } +) { const { Page, pageProps } = pageContext const pageHtml = ReactDOMServer.renderToString( - - hi - {/* */} - + + + ) + // TODO: this needs to be index.html return escapeInject` diff --git a/packages/web/ssr/profile.page.route.tsx b/packages/web/src/ssr/profile.page.route.tsx similarity index 99% rename from packages/web/ssr/profile.page.route.tsx rename to packages/web/src/ssr/profile.page.route.tsx index 0de3dca2ba0..f64746c69dc 100644 --- a/packages/web/ssr/profile.page.route.tsx +++ b/packages/web/src/ssr/profile.page.route.tsx @@ -1,4 +1,5 @@ import { resolveRoute } from 'vike/routing' + import { staticRoutes } from 'utils/route' export default (pageContext) => { diff --git a/packages/web/src/ssr/track.page.route.tsx b/packages/web/src/ssr/track.page.route.tsx new file mode 100644 index 00000000000..0526c9c86f6 --- /dev/null +++ b/packages/web/src/ssr/track.page.route.tsx @@ -0,0 +1,9 @@ +import { resolveRoute } from 'vike/routing' +import { PageContextServer } from 'vike/types' + +export default (pageContext: PageContextServer) => { + if (pageContext.urlPathname.match(/index\.css\.map$/)) { + return false + } + return resolveRoute('/@handle/@slug', pageContext.urlPathname) +} diff --git a/packages/web/src/ssr/track.page.server.tsx b/packages/web/src/ssr/track.page.server.tsx new file mode 100644 index 00000000000..de37542b277 --- /dev/null +++ b/packages/web/src/ssr/track.page.server.tsx @@ -0,0 +1,27 @@ +import type { Maybe } from '@audius/common' +import { Track, sdk } from '@audius/sdk' +import { PageContextServer } from 'vike/types' + +const audiusSdk = sdk({ + appName: 'audius.co' +}) + +export type TrackPageProps = { + track: Maybe +} + +export async function onBeforeRender(pageContext: PageContextServer) { + const { handle, slug } = pageContext.routeParams + + const { data: tracks } = await audiusSdk.full.tracks.getBulkTracks({ + permalink: [`${handle}/${slug}`] + }) + + const pageProps = { track: tracks?.[0] } + + return { + pageContext: { + pageProps + } + } +} diff --git a/packages/web/src/ssr/track.page.tsx b/packages/web/src/ssr/track.page.tsx new file mode 100644 index 00000000000..1832d86a309 --- /dev/null +++ b/packages/web/src/ssr/track.page.tsx @@ -0,0 +1,114 @@ +import React from 'react' + +import { GiantTrackTile } from 'components/track/GiantTrackTile' + +import { TrackPageProps } from './track.page.server' + +export function Page(props: TrackPageProps) { + const { track } = props + + console.log(props) + return
hi
+ // return + + // return + //
+ // + //
+ //
+ // {renderCardTitle(cn(fadeIn))} + //
+ //

{trackTitle}

+ // {isLoading && } + //
+ //
+ //
+ // By + // + //
+ // {isLoading && ( + // + // )} + //
+ //
+ + //
+ // {showPlay ? ( + // + // ) : null} + // {showPreview ? ( + // + // ) : null} + // {isLongFormContent && isNewPodcastControlsEnabled ? ( + // + // ) : ( + // renderListenCount() + // )} + //
+ + //
+ // {renderStatsRow()} + //
+ + //
+ // {renderShareButton()} + // {renderMakePublicButton()} + // {doesUserHaveAccess && renderRepostButton()} + // {doesUserHaveAccess && renderFavoriteButton()} + // + // {/* prop types for overflow menu don't work correctly + // so we need to cast here */} + // + // {(ref, triggerPopup) => ( + //
+ //
+ // )} + //
+ //
+ //
+ //
+ // +} diff --git a/packages/web/ssr/PageLayout.tsx b/packages/web/ssr/PageLayout.tsx deleted file mode 100644 index 355d2e576d6..00000000000 --- a/packages/web/ssr/PageLayout.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react' - -import '../src/index.css' - -import styles from '../src/app/web-player/WebPlayer.module.css' -import navStyles from '../src/components/nav/desktop/LeftNav.module.css' -import cn from 'classnames' - -// TODO: CSS vars aren't defined -// TODO: mobile - -export function PageLayout({ children }) { - return ( - -
-
-
-
-
- {children} -
-
-
- ) -} diff --git a/packages/web/ssr/_default.page.client.tsx b/packages/web/ssr/_default.page.client.tsx deleted file mode 100644 index 84ea9317ae8..00000000000 --- a/packages/web/ssr/_default.page.client.tsx +++ /dev/null @@ -1,18 +0,0 @@ -// This should hydrate index.html - -import React from 'react' - -import { hydrateRoot } from 'react-dom/client' - -import { PageLayout } from './PageLayout' - -export async function render(pageContext) { - const { Page, pageProps } = pageContext - hydrateRoot( - document.getElementById('page-view'), - - hi - {/* */} - - ) -} From 9c92c7b967c5251c5d4b99deb42594ebdb7c8dd0 Mon Sep 17 00:00:00 2001 From: sliptype Date: Tue, 21 Nov 2023 15:08:28 -0600 Subject: [PATCH 08/74] Get basic track page rendering serverside --- packages/common/src/store/pages/chat/sagas.ts | 2 +- .../src/store/pages/trending/reducer.ts | 6 +- .../components/Modal/ModalContentPages.tsx | 2 +- packages/stems/src/hooks/useGlobal.ts | 6 +- packages/web/src/app/App.tsx | 8 + .../web/src/app/web-player/WebPlayer.test.tsx | 2 +- .../change-password/ConfirmCredentials.tsx | 2 +- .../src/components/client-only/ClientOnly.tsx | 18 ++ .../src/components/lineup/LineupProvider.tsx | 2 +- packages/web/src/components/page/Page.jsx | 2 +- .../web/src/components/search/SearchBar.jsx | 2 +- .../tipping/tip-audio/ConfirmSendTip.tsx | 2 +- .../tipping/tip-audio/TipAudioModal.tsx | 2 +- .../web/src/components/track/CardTitle.tsx | 2 +- .../src/components/track/GiantTrackTile.tsx | 105 ++++--- .../TransitionContainer.tsx | 2 +- .../src/components/upload/InvalidFileType.jsx | 2 +- .../components/CompleteProfileWithSocial.tsx | 2 +- .../pages/sign-on/components/ProfileForm.tsx | 2 +- .../sign-on/components/desktop/EmailPage.tsx | 2 +- .../sign-on/components/desktop/SignInPage.tsx | 2 +- .../sign-on/components/desktop/SignOnPage.tsx | 2 +- .../sign-on/components/mobile/InitialPage.tsx | 2 +- .../sign-on/components/mobile/SignOnPage.tsx | 2 +- packages/web/src/services/WebWorker.js | 5 +- .../audius-sdk/discoveryNodeSelector.ts | 5 +- packages/web/src/services/local-storage.ts | 2 +- .../remote-config/featureFlagHelpers.ts | 3 +- .../remote-config/remote-config-instance.ts | 2 - packages/web/src/ssr/SsrRoot.tsx | 13 + packages/web/src/ssr/_default.page.client.tsx | 9 +- packages/web/src/ssr/_default.page.server.tsx | 9 +- packages/web/src/ssr/track.page.server.tsx | 4 +- packages/web/src/ssr/track.page.tsx | 274 +++++++++++------- packages/web/src/utils/clientUtil.ts | 6 + packages/web/src/utils/safeArea.ts | 1 + 36 files changed, 328 insertions(+), 186 deletions(-) create mode 100644 packages/web/src/components/client-only/ClientOnly.tsx create mode 100644 packages/web/src/ssr/SsrRoot.tsx diff --git a/packages/common/src/store/pages/chat/sagas.ts b/packages/common/src/store/pages/chat/sagas.ts index e4a44993dbf..ede348108ab 100644 --- a/packages/common/src/store/pages/chat/sagas.ts +++ b/packages/common/src/store/pages/chat/sagas.ts @@ -32,7 +32,7 @@ import { makeChatId } from './utils' // Attach ulid to window object for debugging DMs // @ts-ignore -window.ulid = ulid +// window.ulid = ulid const { createChat, diff --git a/packages/common/src/store/pages/trending/reducer.ts b/packages/common/src/store/pages/trending/reducer.ts index eb28b54ffd9..fa09cda3fa8 100644 --- a/packages/common/src/store/pages/trending/reducer.ts +++ b/packages/common/src/store/pages/trending/reducer.ts @@ -22,9 +22,9 @@ import { makeInitialState } from './lineup/reducer' -const urlParams = new URLSearchParams(window.location.search) -const genre = urlParams.get('genre') -const timeRange = urlParams.get('timeRange') +// const urlParams = new URLSearchParams(window.location.search) +const genre = '' +const timeRange = '' const initialState = { trendingTimeRange: Object.values(TimeRange).includes(timeRange) diff --git a/packages/stems/src/components/Modal/ModalContentPages.tsx b/packages/stems/src/components/Modal/ModalContentPages.tsx index 5404d99681d..989be9e3890 100644 --- a/packages/stems/src/components/Modal/ModalContentPages.tsx +++ b/packages/stems/src/components/Modal/ModalContentPages.tsx @@ -3,7 +3,7 @@ import { Children, ReactChild, useState } from 'react' import { ResizeObserver } from '@juggle/resize-observer' import cn from 'classnames' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web -import { animated, Transition } from 'react-spring/renderprops' +import { animated, Transition } from 'react-spring/renderprops.cjs' import useMeasure from 'react-use-measure' import { ModalContent } from './ModalContent' diff --git a/packages/stems/src/hooks/useGlobal.ts b/packages/stems/src/hooks/useGlobal.ts index 95c5949b718..75e9b478bdd 100644 --- a/packages/stems/src/hooks/useGlobal.ts +++ b/packages/stems/src/hooks/useGlobal.ts @@ -6,8 +6,6 @@ declare global { } } -window.AudiusStems = window.AudiusStems || {} - /** * Hook to "share state" between components using the global window object. * Obviously, comes with caveats with globals. @@ -23,6 +21,10 @@ export const useGlobal = ( name: string, initialValue: T ): [() => T, (mutator: (cur: T) => void) => void] => { + if (window.AudiusStems === undefined) { + window.AudiusStems = window.AudiusStems || {} + } + useEffect(() => { if (window.AudiusStems[name] === undefined) { window.AudiusStems[name] = initialValue diff --git a/packages/web/src/app/App.tsx b/packages/web/src/app/App.tsx index 2e0782c0d74..4f4c006d478 100644 --- a/packages/web/src/app/App.tsx +++ b/packages/web/src/app/App.tsx @@ -1,5 +1,7 @@ // @refresh reset +import { useEffect } from 'react' + import { Route, Switch } from 'react-router-dom' import { CoinbasePayButtonProvider } from 'components/coinbase-pay-button' @@ -9,11 +11,17 @@ import { SomethingWrong } from 'pages/something-wrong/SomethingWrong' import '../services/webVitals' +import { remoteConfigInstance } from 'services/remote-config/remote-config-instance' + import { AppErrorBoundary } from './AppErrorBoundary' import { AppProviders } from './AppProviders' import WebPlayer from './web-player/WebPlayer' export const App = () => { + useEffect(() => { + remoteConfigInstance.init() + }, []) + return ( diff --git a/packages/web/src/app/web-player/WebPlayer.test.tsx b/packages/web/src/app/web-player/WebPlayer.test.tsx index 2a3e82baecf..b4096f41491 100644 --- a/packages/web/src/app/web-player/WebPlayer.test.tsx +++ b/packages/web/src/app/web-player/WebPlayer.test.tsx @@ -10,7 +10,7 @@ import WebPlayer from './WebPlayer' vitest.mock('jimp/es', () => null) vitest.mock('./visualizer/Visualizer', () => () => null) -vitest.mock('react-spring/renderprops', () => ({ +vitest.mock('react-spring/renderprops.cjs', () => ({ Spring: () => null, Transition: () => null })) diff --git a/packages/web/src/components/change-password/ConfirmCredentials.tsx b/packages/web/src/components/change-password/ConfirmCredentials.tsx index ffb801e94d7..057d47bfaeb 100644 --- a/packages/web/src/components/change-password/ConfirmCredentials.tsx +++ b/packages/web/src/components/change-password/ConfirmCredentials.tsx @@ -9,7 +9,7 @@ import { Button, ButtonType, IconArrow } from '@audius/stems' import cn from 'classnames' import { useDispatch } from 'react-redux' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web -import { Spring } from 'react-spring/renderprops' +import { Spring } from 'react-spring/renderprops.cjs' import Input from 'components/data-entry/Input' import LoadingSpinner from 'components/loading-spinner/LoadingSpinner' diff --git a/packages/web/src/components/client-only/ClientOnly.tsx b/packages/web/src/components/client-only/ClientOnly.tsx new file mode 100644 index 00000000000..cd3f3c1d993 --- /dev/null +++ b/packages/web/src/components/client-only/ClientOnly.tsx @@ -0,0 +1,18 @@ +import { ReactNode, Suspense, useEffect, useState } from 'react' + +type ClientOnlyProps = { + children: ReactNode + fallback?: ReactNode +} + +export const ClientOnly = (props: ClientOnlyProps) => { + const { children, fallback } = props + + const [clientChildren, setClientChildren] = useState(fallback) + + useEffect(() => { + setClientChildren(children) + }, []) + + return {clientChildren} +} diff --git a/packages/web/src/components/lineup/LineupProvider.tsx b/packages/web/src/components/lineup/LineupProvider.tsx index a5d5f05744b..a6223b1368a 100644 --- a/packages/web/src/components/lineup/LineupProvider.tsx +++ b/packages/web/src/components/lineup/LineupProvider.tsx @@ -16,7 +16,7 @@ import { push as pushRoute } from 'connected-react-router' import InfiniteScroll from 'react-infinite-scroller' import { connect } from 'react-redux' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web -import { Transition } from 'react-spring/renderprops' +import { Transition } from 'react-spring/renderprops.cjs' import { Dispatch } from 'redux' import { TrackEvent, make } from 'common/store/analytics/actions' diff --git a/packages/web/src/components/page/Page.jsx b/packages/web/src/components/page/Page.jsx index 91e021f9d7d..b55612d3f9f 100644 --- a/packages/web/src/components/page/Page.jsx +++ b/packages/web/src/components/page/Page.jsx @@ -4,7 +4,7 @@ import cn from 'classnames' import PropTypes from 'prop-types' import { Helmet } from 'react-helmet' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web -import { Spring } from 'react-spring/renderprops' +import { Spring } from 'react-spring/renderprops.cjs' import calcScrollbarWidth from 'scrollbar-width' import SearchBar from 'components/search-bar/ConnectedSearchBar' diff --git a/packages/web/src/components/search/SearchBar.jsx b/packages/web/src/components/search/SearchBar.jsx index c4bb355d279..5735b022dfa 100644 --- a/packages/web/src/components/search/SearchBar.jsx +++ b/packages/web/src/components/search/SearchBar.jsx @@ -8,7 +8,7 @@ import { isEqual } from 'lodash' import PropTypes from 'prop-types' import Lottie from 'react-lottie' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web -import { Transition } from 'react-spring/renderprops' +import { Transition } from 'react-spring/renderprops.cjs' import loadingSpinner from 'assets/animations/loadingSpinner.json' import IconArrow from 'assets/img/iconArrowGrey.svg' diff --git a/packages/web/src/components/tipping/tip-audio/ConfirmSendTip.tsx b/packages/web/src/components/tipping/tip-audio/ConfirmSendTip.tsx index 62fdd6feafe..dac7463e94b 100644 --- a/packages/web/src/components/tipping/tip-audio/ConfirmSendTip.tsx +++ b/packages/web/src/components/tipping/tip-audio/ConfirmSendTip.tsx @@ -5,7 +5,7 @@ import { Button, ButtonType, IconCheck } from '@audius/stems' import cn from 'classnames' import { useDispatch, useSelector } from 'react-redux' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web -import { Transition, animated } from 'react-spring/renderprops' +import { Transition, animated } from 'react-spring/renderprops.cjs' import IconCaretLeft from 'assets/img/iconCaretLeft.svg' import IconSend from 'assets/img/iconSend.svg' diff --git a/packages/web/src/components/tipping/tip-audio/TipAudioModal.tsx b/packages/web/src/components/tipping/tip-audio/TipAudioModal.tsx index 208d8abffef..755fe2aeb2e 100644 --- a/packages/web/src/components/tipping/tip-audio/TipAudioModal.tsx +++ b/packages/web/src/components/tipping/tip-audio/TipAudioModal.tsx @@ -13,7 +13,7 @@ import { Modal, ModalHeader, ModalTitle } from '@audius/stems' import cn from 'classnames' import { useDispatch } from 'react-redux' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web -import { animated, Transition } from 'react-spring/renderprops' +import { animated, Transition } from 'react-spring/renderprops.cjs' import { usePrevious } from 'react-use' import IconSuccess from 'assets/img/iconVerified.svg' diff --git a/packages/web/src/components/track/CardTitle.tsx b/packages/web/src/components/track/CardTitle.tsx index 49bba0f15a5..55909cebc52 100644 --- a/packages/web/src/components/track/CardTitle.tsx +++ b/packages/web/src/components/track/CardTitle.tsx @@ -26,7 +26,7 @@ const messages = { } type CardTitleProps = { - className: string + className?: string isUnlisted: boolean isRemix: boolean isPremium: boolean diff --git a/packages/web/src/components/track/GiantTrackTile.tsx b/packages/web/src/components/track/GiantTrackTile.tsx index fb884a24529..9d167477ea3 100644 --- a/packages/web/src/components/track/GiantTrackTile.tsx +++ b/packages/web/src/components/track/GiantTrackTile.tsx @@ -27,6 +27,7 @@ import { import cn from 'classnames' import IconRobot from 'assets/img/robot.svg' +import { ClientOnly } from 'components/client-only/ClientOnly' import DownloadButtons from 'components/download-buttons/DownloadButtons' import { EntityActionButton } from 'components/entity-page/EntityActionButton' import { UserLink } from 'components/link' @@ -494,12 +495,14 @@ export const GiantTrackTile = ({ elevation='mid' >
- + + +
{renderCardTitle(cn(fadeIn))} @@ -526,32 +529,34 @@ export const GiantTrackTile = ({
-
- {showPlay ? ( - - ) : null} - {showPreview ? ( - - ) : null} - {isLongFormContent && isNewPodcastControlsEnabled ? ( - - ) : ( - renderListenCount() - )} -
+ +
+ {showPlay ? ( + + ) : null} + {showPreview ? ( + + ) : null} + {isLongFormContent && isNewPodcastControlsEnabled ? ( + + ) : ( + renderListenCount() + )} +
+
{renderStatsRow()} @@ -600,20 +605,24 @@ export const GiantTrackTile = ({
- {isPremium && premiumConditions ? ( - - ) : null} + + {isPremium && premiumConditions ? ( + + ) : null} + - {aiAttributionUserId ? ( - - ) : null} + + {aiAttributionUserId ? ( + + ) : null} +
@@ -642,8 +651,10 @@ export const GiantTrackTile = ({ {description} ) : null} - {renderTags()} - {renderDownloadButtons()} + + {renderTags()} + {renderDownloadButtons()} +
) diff --git a/packages/web/src/components/transition-container/TransitionContainer.tsx b/packages/web/src/components/transition-container/TransitionContainer.tsx index de372611e81..ccb79a60a6e 100644 --- a/packages/web/src/components/transition-container/TransitionContainer.tsx +++ b/packages/web/src/components/transition-container/TransitionContainer.tsx @@ -1,7 +1,7 @@ import { ReactElement } from 'react' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web -import { animated, Transition } from 'react-spring/renderprops' +import { animated, Transition } from 'react-spring/renderprops.cjs' type TransitionContainerProps = { render: (item: any, style: object) => ReactElement diff --git a/packages/web/src/components/upload/InvalidFileType.jsx b/packages/web/src/components/upload/InvalidFileType.jsx index 574d06051f2..a6a737b4b09 100644 --- a/packages/web/src/components/upload/InvalidFileType.jsx +++ b/packages/web/src/components/upload/InvalidFileType.jsx @@ -1,7 +1,7 @@ import cn from 'classnames' import PropTypes from 'prop-types' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web -import { Spring } from 'react-spring/renderprops' +import { Spring } from 'react-spring/renderprops.cjs' import { Text } from 'components/typography' diff --git a/packages/web/src/pages/sign-on/components/CompleteProfileWithSocial.tsx b/packages/web/src/pages/sign-on/components/CompleteProfileWithSocial.tsx index d8a0741588c..a3e5d5f281c 100644 --- a/packages/web/src/pages/sign-on/components/CompleteProfileWithSocial.tsx +++ b/packages/web/src/pages/sign-on/components/CompleteProfileWithSocial.tsx @@ -9,7 +9,7 @@ import { import { IconImage, IconUser, IconVerified } from '@audius/stems' import cn from 'classnames' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web -import { Transition } from 'react-spring/renderprops' +import { Transition } from 'react-spring/renderprops.cjs' import { InstagramAuthButton } from 'components/instagram-auth/InstagramAuthButton' import LoadingSpinner from 'components/loading-spinner/LoadingSpinner' diff --git a/packages/web/src/pages/sign-on/components/ProfileForm.tsx b/packages/web/src/pages/sign-on/components/ProfileForm.tsx index 5844cb55b75..b5bfedf3eb7 100644 --- a/packages/web/src/pages/sign-on/components/ProfileForm.tsx +++ b/packages/web/src/pages/sign-on/components/ProfileForm.tsx @@ -9,7 +9,7 @@ import { import { Button, ButtonType, IconArrow } from '@audius/stems' import cn from 'classnames' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web -import { Spring } from 'react-spring/renderprops' +import { Spring } from 'react-spring/renderprops.cjs' import TwitterLogin from 'react-twitter-auth' import Input from 'components/data-entry/Input' diff --git a/packages/web/src/pages/sign-on/components/desktop/EmailPage.tsx b/packages/web/src/pages/sign-on/components/desktop/EmailPage.tsx index 40bd1cdb3d3..f9e8ec3b580 100644 --- a/packages/web/src/pages/sign-on/components/desktop/EmailPage.tsx +++ b/packages/web/src/pages/sign-on/components/desktop/EmailPage.tsx @@ -3,7 +3,7 @@ import { useEffect, useState } from 'react' import { Button, ButtonSize, ButtonType, IconArrow } from '@audius/stems' import cn from 'classnames' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web -import { Spring } from 'react-spring/renderprops' +import { Spring } from 'react-spring/renderprops.cjs' import audiusLogoColored from 'assets/img/audiusLogoColored.png' import Input from 'components/data-entry/Input' diff --git a/packages/web/src/pages/sign-on/components/desktop/SignInPage.tsx b/packages/web/src/pages/sign-on/components/desktop/SignInPage.tsx index 862ab60b824..b91247931a1 100644 --- a/packages/web/src/pages/sign-on/components/desktop/SignInPage.tsx +++ b/packages/web/src/pages/sign-on/components/desktop/SignInPage.tsx @@ -10,7 +10,7 @@ import { useInstanceVar } from '@audius/common' import { Button, ButtonType, IconArrow } from '@audius/stems' import cn from 'classnames' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web -import { Spring } from 'react-spring/renderprops' +import { Spring } from 'react-spring/renderprops.cjs' import audiusLogoColored from 'assets/img/audiusLogoColored.png' import Input from 'components/data-entry/Input' diff --git a/packages/web/src/pages/sign-on/components/desktop/SignOnPage.tsx b/packages/web/src/pages/sign-on/components/desktop/SignOnPage.tsx index e314a359ddb..f00183d138a 100644 --- a/packages/web/src/pages/sign-on/components/desktop/SignOnPage.tsx +++ b/packages/web/src/pages/sign-on/components/desktop/SignOnPage.tsx @@ -14,7 +14,7 @@ import cn from 'classnames' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web import { animated } from 'react-spring' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web -import { Transition } from 'react-spring/renderprops' +import { Transition } from 'react-spring/renderprops.cjs' import imageSignUp1 from 'assets/img/2-DJ-4-3.jpg' import imageSignUp2 from 'assets/img/3-Collection-4-3.jpg' diff --git a/packages/web/src/pages/sign-on/components/mobile/InitialPage.tsx b/packages/web/src/pages/sign-on/components/mobile/InitialPage.tsx index 4b2b046ee05..e3ce0737e5c 100644 --- a/packages/web/src/pages/sign-on/components/mobile/InitialPage.tsx +++ b/packages/web/src/pages/sign-on/components/mobile/InitialPage.tsx @@ -10,7 +10,7 @@ import { import { Button, ButtonType, IconArrow } from '@audius/stems' import cn from 'classnames' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web -import { Spring } from 'react-spring/renderprops' +import { Spring } from 'react-spring/renderprops.cjs' import djBackgroundImage from 'assets/img/2-DJ-4-3.jpg' import audiusLogoHorizontal from 'assets/img/Horizontal-Logo-Full-Color.png' diff --git a/packages/web/src/pages/sign-on/components/mobile/SignOnPage.tsx b/packages/web/src/pages/sign-on/components/mobile/SignOnPage.tsx index afe94c6b124..a91c772771a 100644 --- a/packages/web/src/pages/sign-on/components/mobile/SignOnPage.tsx +++ b/packages/web/src/pages/sign-on/components/mobile/SignOnPage.tsx @@ -12,7 +12,7 @@ import cn from 'classnames' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web import { animated } from 'react-spring' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web -import { Transition } from 'react-spring/renderprops' +import { Transition } from 'react-spring/renderprops.cjs' import { Pages, FollowArtistsCategory } from 'common/store/pages/signon/types' import MobilePageContainer from 'components/mobile-page-container/MobilePageContainer' diff --git a/packages/web/src/services/WebWorker.js b/packages/web/src/services/WebWorker.js index 35735737218..340d9213665 100644 --- a/packages/web/src/services/WebWorker.js +++ b/packages/web/src/services/WebWorker.js @@ -23,7 +23,10 @@ export default class WebWorker { code(); ` ]) - this.worker = new Worker(URL.createObjectURL(blob)) + this.worker = + typeof Worker !== 'undefined' + ? new Worker(URL.createObjectURL(blob)) + : null this.terminateOnResult = terminateOnResult } diff --git a/packages/web/src/services/audius-sdk/discoveryNodeSelector.ts b/packages/web/src/services/audius-sdk/discoveryNodeSelector.ts index a16addc98b4..890f662092c 100644 --- a/packages/web/src/services/audius-sdk/discoveryNodeSelector.ts +++ b/packages/web/src/services/audius-sdk/discoveryNodeSelector.ts @@ -15,7 +15,10 @@ type CachedDiscoveryNodeTimestamp = | undefined const getCachedDiscoveryNode = () => { - const cached = localStorage.getItem(DISCOVERY_PROVIDER_TIMESTAMP) + const cached = + typeof localStorage !== 'undefined' + ? localStorage.getItem(DISCOVERY_PROVIDER_TIMESTAMP) + : null if (cached) { try { const cachedDiscoveryNodeTimestamp = JSON.parse( diff --git a/packages/web/src/services/local-storage.ts b/packages/web/src/services/local-storage.ts index 27ebb4a57ba..55b6070e7df 100644 --- a/packages/web/src/services/local-storage.ts +++ b/packages/web/src/services/local-storage.ts @@ -1,5 +1,5 @@ import { LocalStorage } from '@audius/common' export const localStorage = new LocalStorage({ - localStorage: window.localStorage + localStorage: typeof window !== 'undefined' ? window.localStorage : {} }) diff --git a/packages/web/src/services/remote-config/featureFlagHelpers.ts b/packages/web/src/services/remote-config/featureFlagHelpers.ts index c594111ec9f..60f81175fee 100644 --- a/packages/web/src/services/remote-config/featureFlagHelpers.ts +++ b/packages/web/src/services/remote-config/featureFlagHelpers.ts @@ -6,7 +6,8 @@ import { import { remoteConfigInstance } from './remote-config-instance' -const getLocalStorageItem = (key: string) => window.localStorage.getItem(key) +const getLocalStorageItem = (key: string) => + typeof window !== 'undefined' ? window.localStorage.getItem(key) : null const getFlagEnabled = (flag: FeatureFlags) => { const overrideKey = `${FEATURE_FLAG_OVERRIDE_KEY}:${flag}` diff --git a/packages/web/src/services/remote-config/remote-config-instance.ts b/packages/web/src/services/remote-config/remote-config-instance.ts index 347b814ae79..e6bc7ed17ab 100644 --- a/packages/web/src/services/remote-config/remote-config-instance.ts +++ b/packages/web/src/services/remote-config/remote-config-instance.ts @@ -65,5 +65,3 @@ export const remoteConfigInstance = remoteConfig({ setLogLevel: () => optimizely.setLogLevel('warn'), environment: process.env.VITE_ENVIRONMENT as Environment }) - -remoteConfigInstance.init() diff --git a/packages/web/src/ssr/SsrRoot.tsx b/packages/web/src/ssr/SsrRoot.tsx new file mode 100644 index 00000000000..8b13df00ac9 --- /dev/null +++ b/packages/web/src/ssr/SsrRoot.tsx @@ -0,0 +1,13 @@ +import { ReactNode } from 'react' + +import { ClientOnly } from 'components/client-only/ClientOnly' + +import { Root } from '../Root' + +export const SsrRoot = ({ children }: { children: ReactNode }) => { + return ( + + + + ) +} diff --git a/packages/web/src/ssr/_default.page.client.tsx b/packages/web/src/ssr/_default.page.client.tsx index 8265a39bc4e..b4ba425cb7c 100644 --- a/packages/web/src/ssr/_default.page.client.tsx +++ b/packages/web/src/ssr/_default.page.client.tsx @@ -2,6 +2,7 @@ import { Track } from '@audius/sdk' import { hydrateRoot } from 'react-dom/client' import { PageContextClient } from 'vike/types' +import { SsrRoot } from './SsrRoot' import { WebPlayerSkeleton } from './WebPlayerSkeleton' // TODO: test hydrate vs render @@ -12,8 +13,10 @@ export async function render( const { Page, pageProps } = pageContext hydrateRoot( document.getElementById('page-view'), - - - + + + + + ) } diff --git a/packages/web/src/ssr/_default.page.server.tsx b/packages/web/src/ssr/_default.page.server.tsx index 8ab257eb3cf..3240fa09a39 100644 --- a/packages/web/src/ssr/_default.page.server.tsx +++ b/packages/web/src/ssr/_default.page.server.tsx @@ -3,6 +3,7 @@ import ReactDOMServer from 'react-dom/server' import { escapeInject, dangerouslySkipEscape } from 'vike/server' import { PageContextServer } from 'vike/types' +import { SsrRoot } from './SsrRoot' import { WebPlayerSkeleton } from './WebPlayerSkeleton' export const passToClient = ['pageProps'] @@ -12,9 +13,11 @@ export function render( ) { const { Page, pageProps } = pageContext const pageHtml = ReactDOMServer.renderToString( - - - + + + + + ) // TODO: this needs to be index.html diff --git a/packages/web/src/ssr/track.page.server.tsx b/packages/web/src/ssr/track.page.server.tsx index de37542b277..6693fcb5383 100644 --- a/packages/web/src/ssr/track.page.server.tsx +++ b/packages/web/src/ssr/track.page.server.tsx @@ -1,5 +1,5 @@ import type { Maybe } from '@audius/common' -import { Track, sdk } from '@audius/sdk' +import { sdk, full as FullSdk } from '@audius/sdk' import { PageContextServer } from 'vike/types' const audiusSdk = sdk({ @@ -7,7 +7,7 @@ const audiusSdk = sdk({ }) export type TrackPageProps = { - track: Maybe + track: Maybe } export async function onBeforeRender(pageContext: PageContextServer) { diff --git a/packages/web/src/ssr/track.page.tsx b/packages/web/src/ssr/track.page.tsx index 1832d86a309..35f20a90802 100644 --- a/packages/web/src/ssr/track.page.tsx +++ b/packages/web/src/ssr/track.page.tsx @@ -1,114 +1,186 @@ import React from 'react' -import { GiantTrackTile } from 'components/track/GiantTrackTile' +import { + FieldVisibility, + Genre, + PremiumConditions, + decodeHashId +} from '@audius/common' +import cn from 'classnames' + +import RepostFavoritesStats from 'components/repost-favorites-stats/RepostFavoritesStats' +import { Tile } from 'components/tile' +import { CardTitle } from 'components/track/CardTitle' +import styles from 'components/track/GiantTrackTile.module.css' +import { Text } from 'components/typography' +import trackPageStyles from 'pages/track-page/components/desktop/TrackPage.module.css' +import { profilePage } from 'utils/route' import { TrackPageProps } from './track.page.server' export function Page(props: TrackPageProps) { const { track } = props - console.log(props) - return
hi
- // return + if (!track) { + return null + } + + // return ( + // {}} + // onPreview={() => {}} + // onShare={() => {}} + // onRepost={() => {}} + // onSave={() => {}} + // onFollow={() => {}} + // onUnfollow={() => {}} + // onDownload={() => {}} + // onMakePublic={() => {}} + // onClickReposts={() => {}} + // onClickFavorites={() => {}} + // /> + // ) - // return - //
- // - //
- //
- // {renderCardTitle(cn(fadeIn))} - //
- //

{trackTitle}

- // {isLoading && } - //
- //
- //
- // By - // - //
- // {isLoading && ( - // - // )} - //
- //
+ const { + title, + id, + coverArtSizes, + _coSign, + isUnlisted, + remixOf, + isPremium, + genre, + premiumConditions + } = track - //
- // {showPlay ? ( - // - // ) : null} - // {showPreview ? ( - // - // ) : null} - // {isLongFormContent && isNewPodcastControlsEnabled ? ( - // - // ) : ( - // renderListenCount() - // )} - //
+ return ( +
+ +
+ {/* */} +
+
+ {/* */} +
+

{title}

+
+ +
- //
- // {renderStatsRow()} - //
+ {/*
+ + {isLongFormContent && isNewPodcastControlsEnabled + ? renderListenCount() + : null} +
*/} +
+ {/*
+ {aiAttributionUserId ? ( + } + className={styles.badgeAi} + textLabel={messages.generatedWithAi} + /> + ) : null} + {badge ? ( + + ) : null} +
*/} +
- //
- // {renderShareButton()} - // {renderMakePublicButton()} - // {doesUserHaveAccess && renderRepostButton()} - // {doesUserHaveAccess && renderFavoriteButton()} - // - // {/* prop types for overflow menu don't work correctly - // so we need to cast here */} - // - // {(ref, triggerPopup) => ( - //
- //
- // )} - //
- //
- //
- //
- // + {/*
+
+ + {renderReleased()} + {renderGenre()} + {renderMood()} + {credits ? ( + + ) : null} +
+ {description ? ( + + {description} + + ) : null} +
*/} + +
+ ) } diff --git a/packages/web/src/utils/clientUtil.ts b/packages/web/src/utils/clientUtil.ts index 9476a352ede..7473b056f61 100644 --- a/packages/web/src/utils/clientUtil.ts +++ b/packages/web/src/utils/clientUtil.ts @@ -11,6 +11,9 @@ declare global { } export const isMobile = () => { + if (typeof navigator === 'undefined') { + return false + } let check = false ;(function (a) { if ( @@ -34,6 +37,9 @@ export const isMobile = () => { } export const isElectron = () => { + if (typeof navigator === 'undefined') { + return false + } const userAgent = navigator.userAgent.toLowerCase() return userAgent.indexOf(' electron/') > -1 } diff --git a/packages/web/src/utils/safeArea.ts b/packages/web/src/utils/safeArea.ts index c7ce6d05c9d..0c1ad335bc7 100644 --- a/packages/web/src/utils/safeArea.ts +++ b/packages/web/src/utils/safeArea.ts @@ -13,6 +13,7 @@ const directionMap = { } export const getSafeArea = (direction: SafeAreaDirection) => { + if (typeof getComputedStyle === 'undefined') return 0 const property = directionMap[direction] const style = getComputedStyle(document.documentElement) const propertyValue = style.getPropertyValue(property) From 52812a8e4a393756bc63f94e416c27043eddcad7 Mon Sep 17 00:00:00 2001 From: sliptype Date: Mon, 27 Nov 2023 16:02:42 -0600 Subject: [PATCH 09/74] Get full app rendering server side --- .../services/local-storage/LocalStorage.ts | 2 +- packages/stems/src/components/Modal/Modal.tsx | 7 ++++- packages/stems/src/components/Modal/hooks.ts | 24 +++++++-------- packages/stems/src/components/Popup/Popup.tsx | 4 +-- packages/web/src/Root.tsx | 26 ++++++++++++----- packages/web/src/app/App.tsx | 3 +- packages/web/src/app/AppProviders.tsx | 17 +++++++++-- packages/web/src/app/web-player/WebPlayer.jsx | 15 ++++++---- .../components/banner/DownloadAppBanner.tsx | 7 ++--- .../web/src/components/data-entry/Input.jsx | 6 +--- .../components/nav/mobile/TopLevelPage.tsx | 3 +- .../now-playing/NowPlayingDrawer.tsx | 2 +- .../web/src/components/play-bar/VolumeBar.jsx | 1 + .../web/src/components/tooltip/Tooltip.tsx | 3 +- .../src/services/audio-player/AudioPlayer.ts | 14 +++++---- .../web/src/services/audio-player/index.ts | 3 +- packages/web/src/services/local-storage.ts | 9 +++++- packages/web/src/ssr/SsrContext.tsx | 27 +++++++++++++++++ packages/web/src/ssr/_default.page.server.tsx | 23 ++++++++++----- .../src/store/application/ui/theme/sagas.ts | 7 +++-- packages/web/src/store/configureStore.ts | 11 +++++-- packages/web/src/store/routing/sagas.ts | 4 ++- packages/web/src/utils/browser.ts | 4 ++- .../web/src/utils/browserNotifications.ts | 11 +++++-- packages/web/src/utils/clientUtil.ts | 4 ++- packages/web/src/utils/clipboardUtil.ts | 11 +++++-- packages/web/src/utils/history.ts | 5 +++- packages/web/src/utils/logger.js | 4 ++- packages/web/src/utils/route.ts | 29 ++----------------- packages/web/src/utils/share.ts | 2 +- packages/web/src/utils/theme/theme.ts | 9 ++++-- 31 files changed, 193 insertions(+), 104 deletions(-) create mode 100644 packages/web/src/ssr/SsrContext.tsx diff --git a/packages/common/src/services/local-storage/LocalStorage.ts b/packages/common/src/services/local-storage/LocalStorage.ts index a59dae02fdc..d6332960e09 100644 --- a/packages/common/src/services/local-storage/LocalStorage.ts +++ b/packages/common/src/services/local-storage/LocalStorage.ts @@ -1,8 +1,8 @@ import { CURRENT_USER_EXISTS_LOCAL_STORAGE_KEY } from '@audius/sdk/dist/core' +import { User } from 'models/User' import { PLAYBACK_RATE_LS_KEY } from 'store/index' -import { User } from '../../models' import { Nullable } from '../../utils' // TODO: the following should come from @audius/libs/dist/core when diff --git a/packages/stems/src/components/Modal/Modal.tsx b/packages/stems/src/components/Modal/Modal.tsx index 95f53fa8b3f..4754a436453 100644 --- a/packages/stems/src/components/Modal/Modal.tsx +++ b/packages/stems/src/components/Modal/Modal.tsx @@ -291,9 +291,14 @@ export const Modal = forwardRef(function Modal( [headerContainerClassName!]: !!headerContainerClassName }) - const [height, setHeight] = useState(window.innerHeight) + const [height, setHeight] = useState( + typeof window !== 'undefined' ? window.innerHeight : 0 + ) useEffect(() => { + if (typeof window === 'undefined') { + return + } const onResize = () => { setHeight(window.innerHeight) } diff --git a/packages/stems/src/components/Modal/hooks.ts b/packages/stems/src/components/Modal/hooks.ts index 9abe8caaec4..4ec18ac54ab 100644 --- a/packages/stems/src/components/Modal/hooks.ts +++ b/packages/stems/src/components/Modal/hooks.ts @@ -1,7 +1,5 @@ import { useCallback, useEffect, useState } from 'react' -import { useGlobal } from 'hooks/useGlobal' - export const setOverflowHidden = () => { document.body.setAttribute('style', 'overflow:hidden;') } @@ -12,23 +10,25 @@ export const removeOverflowHidden = () => { export const setModalRootTop = () => { const root = document.getElementById('modalRootContainer') + const scrollY = typeof window !== 'undefined' ? window.scrollY : 0 if (root) { - root.setAttribute('style', `top: ${window.scrollY}px`) + root.setAttribute('style', `top: ${scrollY}px`) } } +let modalCount = 0 + export const useModalScrollCount = () => { - const [getCount, setCount] = useGlobal('modal-scroll-count', 0) // Keep a state toggle to trigger recomputations of the effect const [toggle, setToggle] = useState(false) const [isOverflowHidden, setIsOverflowHidden] = useState(false) useEffect(() => { - if (!isOverflowHidden && getCount() > 0) { + if (!isOverflowHidden && modalCount > 0) { setIsOverflowHidden(true) setOverflowHidden() setModalRootTop() - } else if (isOverflowHidden && getCount() === 0) { + } else if (isOverflowHidden && modalCount === 0) { setIsOverflowHidden(false) removeOverflowHidden() } @@ -44,23 +44,23 @@ export const useModalScrollCount = () => { * NOTE: This should only be triggered on un-mount when not closed */ setImmediate(() => { - if (isOverflowHidden && getCount() === 0) { + if (isOverflowHidden && modalCount === 0) { removeOverflowHidden() } }) } - }, [getCount, isOverflowHidden, toggle]) + }, [isOverflowHidden, toggle]) const incrementScrollCount = useCallback(() => { - setCount((count) => count + 1) + modalCount = modalCount + 1 setToggle((toggle) => !toggle) - }, [setCount, setToggle]) + }, [setToggle]) const decrementScrollCount = useCallback(() => { // Though we should in theory never be decrementing past zero, getting into // that state would be bad for us, so guard against it defensively - setCount((count) => Math.max(0, count - 1)) + modalCount = Math.max(0, modalCount - 1) setToggle((toggle) => !toggle) - }, [setCount, setToggle]) + }, [setToggle]) return { incrementScrollCount, diff --git a/packages/stems/src/components/Popup/Popup.tsx b/packages/stems/src/components/Popup/Popup.tsx index 28ec5ed906c..05a2a03dfee 100644 --- a/packages/stems/src/components/Popup/Popup.tsx +++ b/packages/stems/src/components/Popup/Popup.tsx @@ -416,7 +416,7 @@ export const Popup = forwardRef(function Popup( } }, [dismissOnMouseLeave, onClose]) - return ( + return typeof document !== 'undefined' ? ( <> {/* Portal the popup out of the dom structure so that it has a separate stacking context */} {ReactDOM.createPortal( @@ -463,5 +463,5 @@ export const Popup = forwardRef(function Popup( document.body )} - ) + ) : null }) diff --git a/packages/web/src/Root.tsx b/packages/web/src/Root.tsx index dfd3d825b4d..ebdef2c8260 100644 --- a/packages/web/src/Root.tsx +++ b/packages/web/src/Root.tsx @@ -9,15 +9,22 @@ import { localStorage } from 'services/local-storage' import { useIsMobile, isElectron } from 'utils/clientUtil' import { getPathname, HOME_PAGE, publicSiteRoutes } from 'utils/route' -const App = lazy(() => import('./app')) +import App from './app' +import { useSsrContext } from './ssr/SsrContext' + +// const App = lazy(() => import('./app')) const PublicSite = lazy(() => import('./public-site')) -const isPublicSiteRoute = (location = window.location) => { +const isPublicSiteRoute = ( + location: { pathname: string } = window.location +) => { const pathname = getPathname(location).toLowerCase() return [...publicSiteRoutes, HOME_PAGE].includes(pathname) } -const isPublicSiteSubRoute = (location = window.location) => { +const isPublicSiteSubRoute = ( + location: { pathname: string } = window.location +) => { const pathname = getPathname(location).toLowerCase() return publicSiteRoutes.includes(pathname) } @@ -25,7 +32,10 @@ const isPublicSiteSubRoute = (location = window.location) => { const clientIsElectron = isElectron() export const Root = () => { - const [renderPublicSite, setRenderPublicSite] = useState(isPublicSiteRoute()) + const { path } = useSsrContext() + const [renderPublicSite, setRenderPublicSite] = useState( + isPublicSiteRoute({ pathname: path ?? '' }) + ) const isMobileClient = useIsMobile() const { value: foundUser } = useAsync(() => @@ -35,7 +45,7 @@ export const Root = () => { useEffect(() => { // TODO: listen to history and change routes based on history... window.onpopstate = () => { - setRenderPublicSite(isPublicSiteRoute()) + setRenderPublicSite(isPublicSiteRoute({ pathname: path ?? '' })) } }, []) @@ -52,8 +62,8 @@ export const Root = () => { } return ( - }> - - + // }> + + // ) } diff --git a/packages/web/src/app/App.tsx b/packages/web/src/app/App.tsx index 4f4c006d478..459d9005541 100644 --- a/packages/web/src/app/App.tsx +++ b/packages/web/src/app/App.tsx @@ -9,7 +9,8 @@ import DemoTrpcPage from 'pages/demo-trpc/DemoTrpcPage' import { OAuthLoginPage } from 'pages/oauth-login-page/OAuthLoginPage' import { SomethingWrong } from 'pages/something-wrong/SomethingWrong' -import '../services/webVitals' +// TODO: turn into a component to utilize SsrContext +// import '../services/webVitals' import { remoteConfigInstance } from 'services/remote-config/remote-config-instance' diff --git a/packages/web/src/app/AppProviders.tsx b/packages/web/src/app/AppProviders.tsx index 3b03f104091..3963599ae28 100644 --- a/packages/web/src/app/AppProviders.tsx +++ b/packages/web/src/app/AppProviders.tsx @@ -14,6 +14,7 @@ import { persistor, store } from 'store/configureStore' import history from 'utils/history' import { MainContentContextProvider } from '../pages/MainContentContext' +import { useSsrContext } from '../ssr/SsrContext' import { AppContextProvider } from './AppContextProvider' import { AudiusQueryProvider } from './AudiusQueryProvider' @@ -24,10 +25,22 @@ type AppContextProps = { children: ReactNode } +const Persist = ({ children }: { children: ReactNode }) => ( + + {children} + +) + +const Wrapper = ({ children }: { children: ReactNode }) => <>{children} + export const AppProviders = ({ children }: AppContextProps) => { + const { isServerSide } = useSsrContext() + + const ReduxPersistProvider = isServerSide ? Wrapper : Persist + return ( - + @@ -53,7 +66,7 @@ export const AppProviders = ({ children }: AppContextProps) => { - + ) } diff --git a/packages/web/src/app/web-player/WebPlayer.jsx b/packages/web/src/app/web-player/WebPlayer.jsx index d9ba22cab43..62345709ae3 100644 --- a/packages/web/src/app/web-player/WebPlayer.jsx +++ b/packages/web/src/app/web-player/WebPlayer.jsx @@ -39,7 +39,6 @@ import CookieBanner from 'components/cookie-banner/CookieBanner' import { DevModeMananger } from 'components/dev-mode-manager/DevModeManager' import { HeaderContextConsumer } from 'components/header/mobile/HeaderContextProvider' import Konami from 'components/konami/Konami' -import ConnectedMusicConfetti from 'components/music-confetti/ConnectedMusicConfetti' import Navigator from 'components/nav/Navigator' import TopLevelPage from 'components/nav/mobile/TopLevelPage' import Notice from 'components/notice/Notice' @@ -190,6 +189,10 @@ const { getTheme } = themeSelectors const { getHasAccount, getAccountStatus, getUserId, getUserHandle } = accountSelectors +const ConnectedMusicConfetti = lazy(() => + import('components/music-confetti/ConnectedMusicConfetti') +) + const SignOn = lazy(() => import('pages/sign-on/SignOn')) const UploadPage = lazy(() => import('pages/upload-page')) @@ -235,7 +238,7 @@ class WebPlayer extends Component { this.scrollToTop() this.setState({ initialPage: false, - currentRoute: getPathname(location) + currentRoute: getPathname(this.props.history.location) }) } ) @@ -497,7 +500,7 @@ class WebPlayer extends Component { ))} @@ -950,7 +953,9 @@ class WebPlayer extends Component { // pathname is not HOME_PAGE. Double check that it is and if not, // just trigger a react router push to the current pathname pathname: - getPathname() === HOME_PAGE ? FEED_PAGE : getPathname(), + getPathname(this.props.history) === HOME_PAGE + ? FEED_PAGE + : getPathname(this.props.history), search: includeSearch(this.props.location.search) ? this.props.location.search : '' @@ -963,7 +968,7 @@ class WebPlayer extends Component { - + {/* */} diff --git a/packages/web/src/components/banner/DownloadAppBanner.tsx b/packages/web/src/components/banner/DownloadAppBanner.tsx index c921865f965..425165ece68 100644 --- a/packages/web/src/components/banner/DownloadAppBanner.tsx +++ b/packages/web/src/components/banner/DownloadAppBanner.tsx @@ -4,6 +4,7 @@ import { Client, accountSelectors } from '@audius/common' import { useDispatch } from 'react-redux' import { useSelector } from 'common/hooks/useSelector' +import { localStorage } from 'services/local-storage' import { setVisibility as setAppModalCTAVisibility } from 'store/application/ui/app-cta-modal/slice' import { getClient } from 'utils/clientUtil' @@ -25,9 +26,7 @@ const messages = { export const DownloadAppBanner = () => { const dispatch = useDispatch() const signedIn = useSelector(getHasAccount) - const hasDismissed = window.localStorage.getItem( - MOBILE_BANNER_LOCAL_STORAGE_KEY - ) + const hasDismissed = localStorage.getItem(MOBILE_BANNER_LOCAL_STORAGE_KEY) const isDesktopWeb = getClient() === Client.DESKTOP const [isVisible, setIsVisible] = useState( !hasDismissed && isDesktopWeb && !signedIn @@ -35,7 +34,7 @@ export const DownloadAppBanner = () => { const handleClose = useCallback(() => { setIsVisible(false) - window.localStorage.setItem(MOBILE_BANNER_LOCAL_STORAGE_KEY, 'true') + localStorage.setItem(MOBILE_BANNER_LOCAL_STORAGE_KEY, 'true') }, []) const handleAccept = useCallback(() => { diff --git a/packages/web/src/components/data-entry/Input.jsx b/packages/web/src/components/data-entry/Input.jsx index affc9376764..977013b8788 100644 --- a/packages/web/src/components/data-entry/Input.jsx +++ b/packages/web/src/components/data-entry/Input.jsx @@ -153,11 +153,7 @@ Input.propTypes = { isRequired: PropTypes.bool, onChange: PropTypes.func, onFocus: PropTypes.func, - onBlur: PropTypes.func, - inputRef: PropTypes.oneOfType([ - PropTypes.func, - PropTypes.shape({ current: PropTypes.instanceOf(Element) }) - ]) + onBlur: PropTypes.func } Input.defaultProps = { diff --git a/packages/web/src/components/nav/mobile/TopLevelPage.tsx b/packages/web/src/components/nav/mobile/TopLevelPage.tsx index 7c554c47e0d..424c3234d82 100644 --- a/packages/web/src/components/nav/mobile/TopLevelPage.tsx +++ b/packages/web/src/components/nav/mobile/TopLevelPage.tsx @@ -14,7 +14,8 @@ const { getModalVisibility } = modalsSelectors type TopLevelPageProps = ReturnType & ReturnType -const rootElement = document.querySelector('#root') +const rootElement = + typeof document !== 'undefined' ? document.querySelector('#root') : null const TopLevelPage = ({ showAddToPlaylist }: TopLevelPageProps) => { const { isOpen } = useEditPlaylistModal() diff --git a/packages/web/src/components/now-playing/NowPlayingDrawer.tsx b/packages/web/src/components/now-playing/NowPlayingDrawer.tsx index 15e02ed3b5a..fc609156a5c 100644 --- a/packages/web/src/components/now-playing/NowPlayingDrawer.tsx +++ b/packages/web/src/components/now-playing/NowPlayingDrawer.tsx @@ -14,7 +14,7 @@ import NowPlaying from './NowPlaying' import styles from './NowPlayingDrawer.module.css' const { setIsOpen: _setIsNowPlayingOpen } = nowPlayingUIActions -const DEFAULT_HEIGHT = window.innerHeight +const DEFAULT_HEIGHT = typeof window !== 'undefined' ? window.innerHeight : 0 // Translation values for a totally hidden drawer const DRAWER_HIDDEN_TRANSLATION = -48 diff --git a/packages/web/src/components/play-bar/VolumeBar.jsx b/packages/web/src/components/play-bar/VolumeBar.jsx index 81185c580e6..d59ea63b5da 100644 --- a/packages/web/src/components/play-bar/VolumeBar.jsx +++ b/packages/web/src/components/play-bar/VolumeBar.jsx @@ -19,6 +19,7 @@ const getVolumeIcon = (volumeLevel) => { } const getSavedVolume = (defaultVolume) => { + if (typeof window === 'undefined') return defaultVolume const localStorageVolume = window.localStorage.getItem('volume') if (localStorageVolume === null) { window.localStorage.setItem('volume', defaultVolume) diff --git a/packages/web/src/components/tooltip/Tooltip.tsx b/packages/web/src/components/tooltip/Tooltip.tsx index ca29670f927..8119c5905a7 100644 --- a/packages/web/src/components/tooltip/Tooltip.tsx +++ b/packages/web/src/components/tooltip/Tooltip.tsx @@ -63,7 +63,8 @@ export const Tooltip = ({ ) let popupContainer - const page = document.getElementById('page') + const page = + typeof document !== 'undefined' ? document.getElementById('page') : null switch (mount) { case 'parent': popupContainer = (triggerNode: HTMLElement) => diff --git a/packages/web/src/services/audio-player/AudioPlayer.ts b/packages/web/src/services/audio-player/AudioPlayer.ts index 4ef1d65f05b..200d153d97c 100644 --- a/packages/web/src/services/audio-player/AudioPlayer.ts +++ b/packages/web/src/services/audio-player/AudioPlayer.ts @@ -7,10 +7,12 @@ declare global { } } -const IS_SAFARI = /^((?!chrome|android).)*safari/i.test(navigator.userAgent) -const IS_UI_WEBVIEW = /(iPhone|iPod|iPad).*AppleWebKit/i.test( - navigator.userAgent -) +const IS_SAFARI = + typeof navigator !== 'undefined' && + /^((?!chrome|android).)*safari/i.test(navigator.userAgent) +const IS_UI_WEBVIEW = + typeof navigator !== 'undefined' && + /(iPhone|iPod|iPad).*AppleWebKit/i.test(navigator.userAgent) const FADE_IN_EVENT = new Event('fade-in') const FADE_OUT_EVENT = new Event('fade-out') @@ -20,7 +22,9 @@ const FADE_IN_TIME_MILLISECONDS = 320 const FADE_OUT_TIME_MILLISECONDS = 400 const IS_CHROME_LIKE = - /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor) + typeof navigator !== 'undefined' && + /Chrome/.test(navigator.userAgent) && + /Google Inc/.test(navigator.vendor) export enum AudioError { AUDIO = 'AUDIO' diff --git a/packages/web/src/services/audio-player/index.ts b/packages/web/src/services/audio-player/index.ts index 59913d137c6..abb3ab5da56 100644 --- a/packages/web/src/services/audio-player/index.ts +++ b/packages/web/src/services/audio-player/index.ts @@ -1,3 +1,4 @@ import { AudioPlayer } from './AudioPlayer' -export const audioPlayer = new AudioPlayer() +export const audioPlayer = + typeof Audio !== 'undefined' ? new AudioPlayer() : null diff --git a/packages/web/src/services/local-storage.ts b/packages/web/src/services/local-storage.ts index 55b6070e7df..87c0e53178f 100644 --- a/packages/web/src/services/local-storage.ts +++ b/packages/web/src/services/local-storage.ts @@ -1,5 +1,12 @@ import { LocalStorage } from '@audius/common' export const localStorage = new LocalStorage({ - localStorage: typeof window !== 'undefined' ? window.localStorage : {} + localStorage: + typeof window !== 'undefined' + ? window.localStorage + : { + getItem: (key) => null, + setItem: (key: string, value: string) => {}, + removeItem: (key: string) => {} + } }) diff --git a/packages/web/src/ssr/SsrContext.tsx b/packages/web/src/ssr/SsrContext.tsx new file mode 100644 index 00000000000..f2426a73559 --- /dev/null +++ b/packages/web/src/ssr/SsrContext.tsx @@ -0,0 +1,27 @@ +import { createContext, memo, useContext } from 'react' + +import { Nullable } from '@audius/common' + +type SsrContextType = { + path: Nullable + isServerSide: boolean +} + +export const useSsrContext = () => { + return useContext(SsrContext) +} + +export const SsrContext = createContext({ + path: null, + isServerSide: true +} as SsrContextType) + +export const SsrContextProvider = memo( + (props: { value: SsrContextType; children: JSX.Element }) => { + return ( + + {props.children} + + ) + } +) diff --git a/packages/web/src/ssr/_default.page.server.tsx b/packages/web/src/ssr/_default.page.server.tsx index 3240fa09a39..bae41baf4b5 100644 --- a/packages/web/src/ssr/_default.page.server.tsx +++ b/packages/web/src/ssr/_default.page.server.tsx @@ -3,28 +3,35 @@ import ReactDOMServer from 'react-dom/server' import { escapeInject, dangerouslySkipEscape } from 'vike/server' import { PageContextServer } from 'vike/types' +import history from 'utils/history' + +import { Root } from '../Root' + +import { SsrContextProvider } from './SsrContext' import { SsrRoot } from './SsrRoot' import { WebPlayerSkeleton } from './WebPlayerSkeleton' -export const passToClient = ['pageProps'] +export const passToClient = ['pageProps', 'urlPathname'] export function render( pageContext: PageContextServer & { pageProps: { track: Track } } ) { - const { Page, pageProps } = pageContext + const { Page, pageProps, urlPathname } = pageContext + + history.replace(urlPathname) + const pageHtml = ReactDOMServer.renderToString( - - - - - + + + ) // TODO: this needs to be index.html + // TODO: env vars? return escapeInject` -
${dangerouslySkipEscape(pageHtml)}
+
${dangerouslySkipEscape(pageHtml)}
` } diff --git a/packages/web/src/store/application/ui/theme/sagas.ts b/packages/web/src/store/application/ui/theme/sagas.ts index 23af2fca408..7990b94960b 100644 --- a/packages/web/src/store/application/ui/theme/sagas.ts +++ b/packages/web/src/store/application/ui/theme/sagas.ts @@ -7,9 +7,10 @@ import { setTheme, PREFERS_DARK_MEDIA_QUERY } from 'utils/theme/theme' const { setTheme: setThemeAction } = themeActions // `window.matchMedia` can be undefined in some environments (testing and outdated browsers). -const mql = window.matchMedia - ? window.matchMedia(PREFERS_DARK_MEDIA_QUERY) - : null +const mql = + typeof window !== 'undefined' && window.matchMedia + ? window.matchMedia(PREFERS_DARK_MEDIA_QUERY) + : null let mqlListener: EventListener function* setThemeAsync(action: PayloadAction<{ theme: Theme }>) { diff --git a/packages/web/src/store/configureStore.ts b/packages/web/src/store/configureStore.ts index 2d27b820dd7..9614a43bea9 100644 --- a/packages/web/src/store/configureStore.ts +++ b/packages/web/src/store/configureStore.ts @@ -129,7 +129,7 @@ const sagaMiddleware = createSagaMiddleware({ const middlewares = applyMiddleware( chatMiddleware(audiusSdk), routerMiddleware(history), - sagaMiddleware, + ...(typeof window !== 'undefined' ? [sagaMiddleware] : []), sentryMiddleware, thunk ) @@ -144,7 +144,10 @@ const configureStore = () => { createRootReducer(history), composeEnhancers(middlewares) ) - sagaMiddleware.run(rootSaga) + + if (typeof window !== 'undefined') { + sagaMiddleware.run(rootSaga) + } return store } @@ -152,7 +155,9 @@ export const store = configureStore() export const persistor = persistStore(store) // Mount store to window for easy access -window.store = store +if (typeof window !== 'undefined') { + window.store = store +} // Set up logger on store logger(store) diff --git a/packages/web/src/store/routing/sagas.ts b/packages/web/src/store/routing/sagas.ts index b7c711104d0..2fe7628ddac 100644 --- a/packages/web/src/store/routing/sagas.ts +++ b/packages/web/src/store/routing/sagas.ts @@ -7,7 +7,9 @@ enum LocationAction { REPLACE = 'REPLACE' } -;(window as any).locationHistory = [] +if (typeof window !== 'undefined') { + ;(window as any).locationHistory = [] +} function* trackLocation() { while (true) { diff --git a/packages/web/src/utils/browser.ts b/packages/web/src/utils/browser.ts index cb9be1e8134..3fd780f379d 100644 --- a/packages/web/src/utils/browser.ts +++ b/packages/web/src/utils/browser.ts @@ -1,3 +1,5 @@ export const getIsIOS = () => { - return !/android/i.test(navigator.userAgent) + return ( + typeof navigator !== 'undefined' && !/android/i.test(navigator.userAgent) + ) } diff --git a/packages/web/src/utils/browserNotifications.ts b/packages/web/src/utils/browserNotifications.ts index 7437a923ff3..95eda95c6e3 100644 --- a/packages/web/src/utils/browserNotifications.ts +++ b/packages/web/src/utils/browserNotifications.ts @@ -41,9 +41,16 @@ const fcmWebPushPublicKey = process.env.VITE_FCM_PUSH_PUBLIC_KEY as string const safariWebPushID = process.env.VITE_SAFARI_WEB_PUSH_ID const applicationServerPublicKey = fcmWebPushPublicKey export const isPushManagerAvailable = - !isElectron() && 'serviceWorker' in navigator && 'PushManager' in window + !isElectron() && + typeof navigator !== 'undefined' && + 'serviceWorker' in navigator && + typeof window !== 'undefined' && + 'PushManager' in window export const isSafariPushAvailable = - !isElectron() && 'safari' in window && 'pushNotification' in window.safari + !isElectron() && + typeof window !== 'undefined' && + 'safari' in window && + 'pushNotification' in window.safari export const isBrowserPushAvailable = isPushManagerAvailable || isSafariPushAvailable diff --git a/packages/web/src/utils/clientUtil.ts b/packages/web/src/utils/clientUtil.ts index 7473b056f61..617b5f71c3d 100644 --- a/packages/web/src/utils/clientUtil.ts +++ b/packages/web/src/utils/clientUtil.ts @@ -11,7 +11,7 @@ declare global { } export const isMobile = () => { - if (typeof navigator === 'undefined') { + if (typeof navigator === 'undefined' || typeof window === 'undefined') { return false } let check = false @@ -45,6 +45,7 @@ export const isElectron = () => { } export const getOS = () => { + if (typeof window === 'undefined') return null const platform = window.navigator.platform const macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'] @@ -61,6 +62,7 @@ export const getOS = () => { } export const getMobileOS = () => { + if (typeof window === 'undefined') return null const userAgent = navigator.userAgent || navigator.vendor || window.opera // Windows Phone must come first because its UA also contains "Android" diff --git a/packages/web/src/utils/clipboardUtil.ts b/packages/web/src/utils/clipboardUtil.ts index 13e30498569..27b626c0272 100644 --- a/packages/web/src/utils/clipboardUtil.ts +++ b/packages/web/src/utils/clipboardUtil.ts @@ -1,8 +1,12 @@ const PUBLIC_PROTOCOL = process.env.VITE_PUBLIC_PROTOCOL const PUBLIC_HOSTNAME = process.env.VITE_PUBLIC_HOSTNAME -const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) -const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent) +const isIOS = + typeof navigator !== 'undefined' && + /iPad|iPhone|iPod/.test(navigator.userAgent) +const isSafari = + typeof navigator !== 'undefined' && + /^((?!chrome|android).)*safari/i.test(navigator.userAgent) // Pulled from: https://hackernoon.com/copying-text-to-clipboard-with-javascript-df4d4988697f export const copyToClipboard = (str: string) => { @@ -51,4 +55,5 @@ export const copyLinkToClipboard = (link: string) => { } // @ts-ignore: Navigator's share exists on newer browsers -export const isShareToastDisabled = !!navigator.share +export const isShareToastDisabled = + typeof navigator !== 'undefined' && !!navigator.share diff --git a/packages/web/src/utils/history.ts b/packages/web/src/utils/history.ts index 9918db44b30..67e832aa599 100644 --- a/packages/web/src/utils/history.ts +++ b/packages/web/src/utils/history.ts @@ -2,6 +2,7 @@ import { BrowserHistoryBuildOptions, createBrowserHistory, createHashHistory, + createMemoryHistory, HashHistoryBuildOptions, History } from 'history' @@ -16,12 +17,14 @@ if (USE_HASH_ROUTING) { config.basename = basename } history = createHashHistory(config) -} else { +} else if (typeof window !== 'undefined') { const config: BrowserHistoryBuildOptions = {} if (basename) { config.basename = basename } history = createBrowserHistory(config) +} else { + history = createMemoryHistory() } export default history diff --git a/packages/web/src/utils/logger.js b/packages/web/src/utils/logger.js index 064544fb530..d161454c8f1 100644 --- a/packages/web/src/utils/logger.js +++ b/packages/web/src/utils/logger.js @@ -1,6 +1,8 @@ /* eslint-disable no-console */ const preserveLogs = - window.localStorage && window.localStorage.getItem('preserve-logs') + typeof window !== 'undefined' && + window.localStorage && + window.localStorage.getItem('preserve-logs') export const storeLogger = (store) => { if (process.env.VITE_ENVIRONMENT === 'production' && !preserveLogs) { diff --git a/packages/web/src/utils/route.ts b/packages/web/src/utils/route.ts index 174ba70d278..4387835c496 100644 --- a/packages/web/src/utils/route.ts +++ b/packages/web/src/utils/route.ts @@ -3,6 +3,8 @@ import { push as pushRoute } from 'connected-react-router' import { Location as HistoryLocation } from 'history' import { matchPath } from 'react-router' +import history from './history' + const USE_HASH_ROUTING = process.env.VITE_USE_HASH_ROUTING === 'true' // Host/protocol. @@ -424,36 +426,11 @@ export const stripBaseUrl = (url: string) => url.replace(BASE_URL, '') * @param {Location} location */ export const getPathname = ( - location: Location | HistoryLocation = window.location + location: Location | HistoryLocation = history.location ) => { - // If this is a Location, pathname will have a host. If it's a HistoryLocation, - // the hashrouter will automatically understand the pathname to be the hash route - if (USE_HASH_ROUTING && 'host' in location) { - return location.hash.replace('#', '') - } return BASENAME ? location.pathname.replace(BASENAME, '') : location.pathname } -/** - * For a given route, checks if any of the previous routes in the `orderedRoutes` array matches the window's pathname - * Returns true if none of the previous routes mach and it does, otherwise false. - */ -export const doesRenderPage = (pageRoute: string) => { - const pgIndex = orderedRoutes.findIndex((route) => route === pageRoute) - if (pgIndex === -1) return false - const noPreviousMatches = orderedRoutes.slice(0, pgIndex).every((route) => { - return !matchPath(getPathname(), { - path: route, - exact: true - }) - }) - if (!noPreviousMatches) return false - return matchPath(getPathname(), { - path: pageRoute, - exact: true - }) -} - export const recordGoToSignup = (callback: () => void) => { if ((window as any).analytics) { ;(window as any).analytics.track( diff --git a/packages/web/src/utils/share.ts b/packages/web/src/utils/share.ts index 5ba5c9e0019..655f3f73ac4 100644 --- a/packages/web/src/utils/share.ts +++ b/packages/web/src/utils/share.ts @@ -9,7 +9,7 @@ export const share = (url: string, text?: string) => { const shareableLink = getCopyableLink(url) // @ts-ignore: navigator may have share field in updated browsers - if (navigator.share && isMobile()) { + if (typeof navigator !== 'undefined' && navigator.share && isMobile()) { navigator // @ts-ignore: navigator may have share field in updated browsers .share({ diff --git a/packages/web/src/utils/theme/theme.ts b/packages/web/src/utils/theme/theme.ts index cfefaf64241..aabb83317a4 100644 --- a/packages/web/src/utils/theme/theme.ts +++ b/packages/web/src/utils/theme/theme.ts @@ -66,11 +66,16 @@ const getThemeColors = (theme: Theme | null) => { export const setTheme = (theme: Theme) => { applyTheme(theme) - window.localStorage.setItem(THEME_KEY, theme) + if (typeof window !== 'undefined') { + window.localStorage.setItem(THEME_KEY, theme) + } } export const getTheme = (): Theme | null => { - const theme = window.localStorage.getItem(THEME_KEY) + const theme = + typeof window !== 'undefined' + ? window.localStorage.getItem(THEME_KEY) + : null if (theme && Object.values(Theme).includes(theme as Theme)) { return theme as Theme } From a5ff151e9e237ecdf90bdf7211ad3f0711ab66d8 Mon Sep 17 00:00:00 2001 From: sliptype Date: Mon, 27 Nov 2023 17:23:11 -0600 Subject: [PATCH 10/74] Get full track page rendering server side --- packages/web/src/app/web-player/WebPlayer.jsx | 76 ++++++++++--------- .../background-animations/MusicConfetti.tsx | 43 ++++++----- .../FeatureFlagOverrideModal.tsx | 6 +- .../src/components/lineup/LineupProvider.tsx | 6 +- packages/web/src/components/toast/Toast.tsx | 8 +- packages/web/src/utils/clipboardUtil.ts | 2 + 6 files changed, 80 insertions(+), 61 deletions(-) diff --git a/packages/web/src/app/web-player/WebPlayer.jsx b/packages/web/src/app/web-player/WebPlayer.jsx index 62345709ae3..7086182df38 100644 --- a/packages/web/src/app/web-player/WebPlayer.jsx +++ b/packages/web/src/app/web-player/WebPlayer.jsx @@ -183,6 +183,8 @@ import { getTheme as getSystemTheme } from 'utils/theme/theme' import styles from './WebPlayer.module.css' +import { ClientOnly } from 'components/client-only/ClientOnly' + const { setTheme } = themeActions const { getTheme } = themeSelectors @@ -287,44 +289,46 @@ class WebPlayer extends Component { } }) - const windowOpen = window.open - - const a = document.createElement('a') - window.open = (...args) => { - const url = args[0] - if (!url) { - const popup = windowOpen(window.location) - const win = { - popup, - closed: popup.closed, - close: () => { - popup.close() + if (typeof window !== 'undefined') { + const windowOpen = window.open + + const a = document.createElement('a') + window.open = (...args) => { + const url = args[0] + if (!url) { + const popup = windowOpen(window.location) + const win = { + popup, + closed: popup.closed, + close: () => { + popup.close() + } } - } - Object.defineProperty(win, 'location', { - get: () => { - a.href = popup.location - if (!a.search) { + Object.defineProperty(win, 'location', { + get: () => { + a.href = popup.location + if (!a.search) { + return { + href: popup.location, + search: a.search, + hostname: '' + } + } return { href: popup.location, search: a.search, - hostname: '' + hostname: a.hostname } + }, + set: (locationHref) => { + popup.location = locationHref + this.locationHref = locationHref } - return { - href: popup.location, - search: a.search, - hostname: a.hostname - } - }, - set: (locationHref) => { - popup.location = locationHref - this.locationHref = locationHref - } - }) - return win + }) + return win + } + return windowOpen(...args) } - return windowOpen(...args) } } @@ -965,10 +969,12 @@ class WebPlayer extends Component {
- - - - {/* */} + + + + + + diff --git a/packages/web/src/components/background-animations/MusicConfetti.tsx b/packages/web/src/components/background-animations/MusicConfetti.tsx index 905893d9966..3d39b7ea106 100644 --- a/packages/web/src/components/background-animations/MusicConfetti.tsx +++ b/packages/web/src/components/background-animations/MusicConfetti.tsx @@ -1,4 +1,4 @@ -import { useRef, useCallback, useEffect, useState } from 'react' +import { useRef, useCallback, useEffect, useState, useMemo } from 'react' import { Theme } from '@audius/common' @@ -14,25 +14,6 @@ const DEFAULTS = { particleRate: 0.1 } -const PATHS = [ - // Heart - new Path2D( - 'M4.8294,0 C1.83702857,0 0,2.65379464 0,4.61012277 C0,8.84082589 5.27554286,12.500625 9,15 C12.7244571,12.4996875 18,8.84082589 18,4.61012277 C18,2.65363058 16.1638457,0 13.1706,0 C11.4991714,0 10.0707429,1.21490625 9,2.36835938 C7.92822857,1.21478906 6.50088,0 4.8294,0 Z' - ), - // Listens - new Path2D( - 'M9.01215343,0 C4.03768506,0 0,4.14271233 0,9.24657534 L0,13.9315068 C0.0244073147,16.175737 1.82684761,18 4.013172,18 L4.54169274,18 C4.997924,18 5.38282706,17.6050849 5.38282706,17.1369863 L5.38282706,10.6027397 C5.38282706,10.1346411 4.997924,9.73972603 4.54169274,9.73972603 L4.013172,9.73972603 C3.14762075,9.73972603 2.33090336,10.0354192 1.65780365,10.5285699 L1.65780365,9.24657534 C1.65780365,5.10386301 4.95000337,1.7260274 8.98768843,1.7260274 C13.0253735,1.7260274 16.3420863,5.10386301 16.3420863,9.24657534 L16.3420863,10.5285699 C15.6689866,10.0354192 14.8757248,9.73972603 13.9867179,9.73972603 L13.4581972,9.73972603 C13.0019659,9.73972603 12.6170629,10.1346411 12.6170629,10.6027397 L12.6170629,17.1369863 C12.6170629,17.6050849 13.0019659,18 13.4581972,18 L13.9867179,18 C16.1975073,18 17.9765785,16.175737 17.9998899,13.9315068 L17.9998899,9.24657534 C18.0242972,4.14271233 13.9867179,0 9.01224955,0 L9.01215343,0 Z' - ), - // Note - new Path2D( - 'M3,13.0400072 L3,3.61346039 C3,3.16198653 3.28424981,2.76289841 3.70172501,2.62823505 L12.701725,0.0477059646 C13.3456556,-0.160004241 14,0.3365598 14,1.0329313 L14,12.9033651 C14,12.9179063 13.9997087,12.9323773 13.9991318,12.9467722 C13.9997094,12.9644586 14,12.9822021 14,13 C14,14.1045695 12.8807119,15 11.5,15 C10.1192881,15 9,14.1045695 9,13 C9,11.8954305 10.1192881,11 11.5,11 C11.6712329,11 11.838445,11.0137721 12,11.0400072 L12,3.61346039 L5,5.5488572 L5,14.9677884 C5,14.9726204 4.99996783,14.9774447 4.99990371,14.9822611 C4.99996786,14.988168 5,14.994081 5,15 C5,16.1045695 3.88071187,17 2.5,17 C1.11928813,17 0,16.1045695 0,15 C0,13.8954305 1.11928813,13 2.5,13 C2.67123292,13 2.83844503,13.0137721 3,13.0400072 Z' - ), - // Playlists - new Path2D( - 'M5.46563786,16.9245466 C4.92388449,17.5744882 4.02157241,18 3,18 C1.34314575,18 0,16.8807119 0,15.5 C0,14.1192881 1.34314575,13 3,13 C3.35063542,13 3.68722107,13.0501285 4,13.1422548 L4,3.02055066 C4,2.49224061 4.31978104,2.02523181 4.78944063,1.86765013 L10.5394406,0.0558250276 C11.2638626,-0.187235311 12,0.393838806 12,1.20872555 C12,2.01398116 12,2.61792286 12,3.02055066 C12,3.62449236 11.4511634,4.01020322 11,4.12121212 C10.3508668,4.28093157 8.68420009,4.62436591 6,5.15151515 L6,16.0224658 C6,16.5009995 5.80514083,16.7960063 5.46563786,16.9245466 Z M13,6 L17,6 C17.5522847,6 18,6.44771525 18,7 C18,7.55228475 17.5522847,8 17,8 L13,8 C12.4477153,8 12,7.55228475 12,7 C12,6.44771525 12.4477153,6 13,6 Z M11,10 L17,10 C17.5522847,10 18,10.4477153 18,11 C18,11.5522847 17.5522847,12 17,12 L11,12 C10.4477153,12 10,11.5522847 10,11 C10,10.4477153 10.4477153,10 11,10 Z M11,14 L17,14 C17.5522847,14 18,14.4477153 18,15 C18,15.5522847 17.5522847,16 17,16 L11,16 C10.4477153,16 10,15.5522847 10,15 C10,14.4477153 10.4477153,14 11,14 Z' - ) -] - type MusicConfettiProps = { withBackground?: boolean zIndex?: number @@ -48,6 +29,28 @@ export const MusicConfetti = ({ theme, isMobile }: MusicConfettiProps) => { + const PATHS = useMemo( + () => [ + // Heart + new Path2D( + 'M4.8294,0 C1.83702857,0 0,2.65379464 0,4.61012277 C0,8.84082589 5.27554286,12.500625 9,15 C12.7244571,12.4996875 18,8.84082589 18,4.61012277 C18,2.65363058 16.1638457,0 13.1706,0 C11.4991714,0 10.0707429,1.21490625 9,2.36835938 C7.92822857,1.21478906 6.50088,0 4.8294,0 Z' + ), + // Listens + new Path2D( + 'M9.01215343,0 C4.03768506,0 0,4.14271233 0,9.24657534 L0,13.9315068 C0.0244073147,16.175737 1.82684761,18 4.013172,18 L4.54169274,18 C4.997924,18 5.38282706,17.6050849 5.38282706,17.1369863 L5.38282706,10.6027397 C5.38282706,10.1346411 4.997924,9.73972603 4.54169274,9.73972603 L4.013172,9.73972603 C3.14762075,9.73972603 2.33090336,10.0354192 1.65780365,10.5285699 L1.65780365,9.24657534 C1.65780365,5.10386301 4.95000337,1.7260274 8.98768843,1.7260274 C13.0253735,1.7260274 16.3420863,5.10386301 16.3420863,9.24657534 L16.3420863,10.5285699 C15.6689866,10.0354192 14.8757248,9.73972603 13.9867179,9.73972603 L13.4581972,9.73972603 C13.0019659,9.73972603 12.6170629,10.1346411 12.6170629,10.6027397 L12.6170629,17.1369863 C12.6170629,17.6050849 13.0019659,18 13.4581972,18 L13.9867179,18 C16.1975073,18 17.9765785,16.175737 17.9998899,13.9315068 L17.9998899,9.24657534 C18.0242972,4.14271233 13.9867179,0 9.01224955,0 L9.01215343,0 Z' + ), + // Note + new Path2D( + 'M3,13.0400072 L3,3.61346039 C3,3.16198653 3.28424981,2.76289841 3.70172501,2.62823505 L12.701725,0.0477059646 C13.3456556,-0.160004241 14,0.3365598 14,1.0329313 L14,12.9033651 C14,12.9179063 13.9997087,12.9323773 13.9991318,12.9467722 C13.9997094,12.9644586 14,12.9822021 14,13 C14,14.1045695 12.8807119,15 11.5,15 C10.1192881,15 9,14.1045695 9,13 C9,11.8954305 10.1192881,11 11.5,11 C11.6712329,11 11.838445,11.0137721 12,11.0400072 L12,3.61346039 L5,5.5488572 L5,14.9677884 C5,14.9726204 4.99996783,14.9774447 4.99990371,14.9822611 C4.99996786,14.988168 5,14.994081 5,15 C5,16.1045695 3.88071187,17 2.5,17 C1.11928813,17 0,16.1045695 0,15 C0,13.8954305 1.11928813,13 2.5,13 C2.67123292,13 2.83844503,13.0137721 3,13.0400072 Z' + ), + // Playlists + new Path2D( + 'M5.46563786,16.9245466 C4.92388449,17.5744882 4.02157241,18 3,18 C1.34314575,18 0,16.8807119 0,15.5 C0,14.1192881 1.34314575,13 3,13 C3.35063542,13 3.68722107,13.0501285 4,13.1422548 L4,3.02055066 C4,2.49224061 4.31978104,2.02523181 4.78944063,1.86765013 L10.5394406,0.0558250276 C11.2638626,-0.187235311 12,0.393838806 12,1.20872555 C12,2.01398116 12,2.61792286 12,3.02055066 C12,3.62449236 11.4511634,4.01020322 11,4.12121212 C10.3508668,4.28093157 8.68420009,4.62436591 6,5.15151515 L6,16.0224658 C6,16.5009995 5.80514083,16.7960063 5.46563786,16.9245466 Z M13,6 L17,6 C17.5522847,6 18,6.44771525 18,7 C18,7.55228475 17.5522847,8 17,8 L13,8 C12.4477153,8 12,7.55228475 12,7 C12,6.44771525 12.4477153,6 13,6 Z M11,10 L17,10 C17.5522847,10 18,10.4477153 18,11 C18,11.5522847 17.5522847,12 17,12 L11,12 C10.4477153,12 10,11.5522847 10,11 C10,10.4477153 10.4477153,10 11,10 Z M11,14 L17,14 C17.5522847,14 18,14.4477153 18,15 C18,15.5522847 17.5522847,16 17,16 L11,16 C10.4477153,16 10,15.5522847 10,15 C10,14.4477153 10.4477153,14 11,14 Z' + ) + ], + [] + ) + const confettiRef = useRef(null) const [colors, setColors] = useState([ getCurrentThemeColors()['--primary'], diff --git a/packages/web/src/components/feature-flag-override-modal/FeatureFlagOverrideModal.tsx b/packages/web/src/components/feature-flag-override-modal/FeatureFlagOverrideModal.tsx index caa1758c194..a4ddeebed44 100644 --- a/packages/web/src/components/feature-flag-override-modal/FeatureFlagOverrideModal.tsx +++ b/packages/web/src/components/feature-flag-override-modal/FeatureFlagOverrideModal.tsx @@ -29,10 +29,12 @@ const messages = { title: 'Feature Flag Override Settings' } -const getOverrideSetting = (flag: string) => - localStorage.getItem( +const getOverrideSetting = (flag: string) => { + if (typeof localStorage === 'undefined') return null + return localStorage.getItem( `${FEATURE_FLAG_OVERRIDE_KEY}:${flag}` ) as OverrideSetting +} const setOverrideSetting = (flag: string, val: OverrideSetting) => { const flagKey = `${FEATURE_FLAG_OVERRIDE_KEY}:${flag}` diff --git a/packages/web/src/components/lineup/LineupProvider.tsx b/packages/web/src/components/lineup/LineupProvider.tsx index a6223b1368a..68a4956af62 100644 --- a/packages/web/src/components/lineup/LineupProvider.tsx +++ b/packages/web/src/components/lineup/LineupProvider.tsx @@ -66,20 +66,22 @@ const totalTileHeight = { playlist: 350 } +const innerHeight = typeof window !== 'undefined' ? window.innerHeight : 0 + // Load TRACKS_AHEAD x the number of tiles to be displayed on the screen export const getLoadMoreTrackCount = ( variant: LineupVariant, multiplier: number | (() => number) ) => Math.ceil( - (window.innerHeight / totalTileHeight[variant]) * + (innerHeight / totalTileHeight[variant]) * (typeof multiplier === 'function' ? multiplier() : multiplier) ) // Call load more when the user is LOAD_MORE_PAGE_THRESHOLD of the view height // away from the bottom of the scrolling window. const getLoadMoreThreshold = () => - Math.ceil(window.innerHeight * LOAD_MORE_PAGE_THRESHOLD) + Math.ceil(innerHeight * LOAD_MORE_PAGE_THRESHOLD) const shouldLoadMore = ( scrollContainer: HTMLDivElement | null, diff --git a/packages/web/src/components/toast/Toast.tsx b/packages/web/src/components/toast/Toast.tsx index 1dbfa7bc7cd..fb1461c3687 100644 --- a/packages/web/src/components/toast/Toast.tsx +++ b/packages/web/src/components/toast/Toast.tsx @@ -122,13 +122,17 @@ class Toast extends PureComponent { triggerNode.parentNode as HTMLElement break case MountPlacement.PAGE: { - const page = document.getElementById('page') + const page = + typeof document !== 'undefined' && document.getElementById('page') if (page) popupContainer = () => page || undefined break } case MountPlacement.BODY: default: - popupContainer = () => document.body as HTMLElement + popupContainer = + typeof document !== 'undefined' + ? () => document.body as HTMLElement + : undefined } return ( diff --git a/packages/web/src/utils/clipboardUtil.ts b/packages/web/src/utils/clipboardUtil.ts index 27b626c0272..a38ddd685ff 100644 --- a/packages/web/src/utils/clipboardUtil.ts +++ b/packages/web/src/utils/clipboardUtil.ts @@ -37,6 +37,8 @@ export const copyToClipboard = (str: string) => { * The protocol will change depending on the context (electron vs. mobile vs. web) */ export const getCopyableLink = (link: string) => { + if (typeof window === 'undefined') return link + const protocol = window.location.protocol const hostname = window.location.host // host instead of hostname to work with ports besides 80 From dc64371b0270b929b2d4586272b3e75a1d5b23f0 Mon Sep 17 00:00:00 2001 From: sliptype Date: Thu, 30 Nov 2023 15:58:17 -0600 Subject: [PATCH 11/74] Get hydration working --- packages/common/src/models/SsrPageProps.ts | 3 + packages/common/src/models/index.ts | 1 + .../common/src/store/cache/tracks/reducer.ts | 50 +++++- .../common/src/store/cache/users/reducer.ts | 57 ++++++- .../common/src/store/pages/track/reducer.ts | 21 ++- packages/common/src/store/reducers.ts | 10 +- packages/stems/src/components/ClientOnly.tsx | 18 +++ packages/stems/src/components/Popup/Popup.tsx | 97 ++++++------ .../src/components/Scrollbar/Scrollbar.tsx | 14 +- packages/web/.eslintrc.js | 3 +- packages/web/src/app/AppProviders.tsx | 75 ++++----- packages/web/src/app/AudiusQueryProvider.tsx | 27 ++-- packages/web/src/app/ReduxProvider.tsx | 35 +++++ packages/web/src/app/web-player/WebPlayer.jsx | 10 +- .../cache/tracks/utils/retrieveTracks.ts | 3 +- .../src/components/nav/desktop/LeftNav.tsx | 13 +- .../components/page/{Page.jsx => Page.tsx} | 147 ++++++++++-------- .../src/components/track/GiantTrackTile.tsx | 16 +- .../pages/track-page/TrackPageProvider.tsx | 9 +- .../components/desktop/TrackPage.tsx | 1 + .../web/src/pages/visualizer/Visualizer.tsx | 2 - packages/web/src/ssr/SsrContext.tsx | 8 +- packages/web/src/ssr/SsrRoot.tsx | 13 -- packages/web/src/ssr/WebPlayerSkeleton.tsx | 43 ----- packages/web/src/ssr/_default.page.client.tsx | 36 +++-- packages/web/src/ssr/_default.page.server.tsx | 35 +++-- packages/web/src/store/configureStore.ts | 103 ++++++------ packages/web/src/store/reducers.ts | 13 +- 28 files changed, 504 insertions(+), 359 deletions(-) create mode 100644 packages/common/src/models/SsrPageProps.ts create mode 100644 packages/stems/src/components/ClientOnly.tsx create mode 100644 packages/web/src/app/ReduxProvider.tsx rename packages/web/src/components/page/{Page.jsx => Page.tsx} (63%) delete mode 100644 packages/web/src/ssr/SsrRoot.tsx delete mode 100644 packages/web/src/ssr/WebPlayerSkeleton.tsx diff --git a/packages/common/src/models/SsrPageProps.ts b/packages/common/src/models/SsrPageProps.ts new file mode 100644 index 00000000000..36cb77fe018 --- /dev/null +++ b/packages/common/src/models/SsrPageProps.ts @@ -0,0 +1,3 @@ +import { full as FullSdk } from '@audius/sdk' + +export type SsrPageProps = { track?: FullSdk.TrackFull } diff --git a/packages/common/src/models/index.ts b/packages/common/src/models/index.ts index d1beb6e91ab..511c1575876 100644 --- a/packages/common/src/models/index.ts +++ b/packages/common/src/models/index.ts @@ -25,6 +25,7 @@ export * from './PlaylistLibrary' export * from './Repost' export * from './Services' export * from './SmartCollectionVariant' +export * from './SsrPageProps' export * from './Status' export * from './Stems' export * from './Theme' diff --git a/packages/common/src/store/cache/tracks/reducer.ts b/packages/common/src/store/cache/tracks/reducer.ts index 736437c9edf..7b50bb9ead2 100644 --- a/packages/common/src/store/cache/tracks/reducer.ts +++ b/packages/common/src/store/cache/tracks/reducer.ts @@ -1,8 +1,13 @@ +import snakecaseKeys from 'snakecase-keys' + import { Cache } from 'models/Cache' import { ID } from 'models/Identifiers' import { Kind } from 'models/Kind' +import { SsrPageProps } from 'models/SsrPageProps' import { Track } from 'models/Track' +import { makeTrack } from 'services/audius-api-client/ResponseAdapter' import { initialCacheState } from 'store/cache/reducer' +import { makeUid } from 'utils/uid' import { AddEntriesAction, @@ -72,10 +77,47 @@ const actionsMap = { } } -const reducer = (state = initialState, action: AddSuccededAction) => { - const matchingReduceFunction = actionsMap[action.type] - if (!matchingReduceFunction) return state - return matchingReduceFunction(state, action) +const buildInitialState = (ssrPageProps?: SsrPageProps) => { + // If we have preloaded data from the server, populate the initial + // cache state with it + if (ssrPageProps?.track) { + // @ts-ignore + const track = makeTrack(snakecaseKeys(ssrPageProps.track)) + if (!track) return initialState + + const id = track.track_id + const uid = makeUid(Kind.TRACKS, id) + + return { + ...initialState, + entries: { + [id]: { + metadata: track, + _timestamp: Date.now() + } + }, + uids: { + [uid]: track.track_id + }, + statuses: { + [id]: 'SUCCESS' + } + } + } + return initialState } +const reducer = + (ssrPageProps: SsrPageProps) => + (state: TracksCacheState, action: AddSuccededAction) => { + if (!state) { + // @ts-ignore + state = buildInitialState(ssrPageProps) + } + + const matchingReduceFunction = actionsMap[action.type] + if (!matchingReduceFunction) return state + return matchingReduceFunction(state, action) + } + export default reducer diff --git a/packages/common/src/store/cache/users/reducer.ts b/packages/common/src/store/cache/users/reducer.ts index e12a52718a3..c6bbdb876dc 100644 --- a/packages/common/src/store/cache/users/reducer.ts +++ b/packages/common/src/store/cache/users/reducer.ts @@ -1,8 +1,13 @@ +import snakecaseKeys from 'snakecase-keys' + import { Cache } from 'models/Cache' import { ID } from 'models/Identifiers' import { Kind } from 'models/Kind' +import { SsrPageProps } from 'models/SsrPageProps' import { User } from 'models/User' +import { makeUser } from 'services/audius-api-client/ResponseAdapter' import { initialCacheState } from 'store/cache/reducer' +import { makeUid } from 'utils/uid' import { AddEntriesAction, @@ -57,13 +62,51 @@ const actionsMap = { return addEntries(state, matchingEntries) } } -const reducer = ( - state: UsersCacheState = initialState, - action: AddSuccededAction -) => { - const matchingReduceFunction = actionsMap[action.type] - if (!matchingReduceFunction) return state - return matchingReduceFunction(state, action) + +// TODO: Generalize this +const buildInitialState = (ssrPageProps?: SsrPageProps) => { + // TODO: support user profile page. Only track page supported for now. + + // If we have preloaded data from the server, populate the initial + // cache state with it + if (ssrPageProps?.track) { + // @ts-ignore + const user = makeUser(snakecaseKeys(ssrPageProps.track.user)) + if (!user) return initialState + + const id = user.user_id + const uid = makeUid(Kind.USERS, id) + + return { + ...initialState, + entries: { + [id]: { + metadata: user, + _timestamp: Date.now() + } + }, + uids: { + [uid]: user.user_id + }, + statuses: { + [id]: 'SUCCESS' + } + } + } + return initialState } +const reducer = + (ssrPageProps: SsrPageProps) => + (state: UsersCacheState, action: AddSuccededAction) => { + if (!state) { + // @ts-ignore + state = buildInitialState(ssrPageProps) + } + + const matchingReduceFunction = actionsMap[action.type] + if (!matchingReduceFunction) return state + return matchingReduceFunction(state, action) + } + export default reducer diff --git a/packages/common/src/store/pages/track/reducer.ts b/packages/common/src/store/pages/track/reducer.ts index b72612c562b..50b0a7adcae 100644 --- a/packages/common/src/store/pages/track/reducer.ts +++ b/packages/common/src/store/pages/track/reducer.ts @@ -1,9 +1,12 @@ // @ts-nocheck // TODO(nkang) - convert to TS + +import { SsrPageProps } from 'models/SsrPageProps' import { asLineup } from 'store/lineup/reducer' import tracksReducer, { initialState as initialLineupState } from 'store/pages/track/lineup/reducer' +import { decodeHashId } from 'utils/hashIds' import { SET_TRACK_ID, @@ -71,7 +74,23 @@ const actionsMap = { const tracksLineupReducer = asLineup(tracksPrefix, tracksReducer) -const reducer = (state = initialState, action) => { +const buildInitialState = (ssrPageProps?: SsrPageProps) => { + // If we have preloaded data from the server, populate the initial + // cache state with it + if (ssrPageProps?.track) { + return { + ...initialState, + trackId: decodeHashId(ssrPageProps.track.id) + } + } + return initialState +} + +const reducer = (ssrPageProps?: SsrPageProps) => (state, action) => { + if (!state) { + state = buildInitialState(ssrPageProps) + } + const tracks = tracksLineupReducer(state.tracks, action) if (tracks !== state.tracks) return { ...state, tracks } diff --git a/packages/common/src/store/reducers.ts b/packages/common/src/store/reducers.ts index ede79358f0f..5dd7c2242db 100644 --- a/packages/common/src/store/reducers.ts +++ b/packages/common/src/store/reducers.ts @@ -1,6 +1,8 @@ import { combineReducers } from 'redux' import type { Storage } from 'redux-persist' +import { SsrPageProps } from 'models/SsrPageProps' + import apiReducer from '../api/reducer' import { Kind } from '../models' @@ -136,7 +138,7 @@ import wallet from './wallet/slice' * A function that creates common reducers. * @returns an object of all reducers to be used with `combineReducers` */ -export const reducers = (storage: Storage) => ({ +export const reducers = (storage: Storage, ssrPageProps?: SsrPageProps) => ({ account, api: apiReducer, @@ -154,10 +156,10 @@ export const reducers = (storage: Storage) => ({ collections: asCache(collectionsReducer, Kind.COLLECTIONS), // TODO: Fix type error // @ts-ignore - tracks: asCache(tracksReducer, Kind.TRACKS), + tracks: asCache(tracksReducer(ssrPageProps), Kind.TRACKS), // TODO: Fix type error // @ts-ignore - users: asCache(usersReducer, Kind.USERS), + users: asCache(usersReducer(ssrPageProps), Kind.USERS), savedCollections: savedCollectionsReducer, @@ -236,7 +238,7 @@ export const reducers = (storage: Storage) => ({ savedPage: persistedSavePageReducer(storage), searchResults, tokenDashboard: tokenDashboardSlice.reducer, - track, + track: track(ssrPageProps), trending, trendingPlaylists, trendingUnderground, diff --git a/packages/stems/src/components/ClientOnly.tsx b/packages/stems/src/components/ClientOnly.tsx new file mode 100644 index 00000000000..55323e9b9ca --- /dev/null +++ b/packages/stems/src/components/ClientOnly.tsx @@ -0,0 +1,18 @@ +import { ReactNode, Suspense, useEffect, useState } from 'react' + +type ClientOnlyProps = { + children: () => ReactNode + fallback?: ReactNode +} + +export const ClientOnly = (props: ClientOnlyProps) => { + const { children, fallback } = props + + const [clientChildren, setClientChildren] = useState(() => () => fallback) + + useEffect(() => { + setClientChildren(() => children) + }, []) + + return {clientChildren()} +} diff --git a/packages/stems/src/components/Popup/Popup.tsx b/packages/stems/src/components/Popup/Popup.tsx index 05a2a03dfee..702db91dcfe 100644 --- a/packages/stems/src/components/Popup/Popup.tsx +++ b/packages/stems/src/components/Popup/Popup.tsx @@ -13,6 +13,7 @@ import ReactDOM from 'react-dom' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web import { useTransition, animated } from 'react-spring' +import { ClientOnly } from 'components/ClientOnly' import { IconButton } from 'components/IconButton' import { IconRemove } from 'components/Icons' import { useClickOutside } from 'hooks/useClickOutside' @@ -416,52 +417,54 @@ export const Popup = forwardRef(function Popup( } }, [dismissOnMouseLeave, onClose]) - return typeof document !== 'undefined' ? ( - <> - {/* Portal the popup out of the dom structure so that it has a separate stacking context */} - {ReactDOM.createPortal( -
- {transitions.map(({ item, key, props }) => - item ? ( - - {showHeader && ( -
- {hideCloseButton ? null : ( - } - /> - )} -
- {title} + // Portal the popup out of the dom structure so that it has a separate stacking context + return ( + + {() => + ReactDOM.createPortal( +
+ {transitions.map(({ item, key, props }) => + item ? ( + + {showHeader && ( +
+ {hideCloseButton ? null : ( + } + /> + )} +
+ {title} +
-
- )} - {children} - - ) : null - )} -
, - document.body - )} - - ) : null + )} + {children} + + ) : null + )} +
, + document.body + ) + } + + ) }) diff --git a/packages/stems/src/components/Scrollbar/Scrollbar.tsx b/packages/stems/src/components/Scrollbar/Scrollbar.tsx index dbf63308927..89a70754c53 100644 --- a/packages/stems/src/components/Scrollbar/Scrollbar.tsx +++ b/packages/stems/src/components/Scrollbar/Scrollbar.tsx @@ -1,8 +1,15 @@ -import { useEffect, useRef, useMemo, forwardRef, Ref, useCallback } from 'react' +import { + useEffect, + useRef, + useMemo, + forwardRef, + Ref, + useCallback, + useId +} from 'react' import { ResizeObserver } from '@juggle/resize-observer' import cn from 'classnames' -import { uniqueId } from 'lodash' import PerfectScrollbar from 'react-perfect-scrollbar' import useMeasure from 'react-use-measure' @@ -24,7 +31,8 @@ export const Scrollbar = forwardRef( // useMeasure ref is required for infinite scrolling to work const [ref] = useMeasure({ polyfill: ResizeObserver }) const timerRef = useRef(null) - const elementId = useMemo(() => id || uniqueId('scrollbar-'), [id]) + const reactId = useId() + const elementId = useMemo(() => id || reactId, [id, reactId]) useEffect(() => { return () => { diff --git a/packages/web/.eslintrc.js b/packages/web/.eslintrc.js index 84e1e8ed4c8..54d662558c8 100644 --- a/packages/web/.eslintrc.js +++ b/packages/web/.eslintrc.js @@ -25,7 +25,8 @@ module.exports = { ['types', './src/types'], ['utils', './src/utils'], ['workers', './src/workers'], - ['pages', './src/pages'] + ['pages', './src/pages'], + ['ssr', './src/ssr'] ], extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'] } diff --git a/packages/web/src/app/AppProviders.tsx b/packages/web/src/app/AppProviders.tsx index 3963599ae28..ce4554cc576 100644 --- a/packages/web/src/app/AppProviders.tsx +++ b/packages/web/src/app/AppProviders.tsx @@ -1,23 +1,20 @@ -import { ReactNode } from 'react' +import { ReactNode, Suspense } from 'react' import { ConnectedRouter } from 'connected-react-router' -import { Provider } from 'react-redux' import { LastLocationProvider } from 'react-router-last-location' -import { PersistGate } from 'redux-persist/integration/react' import { RouterContextProvider } from 'components/animated-switch/RouterContextProvider' import { HeaderContextProvider } from 'components/header/mobile/HeaderContextProvider' import { NavProvider } from 'components/nav/store/context' import { ScrollProvider } from 'components/scroll-provider/ScrollProvider' import { ToastContextProvider } from 'components/toast/ToastContext' -import { persistor, store } from 'store/configureStore' import history from 'utils/history' import { MainContentContextProvider } from '../pages/MainContentContext' -import { useSsrContext } from '../ssr/SsrContext' import { AppContextProvider } from './AppContextProvider' import { AudiusQueryProvider } from './AudiusQueryProvider' +import { ReduxProvider } from './ReduxProvider' import { ThemeProvider } from './ThemeProvider' import { TrpcProvider } from './TrpcProvider' @@ -25,48 +22,34 @@ type AppContextProps = { children: ReactNode } -const Persist = ({ children }: { children: ReactNode }) => ( - - {children} - -) - -const Wrapper = ({ children }: { children: ReactNode }) => <>{children} - export const AppProviders = ({ children }: AppContextProps) => { - const { isServerSide } = useSsrContext() - - const ReduxPersistProvider = isServerSide ? Wrapper : Persist - return ( - - - - - - - - - - - - - - - {children} - - - - - - - - - - - - - - + + + + + + + + + + + + + + {children} + + + + + + + + + + + + + ) } diff --git a/packages/web/src/app/AudiusQueryProvider.tsx b/packages/web/src/app/AudiusQueryProvider.tsx index 93ec861b4dc..626aec1b765 100644 --- a/packages/web/src/app/AudiusQueryProvider.tsx +++ b/packages/web/src/app/AudiusQueryProvider.tsx @@ -1,34 +1,35 @@ import { ReactNode } from 'react' import { AudiusQueryContext } from '@audius/common' +import { useDispatch } from 'react-redux' import { apiClient } from 'services/audius-api-client' import { audiusBackendInstance } from 'services/audius-backend/audius-backend-instance' import { audiusSdk } from 'services/audius-sdk' import { env } from 'services/env' import { remoteConfigInstance } from 'services/remote-config/remote-config-instance' -import { store } from 'store/configureStore' import { reportToSentry } from 'store/errors/reportToSentry' type AudiusQueryProviderProps = { children: ReactNode } -const audiusQueryContext = { - apiClient, - audiusBackend: audiusBackendInstance, - audiusSdk, - dispatch: store.dispatch, - reportToSentry, - env, - fetch, - remoteConfigInstance -} - export const AudiusQueryProvider = (props: AudiusQueryProviderProps) => { const { children } = props + const dispatch = useDispatch() return ( - + {children} ) diff --git a/packages/web/src/app/ReduxProvider.tsx b/packages/web/src/app/ReduxProvider.tsx new file mode 100644 index 00000000000..014bd7fa23c --- /dev/null +++ b/packages/web/src/app/ReduxProvider.tsx @@ -0,0 +1,35 @@ +import { ReactNode } from 'react' + +import { Provider } from 'react-redux' +import { persistStore } from 'redux-persist' +import { PersistGate } from 'redux-persist/integration/react' + +import { configureStore } from 'store/configureStore' +import logger from 'utils/logger' + +import { useSsrContext } from '../ssr/SsrContext' + +let store: ReturnType +let persistor: ReturnType + +// TODO: Figure out persist gate? Do we need to block on loading from localstorage? +export const ReduxProvider = ({ children }: { children: ReactNode }) => { + const { isServerSide, pageProps } = useSsrContext() + + if (!store) { + store = configureStore(pageProps) + persistor = persistStore(store) + + // Mount store to window for easy access + if (typeof window !== 'undefined') { + window.store = store + } + + // Set up logger on store + logger(store) + } + + return store && persistor ? ( + {children} + ) : null +} diff --git a/packages/web/src/app/web-player/WebPlayer.jsx b/packages/web/src/app/web-player/WebPlayer.jsx index 7086182df38..01fa1f80462 100644 --- a/packages/web/src/app/web-player/WebPlayer.jsx +++ b/packages/web/src/app/web-player/WebPlayer.jsx @@ -194,7 +194,6 @@ const { getHasAccount, getAccountStatus, getUserId, getUserHandle } = const ConnectedMusicConfetti = lazy(() => import('components/music-confetti/ConnectedMusicConfetti') ) - const SignOn = lazy(() => import('pages/sign-on/SignOn')) const UploadPage = lazy(() => import('pages/upload-page')) @@ -970,14 +969,11 @@ class WebPlayer extends Component {
- - - + - - - + + {/* Non-mobile */} {!isMobileClient ? : null} {!isMobileClient ? : null} diff --git a/packages/web/src/common/store/cache/tracks/utils/retrieveTracks.ts b/packages/web/src/common/store/cache/tracks/utils/retrieveTracks.ts index 83e7091442e..95c7ae5cf38 100644 --- a/packages/web/src/common/store/cache/tracks/utils/retrieveTracks.ts +++ b/packages/web/src/common/store/cache/tracks/utils/retrieveTracks.ts @@ -86,7 +86,8 @@ export function* retrieveTrackByHandleAndSlug({ idField: 'track_id', forceRetrieveFromSource, shouldSetLoading: true, - deleteExistingEntry: false, + // TODO: only deleteExistingEntry on initial page load + deleteExistingEntry: true, getEntriesTimestamp: function* (ids: ID[]) { const selected = yield* select( (state: CommonState, ids: ID[]) => diff --git a/packages/web/src/components/nav/desktop/LeftNav.tsx b/packages/web/src/components/nav/desktop/LeftNav.tsx index 03816282399..5ad81a24b57 100644 --- a/packages/web/src/components/nav/desktop/LeftNav.tsx +++ b/packages/web/src/components/nav/desktop/LeftNav.tsx @@ -19,6 +19,7 @@ import { Dispatch } from 'redux' import { make, useRecord } from 'common/store/analytics/actions' import * as signOnActions from 'common/store/pages/signon/actions' +import { ClientOnly } from 'components/client-only/ClientOnly' import { DragAutoscroller } from 'components/drag-autoscroller/DragAutoscroller' import ConnectedProfileCompletionPane from 'components/profile-progress/ConnectedProfileCompletionPane' import { selectDraggingKind } from 'store/dragndrop/slice' @@ -189,11 +190,13 @@ const LeftNav = (props: NavColumnProps) => {
-
- {profileCompletionMeter} - - -
+ +
+ {profileCompletionMeter} + + +
+
) } diff --git a/packages/web/src/components/page/Page.jsx b/packages/web/src/components/page/Page.tsx similarity index 63% rename from packages/web/src/components/page/Page.jsx rename to packages/web/src/components/page/Page.tsx index b55612d3f9f..a7aa0a3d1c5 100644 --- a/packages/web/src/components/page/Page.jsx +++ b/packages/web/src/components/page/Page.tsx @@ -1,10 +1,19 @@ -import { cloneElement, useRef, useState, useEffect, useCallback } from 'react' - +import { + ReactNode, + cloneElement, + useRef, + useState, + useEffect, + useCallback, + MutableRefObject +} from 'react' + +import { Nullable } from '@audius/common' import cn from 'classnames' -import PropTypes from 'prop-types' import { Helmet } from 'react-helmet' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web import { Spring } from 'react-spring/renderprops.cjs' +// @ts-ignore import calcScrollbarWidth from 'scrollbar-width' import SearchBar from 'components/search-bar/ConnectedSearchBar' @@ -21,7 +30,13 @@ const HEADER_MARGIN_PX = 32 const MIN_GUTTER_WIDTH = 20 // Responsible for positioning the header -const HeaderContainer = ({ header, containerRef, showSearch }) => { +type HeaderContainerProps = Pick & { + containerRef: (element: Nullable) => void +} + +const HeaderContainer = (props: HeaderContainerProps) => { + const { header, containerRef, showSearch } = props + // Need to offset the header on the right side // the width of the scrollbar. const [scrollBarWidth, setScrollbarWidth] = useState(0) @@ -50,7 +65,7 @@ const HeaderContainer = ({ header, containerRef, showSearch }) => { setIsChromeOrSafari(chromeOrSafari) }, []) - const headerContainerRef = useRef() + const headerContainerRef = useRef(null) return (
{ : 'linear-gradient(180deg, var(--page-header-gradient-1) 0%, var(--page-header-gradient-1) 40%, var(--page-header-gradient-2-alt) 85%)' }} > - {cloneElement(header, { + {cloneElement(header as any, { isChromeOrSafari, scrollBarWidth, headerContainerRef, @@ -88,10 +103,48 @@ const HeaderContainer = ({ header, containerRef, showSearch }) => { ) } -export const Page = (props) => { +type PageProps = { + title?: string + description?: string + canonicalUrl?: string + structuredData?: object + variant?: 'insert' | 'flush' + size?: 'medium' | 'large' + containerRef?: MutableRefObject + contentClassName?: string + containerClassName?: string + fromOpacity?: number + fadeDuration?: number + header?: ReactNode + + // There are some pages which don't have a fixed header but still display + // a search bar that scrolls with the page. + scrollableSearch?: boolean + children?: ReactNode + showSearch?: boolean +} + +export const Page = (props: PageProps) => { + const { + title, + description, + structuredData, + variant = 'inset', + size = 'medium', + containerRef, + contentClassName, + containerClassName, + fromOpacity = 0.2, + fadeDuration = 200, + header, + scrollableSearch = false, + children, + showSearch = true + } = props + const [headerHeight, setHeaderHeight] = useState(0) - const calculateHeaderHeight = (element) => { + const calculateHeaderHeight = (element: Nullable) => { if (element) { setHeaderHeight(element.offsetHeight) } @@ -99,69 +152,69 @@ export const Page = (props) => { return ( {(animProps) => (
- {props.title ? ( - {`${props.title} ${messages.dotAudius}`} + {title ? ( + {`${title} ${messages.dotAudius}`} ) : ( {messages.audius} )} - {props.description ? ( - + {description ? ( + ) : null} {/* TODO: re-enable once we fix redirects and casing of canonicalUrls */} - {/* {props.canonicalUrl && ( - + {/* {canonicalUrl && ( + )} */} - {props.structuredData && ( + {structuredData && ( )} - {props.header && ( + {header && ( )}
{/* Set an id so that nested components can mount in relation to page if needed, e.g. fixed menu popups. */}
- {props.children} + {children}
- {props.scrollableSearch && ( + {scrollableSearch && (
@@ -172,32 +225,4 @@ export const Page = (props) => { ) } -Page.propTypes = { - title: PropTypes.string, - description: PropTypes.string, - canonicalUrl: PropTypes.string, - structuredData: PropTypes.object, - variant: PropTypes.oneOf(['inset', 'flush']), - size: PropTypes.oneOf(['medium', 'large']), - containerRef: PropTypes.node, - contentClassName: PropTypes.string, - containerClassName: PropTypes.string, - fadeDuration: PropTypes.number, - header: PropTypes.node, - - // There are some pages which don't have a fixed header but still display - // a search bar that scrolls with the page. - scrollableSearch: PropTypes.bool, - children: PropTypes.node, - showSearch: PropTypes.bool -} - -Page.defaultProps = { - variant: 'inset', - size: 'medium', - fadeDuration: 200, - scrollableSearch: false, - showSearch: true -} - export default Page diff --git a/packages/web/src/components/track/GiantTrackTile.tsx b/packages/web/src/components/track/GiantTrackTile.tsx index 9d167477ea3..543cf1adbdb 100644 --- a/packages/web/src/components/track/GiantTrackTile.tsx +++ b/packages/web/src/components/track/GiantTrackTile.tsx @@ -169,7 +169,7 @@ export const GiantTrackTile = ({ trackTitle, userId }: GiantTrackTileProps) => { - const [artworkLoading, setArtworkLoading] = useState(true) + const [artworkLoading, setArtworkLoading] = useState(false) const onArtworkLoad = useCallback( () => setArtworkLoading(false), [setArtworkLoading] @@ -495,14 +495,12 @@ export const GiantTrackTile = ({ elevation='mid' >
- - - +
{renderCardTitle(cn(fadeIn))} diff --git a/packages/web/src/pages/track-page/TrackPageProvider.tsx b/packages/web/src/pages/track-page/TrackPageProvider.tsx index 18a20bfc32b..992a04fdf5c 100644 --- a/packages/web/src/pages/track-page/TrackPageProvider.tsx +++ b/packages/web/src/pages/track-page/TrackPageProvider.tsx @@ -542,7 +542,14 @@ function mapDispatchToProps(dispatch: Dispatch) { canBeUnlisted: boolean ) => dispatch( - trackPageActions.fetchTrack(trackId, slug, ownerHandle, canBeUnlisted) + trackPageActions.fetchTrack( + trackId, + slug, + ownerHandle, + canBeUnlisted, + // TODO: only force retrieve on initial load + true + ) ), setTrackId: (trackId: number) => dispatch(trackPageActions.setTrackId(trackId)), diff --git a/packages/web/src/pages/track-page/components/desktop/TrackPage.tsx b/packages/web/src/pages/track-page/components/desktop/TrackPage.tsx index fd6fc0371ee..0585716de13 100644 --- a/packages/web/src/pages/track-page/components/desktop/TrackPage.tsx +++ b/packages/web/src/pages/track-page/components/desktop/TrackPage.tsx @@ -206,6 +206,7 @@ const TrackPage = ({ structuredData={structuredData} variant='flush' scrollableSearch + fromOpacity={1} >
import('./VisualizerProvider')) type VisualizerProps = {} & ReturnType & diff --git a/packages/web/src/ssr/SsrContext.tsx b/packages/web/src/ssr/SsrContext.tsx index f2426a73559..f95607a6ba9 100644 --- a/packages/web/src/ssr/SsrContext.tsx +++ b/packages/web/src/ssr/SsrContext.tsx @@ -1,10 +1,11 @@ import { createContext, memo, useContext } from 'react' -import { Nullable } from '@audius/common' +import { Nullable, SsrPageProps } from '@audius/common' -type SsrContextType = { +export type SsrContextType = { path: Nullable isServerSide: boolean + pageProps: SsrPageProps } export const useSsrContext = () => { @@ -13,7 +14,8 @@ export const useSsrContext = () => { export const SsrContext = createContext({ path: null, - isServerSide: true + isServerSide: true, + pageProps: {} } as SsrContextType) export const SsrContextProvider = memo( diff --git a/packages/web/src/ssr/SsrRoot.tsx b/packages/web/src/ssr/SsrRoot.tsx deleted file mode 100644 index 8b13df00ac9..00000000000 --- a/packages/web/src/ssr/SsrRoot.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { ReactNode } from 'react' - -import { ClientOnly } from 'components/client-only/ClientOnly' - -import { Root } from '../Root' - -export const SsrRoot = ({ children }: { children: ReactNode }) => { - return ( - - - - ) -} diff --git a/packages/web/src/ssr/WebPlayerSkeleton.tsx b/packages/web/src/ssr/WebPlayerSkeleton.tsx deleted file mode 100644 index 89d16b81304..00000000000 --- a/packages/web/src/ssr/WebPlayerSkeleton.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react' - -import '../index.css' - -import cn from 'classnames' - -import AudiusLogoHorizontal from 'assets/img/audiusLogoHorizontal.svg' -import navStyles from 'components/nav/Navigator.module.css' -import leftNavStyles from 'components/nav/desktop/LeftNav.module.css' -import navHeaderStyles from 'components/nav/desktop/NavHeader.module.css' -import { HOME_PAGE } from 'utils/route' - -import styles from '../app/web-player/WebPlayer.module.css' - -const messages = { - homeLink: 'Go to Home' -} - -// TODO: mobile -// TODO: convert to emotion -export function WebPlayerSkeleton({ children }) { - return ( - -
-
-
- -
-
- {children} -
- {/* playbar */} -
-
-
- ) -} diff --git a/packages/web/src/ssr/_default.page.client.tsx b/packages/web/src/ssr/_default.page.client.tsx index b4ba425cb7c..c7573537c8b 100644 --- a/packages/web/src/ssr/_default.page.client.tsx +++ b/packages/web/src/ssr/_default.page.client.tsx @@ -1,22 +1,28 @@ -import { Track } from '@audius/sdk' +import { full as FullSdk } from '@audius/sdk' import { hydrateRoot } from 'react-dom/client' import { PageContextClient } from 'vike/types' -import { SsrRoot } from './SsrRoot' -import { WebPlayerSkeleton } from './WebPlayerSkeleton' +import { Root } from '../Root' + +import { SsrContextProvider } from './SsrContext' + +// Set this to false to turn off client hydration +// Useful for testing the SSR output +const HYDRATE_CLIENT = true -// TODO: test hydrate vs render -// TODO: can render skeleton on client and hydrate, then render full app export async function render( - pageContext: PageContextClient & { pageProps: { track: Track } } + pageContext: PageContextClient & { pageProps: { track: FullSdk.TrackFull } } ) { - const { Page, pageProps } = pageContext - hydrateRoot( - document.getElementById('page-view'), - - - - - - ) + const { Page, pageProps, urlPathname } = pageContext + + if (HYDRATE_CLIENT) { + hydrateRoot( + document.getElementById('root'), + + + + ) + } } diff --git a/packages/web/src/ssr/_default.page.server.tsx b/packages/web/src/ssr/_default.page.server.tsx index bae41baf4b5..be36f181c09 100644 --- a/packages/web/src/ssr/_default.page.server.tsx +++ b/packages/web/src/ssr/_default.page.server.tsx @@ -1,37 +1,46 @@ -import { Track } from '@audius/sdk' +import { SsrPageProps } from '@audius/common' import ReactDOMServer from 'react-dom/server' import { escapeInject, dangerouslySkipEscape } from 'vike/server' import { PageContextServer } from 'vike/types' import history from 'utils/history' +import indexHtml from '../../index.html?raw' import { Root } from '../Root' import { SsrContextProvider } from './SsrContext' -import { SsrRoot } from './SsrRoot' -import { WebPlayerSkeleton } from './WebPlayerSkeleton' export const passToClient = ['pageProps', 'urlPathname'] export function render( - pageContext: PageContextServer & { pageProps: { track: Track } } + pageContext: PageContextServer & { pageProps: SsrPageProps } ) { const { Page, pageProps, urlPathname } = pageContext + // TODO: Shared history instance is causing page not to change on new route history.replace(urlPathname) const pageHtml = ReactDOMServer.renderToString( - + ) - // TODO: this needs to be index.html - // TODO: env vars? - return escapeInject` - - -
${dangerouslySkipEscape(pageHtml)}
- - ` + const pattern = /%(\S+?)%/g + const env = process.env + + // Replace all %VITE_*% with the corresponding environment variable + const html = indexHtml + .replace(pattern, (text: string, key) => { + if (key in env) { + return env[key] ?? text + } + // TODO: throw warning + return text + }) + .replace(`
`, `
${pageHtml}
`) + + return escapeInject`${dangerouslySkipEscape(html)}` } diff --git a/packages/web/src/store/configureStore.ts b/packages/web/src/store/configureStore.ts index 9614a43bea9..48411b23775 100644 --- a/packages/web/src/store/configureStore.ts +++ b/packages/web/src/store/configureStore.ts @@ -1,9 +1,9 @@ import { chatMiddleware, ErrorLevel, Name } from '@audius/common' +import { SsrPageProps } from '@audius/common/dist/models/SsrPageProps' import { composeWithDevToolsLogOnlyInProduction } from '@redux-devtools/extension' import { configureScope, addBreadcrumb } from '@sentry/browser' import { routerMiddleware } from 'connected-react-router' import { createStore, applyMiddleware, Action, Store } from 'redux' -import { persistStore } from 'redux-persist' import createSagaMiddleware from 'redux-saga' import createSentryMiddleware from 'redux-sentry-middleware' import thunk from 'redux-thunk' @@ -15,7 +15,6 @@ import { reportToSentry } from 'store/errors/reportToSentry' import createRootReducer from 'store/reducers' import rootSaga from 'store/sagas' import history from 'utils/history' -import logger from 'utils/logger' import { storeContext } from './storeContext' import { AppState } from './types' @@ -26,36 +25,8 @@ declare global { } } -type RootState = ReturnType - -const onSagaError = ( - error: Error, - errorInfo: { - sagaStack: string - } -) => { - console.error( - `Caught saga error: ${error} ${JSON.stringify(errorInfo, null, 4)}` - ) - store.dispatch( - errorActions.handleError({ - name: 'Caught Saga Error', - message: error.message, - shouldRedirect: true - }) - ) - const additionalInfo = { - ...errorInfo, - route: window.location.pathname - } - - reportToSentry({ - level: ErrorLevel.Fatal, - error, - additionalInfo - }) - amplitudeTrack(Name.ERROR_PAGE, additionalInfo) -} +export type StoreType = ReturnType +type RootState = ReturnType // Can't send up the entire Redux state b/c it's too fat // for Sentry to handle, and there is sensitive data @@ -121,27 +92,58 @@ const sentryMiddleware = createSentryMiddleware( } ) -const sagaMiddleware = createSagaMiddleware({ - onError: onSagaError, - context: storeContext -}) +export const configureStore = (ssrPageProps?: SsrPageProps) => { + const onSagaError = ( + error: Error, + errorInfo: { + sagaStack: string + } + ) => { + console.error( + `Caught saga error: ${error} ${JSON.stringify(errorInfo, null, 4)}` + ) + store.dispatch( + errorActions.handleError({ + name: 'Caught Saga Error', + message: error.message, + shouldRedirect: true + }) + ) + const additionalInfo = { + ...errorInfo, + route: window.location.pathname + } -const middlewares = applyMiddleware( - chatMiddleware(audiusSdk), - routerMiddleware(history), - ...(typeof window !== 'undefined' ? [sagaMiddleware] : []), - sentryMiddleware, - thunk -) + reportToSentry({ + level: ErrorLevel.Fatal, + error, + additionalInfo + }) + amplitudeTrack(Name.ERROR_PAGE, additionalInfo) + } + + const sagaMiddleware = createSagaMiddleware({ + onError: onSagaError, + context: storeContext + }) + + const middlewares = applyMiddleware( + chatMiddleware(audiusSdk), + routerMiddleware(history), + // Don't run sagas serverside + ...(typeof window !== 'undefined' ? [sagaMiddleware] : []), + sentryMiddleware, + thunk + ) -const configureStore = () => { const composeEnhancers = composeWithDevToolsLogOnlyInProduction({ trace: true, traceLimit: 25, maxAge: 1000 }) + const store = createStore( - createRootReducer(history), + createRootReducer(history, ssrPageProps), composeEnhancers(middlewares) ) @@ -150,14 +152,3 @@ const configureStore = () => { } return store } - -export const store = configureStore() -export const persistor = persistStore(store) - -// Mount store to window for easy access -if (typeof window !== 'undefined') { - window.store = store -} - -// Set up logger on store -logger(store) diff --git a/packages/web/src/store/reducers.ts b/packages/web/src/store/reducers.ts index ccbfb3ad31b..620b4fdea5f 100644 --- a/packages/web/src/store/reducers.ts +++ b/packages/web/src/store/reducers.ts @@ -1,7 +1,8 @@ import { queueReducer as queue, remoteConfigReducer as remoteConfig, - reducers as clientStoreReducers + reducers as clientStoreReducers, + SsrPageProps } from '@audius/common' import { connectRouter } from 'connected-react-router' import { History } from 'history' @@ -29,10 +30,13 @@ import userListModal from 'store/application/ui/userListModal/slice' import dragndrop from 'store/dragndrop/slice' import error from 'store/errors/reducers' -export const commonStoreReducers = clientStoreReducers(localForage) +const createRootReducer = ( + routeHistory: History, + ssrPageProps?: SsrPageProps +) => { + const commonStoreReducers = clientStoreReducers(localForage, ssrPageProps) -const createRootReducer = (routeHistory: History) => - combineReducers({ + return combineReducers({ // Common store ...commonStoreReducers, // These also belong in common store reducers but are here until we move them to the @audius/common package. @@ -82,5 +86,6 @@ const createRootReducer = (routeHistory: History) => }) }) }) +} export default createRootReducer From 5c6796182aacb02ef2d944dbfa0ab355de167ace Mon Sep 17 00:00:00 2001 From: sliptype Date: Fri, 8 Dec 2023 15:20:33 -0600 Subject: [PATCH 12/74] Get worker working --- packages/libs/src/utils/fileHasher.ts | 4 +- packages/libs/src/utils/multiProvider.ts | 3 +- packages/web/scripts/workers-site/index.js | 6 --- packages/web/src/app/web-player/WebPlayer.jsx | 3 ++ .../sign-up-page/pages/CreateEmailPage.tsx | 13 ++++--- .../sign-up-page/pages/CreateLoginDetails.tsx | 11 ++++-- .../sign-up-page/utils/loginDetailsSchema.ts | 37 ++++++++++--------- 7 files changed, 44 insertions(+), 33 deletions(-) diff --git a/packages/libs/src/utils/fileHasher.ts b/packages/libs/src/utils/fileHasher.ts index aa626ac16e8..51578251ea0 100644 --- a/packages/libs/src/utils/fileHasher.ts +++ b/packages/libs/src/utils/fileHasher.ts @@ -1,6 +1,6 @@ import fs from 'fs' import { Stream } from 'stream' -import { promisify } from 'util' +import * as util from 'util' import type { Blockstore, Options } from 'interface-blockstore' import type { @@ -36,6 +36,8 @@ export interface HashedImage { size: number } +const { promisify } = util + const block: Blockstore = { get: async (key: CID, _options?: Options) => { throw new Error(`unexpected block API get for ${key}`) diff --git a/packages/libs/src/utils/multiProvider.ts b/packages/libs/src/utils/multiProvider.ts index 4843799a866..1ffc6dd3a2d 100644 --- a/packages/libs/src/utils/multiProvider.ts +++ b/packages/libs/src/utils/multiProvider.ts @@ -1,10 +1,11 @@ -import { callbackify, promisify } from 'util' +import * as util from 'util' import { shuffle } from 'lodash' import type { HttpProvider, AbstractProvider } from 'web3-core' import type { JsonRpcPayload } from 'web3-core-helpers' import Web3 from '../LibsWeb3' +const { callbackify, promisify } = util const getSendMethod = (provider: HttpProvider | AbstractProvider) => { if ('sendAsync' in provider) { diff --git a/packages/web/scripts/workers-site/index.js b/packages/web/scripts/workers-site/index.js index de0adee8212..a7e99585604 100644 --- a/packages/web/scripts/workers-site/index.js +++ b/packages/web/scripts/workers-site/index.js @@ -274,12 +274,6 @@ async function handleEvent(event) { } const options = {} - // Always map requests to `/` - options.mapRequestToAsset = (request) => { - const url = new URL(request.url) - url.pathname = `/` - return mapRequestToAsset(new Request(url, request)) - } try { if (DEBUG) { diff --git a/packages/web/src/app/web-player/WebPlayer.jsx b/packages/web/src/app/web-player/WebPlayer.jsx index e9b588e2514..15f17fc5c1e 100644 --- a/packages/web/src/app/web-player/WebPlayer.jsx +++ b/packages/web/src/app/web-player/WebPlayer.jsx @@ -193,6 +193,9 @@ const { getHasAccount, getAccountStatus, getUserId, getUserHandle } = const UploadPage = lazy(() => import('pages/upload-page')) const Modals = lazy(() => import('pages/modals/Modals')) +const ConnectedMusicConfetti = lazy(() => + import('components/music-confetti/ConnectedMusicConfetti') +) const includeSearch = (search) => { return search.includes('oauth_token') || search.includes('code') diff --git a/packages/web/src/pages/sign-up-page/pages/CreateEmailPage.tsx b/packages/web/src/pages/sign-up-page/pages/CreateEmailPage.tsx index aeeff486c24..618b55d7d4f 100644 --- a/packages/web/src/pages/sign-up-page/pages/CreateEmailPage.tsx +++ b/packages/web/src/pages/sign-up-page/pages/CreateEmailPage.tsx @@ -1,8 +1,9 @@ -import { useCallback } from 'react' +import { useCallback, useMemo } from 'react' import { emailSchema, - createEmailPageMessages as messages + createEmailPageMessages as messages, + useAudiusQueryContext } from '@audius/common' import { Box, @@ -22,7 +23,6 @@ import { useDispatch, useSelector } from 'react-redux' import { Link } from 'react-router-dom' import { toFormikValidationSchema } from 'zod-formik-adapter' -import { audiusQueryContext } from 'app/AudiusQueryProvider' import audiusLogoColored from 'assets/img/audiusLogoColored.png' import { resetSignOn, @@ -50,8 +50,6 @@ import { SocialMediaLoading } from '../components/SocialMediaLoading' import { Heading, Page } from '../components/layout' import { useSocialMediaLoader } from '../hooks/useSocialMediaLoader' -const EmailSchema = toFormikValidationSchema(emailSchema(audiusQueryContext)) - export type SignUpEmailValues = { email: string } @@ -62,6 +60,11 @@ export const CreateEmailPage = () => { const navigate = useNavigateToPage() const existingEmailValue = useSelector(getEmailField) const alreadyLinkedSocial = useSelector(getLinkedSocialOnFirstPage) + const audiusQueryContext = useAudiusQueryContext() + const EmailSchema = useMemo( + () => toFormikValidationSchema(emailSchema(audiusQueryContext)), + [audiusQueryContext] + ) const initialValues = { email: existingEmailValue.value ?? '' diff --git a/packages/web/src/pages/sign-up-page/pages/CreateLoginDetails.tsx b/packages/web/src/pages/sign-up-page/pages/CreateLoginDetails.tsx index 2e83ab9866c..8d23e649377 100644 --- a/packages/web/src/pages/sign-up-page/pages/CreateLoginDetails.tsx +++ b/packages/web/src/pages/sign-up-page/pages/CreateLoginDetails.tsx @@ -1,4 +1,4 @@ -import { useCallback } from 'react' +import { useCallback, useMemo } from 'react' import { Flex, IconVerified, useTheme } from '@audius/harmony' import { Form, Formik } from 'formik' @@ -20,6 +20,7 @@ import { CompletionChecklist } from '../components/CompletionChecklist' import { SignUpAgreementText } from '../components/SignUpPolicyText' import { Heading, Page, PageFooter, ReadOnlyField } from '../components/layout' import { loginDetailsSchema } from '../utils/loginDetailsSchema' +import { useAudiusQueryContext } from '@audius/common' const messages = { title: 'Create Login Details', @@ -36,8 +37,6 @@ export type CreateLoginDetailsValues = { confirmPassword: string } -const loginDetailsFormikSchema = toFormikValidationSchema(loginDetailsSchema) - export const CreateLoginDetailsPage = () => { const dispatch = useDispatch() const navigate = useNavigateToPage() @@ -53,6 +52,12 @@ export const CreateLoginDetailsPage = () => { password: '', confirmPassword: '' } + const audiusQueryContext = useAudiusQueryContext() + + const loginDetailsFormikSchema = useMemo( + () => toFormikValidationSchema(loginDetailsSchema(audiusQueryContext)), + [audiusQueryContext] + ) const handleSubmit = useCallback( (values: CreateLoginDetailsValues) => { diff --git a/packages/web/src/pages/sign-up-page/utils/loginDetailsSchema.ts b/packages/web/src/pages/sign-up-page/utils/loginDetailsSchema.ts index f616af28932..f4ecf8b1edb 100644 --- a/packages/web/src/pages/sign-up-page/utils/loginDetailsSchema.ts +++ b/packages/web/src/pages/sign-up-page/utils/loginDetailsSchema.ts @@ -1,21 +1,24 @@ -import { emailSchema, isNotCommonPassword } from '@audius/common' +import { + AudiusQueryContext, + emailSchema, + isNotCommonPassword +} from '@audius/common' import { z } from 'zod' -import { audiusQueryContext } from 'app/AudiusQueryProvider' - // Due to issue with zod merge, manually rewriting // https://github.com/colinhacks/zod/issues/454 -export const loginDetailsSchema = z - .object({ - password: z - .string() - .regex(/\d/, { message: 'hasNumber' }) - .min(8, { message: 'minLength' }) - .refine(isNotCommonPassword, { message: 'notCommon' }), - confirmPassword: z.string() - }) - .merge(emailSchema(audiusQueryContext)) - .refine((data) => data.password === data.confirmPassword, { - message: 'matches', - path: ['confirmPassword'] - }) +export const loginDetailsSchema = (audiusQueryContext: AudiusQueryContext) => + z + .object({ + password: z + .string() + .regex(/\d/, { message: 'hasNumber' }) + .min(8, { message: 'minLength' }) + .refine(isNotCommonPassword, { message: 'notCommon' }), + confirmPassword: z.string() + }) + .merge(emailSchema(audiusQueryContext)) + .refine((data) => data.password === data.confirmPassword, { + message: 'matches', + path: ['confirmPassword'] + }) From 7a9821e585f4b16497af358260dc9e49c4d037af Mon Sep 17 00:00:00 2001 From: sliptype Date: Fri, 1 Dec 2023 10:19:34 -0600 Subject: [PATCH 13/74] Begin adding history context --- packages/common/src/store/storeContext.ts | 5 ++- packages/web/src/Root.tsx | 41 ++++++++++++------- packages/web/src/app/AppProviders.tsx | 5 ++- packages/web/src/app/HistoryProvider.tsx | 30 ++++++++++++++ packages/web/src/app/ReduxProvider.tsx | 5 ++- packages/web/src/common/store/queue/sagas.ts | 6 ++- .../components/AppRedirectPopover.tsx | 4 +- .../MobilePageContainer.tsx | 14 +++++-- .../components/play-bar/desktop/PlayBar.jsx | 4 +- .../pages/landing-page/LandingPage.tsx | 5 ++- packages/web/src/services/webVitals.ts | 2 + packages/web/src/ssr/SsrContext.tsx | 18 ++++++-- packages/web/src/ssr/_default.page.server.tsx | 12 +++--- packages/web/src/store/configureStore.ts | 7 +++- .../web/src/store/lineup/lineupForRoute.js | 4 +- packages/web/src/store/routing/selectors.ts | 2 + packages/web/src/utils/history.ts | 33 +++++++-------- packages/web/src/utils/route.ts | 20 ++++----- 18 files changed, 147 insertions(+), 70 deletions(-) create mode 100644 packages/web/src/app/HistoryProvider.tsx diff --git a/packages/common/src/store/storeContext.ts b/packages/common/src/store/storeContext.ts index 11aa9d365cd..fcc4bb59e03 100644 --- a/packages/common/src/store/storeContext.ts +++ b/packages/common/src/store/storeContext.ts @@ -1,4 +1,5 @@ import type { AudiusSdk } from '@audius/sdk' +import { Location } from 'history' import { AllTrackingEvents, @@ -58,7 +59,9 @@ export type CommonStoreContext = { explore: Explore // A helper that returns the appropriate lineup selector for the current // route or screen. - getLineupSelectorForRoute?: () => (state: CommonState) => LineupState + getLineupSelectorForRoute?: ( + location: Location + ) => (state: CommonState) => LineupState audioPlayer: AudioPlayer solanaClient: SolanaClient sentry: { diff --git a/packages/web/src/Root.tsx b/packages/web/src/Root.tsx index ebdef2c8260..f9b58fe9d7d 100644 --- a/packages/web/src/Root.tsx +++ b/packages/web/src/Root.tsx @@ -3,6 +3,7 @@ import '@audius/harmony/dist/harmony.css' import { Suspense, useState, useEffect, lazy } from 'react' +import { Location } from 'history' import { useAsync } from 'react-use' import { localStorage } from 'services/local-storage' @@ -10,31 +11,30 @@ import { useIsMobile, isElectron } from 'utils/clientUtil' import { getPathname, HOME_PAGE, publicSiteRoutes } from 'utils/route' import App from './app' -import { useSsrContext } from './ssr/SsrContext' +import { + HistoryContextProvider, + useHistoryContext +} from './app/HistoryProvider' // const App = lazy(() => import('./app')) const PublicSite = lazy(() => import('./public-site')) -const isPublicSiteRoute = ( - location: { pathname: string } = window.location -) => { +const isPublicSiteRoute = (location: Location) => { const pathname = getPathname(location).toLowerCase() return [...publicSiteRoutes, HOME_PAGE].includes(pathname) } -const isPublicSiteSubRoute = ( - location: { pathname: string } = window.location -) => { +const isPublicSiteSubRoute = (location: Location) => { const pathname = getPathname(location).toLowerCase() return publicSiteRoutes.includes(pathname) } const clientIsElectron = isElectron() -export const Root = () => { - const { path } = useSsrContext() +const AppOrPublicSite = () => { + const { history } = useHistoryContext() const [renderPublicSite, setRenderPublicSite] = useState( - isPublicSiteRoute({ pathname: path ?? '' }) + isPublicSiteRoute(history.location) ) const isMobileClient = useIsMobile() @@ -45,11 +45,12 @@ export const Root = () => { useEffect(() => { // TODO: listen to history and change routes based on history... window.onpopstate = () => { - setRenderPublicSite(isPublicSiteRoute({ pathname: path ?? '' })) + setRenderPublicSite(isPublicSiteRoute(history.location)) } }, []) - const shouldRedirectToApp = foundUser && !isPublicSiteSubRoute() + const shouldRedirectToApp = + foundUser && !isPublicSiteSubRoute(history.location) if (renderPublicSite && !clientIsElectron && !shouldRedirectToApp) { return ( }> @@ -62,8 +63,18 @@ export const Root = () => { } return ( - // }> - - // + <> + {/* }> */} + + {/* */} + + ) +} + +export const Root = () => { + return ( + + + ) } diff --git a/packages/web/src/app/AppProviders.tsx b/packages/web/src/app/AppProviders.tsx index ce4554cc576..9e9232d660a 100644 --- a/packages/web/src/app/AppProviders.tsx +++ b/packages/web/src/app/AppProviders.tsx @@ -1,4 +1,4 @@ -import { ReactNode, Suspense } from 'react' +import { ReactNode } from 'react' import { ConnectedRouter } from 'connected-react-router' import { LastLocationProvider } from 'react-router-last-location' @@ -8,12 +8,12 @@ import { HeaderContextProvider } from 'components/header/mobile/HeaderContextPro import { NavProvider } from 'components/nav/store/context' import { ScrollProvider } from 'components/scroll-provider/ScrollProvider' import { ToastContextProvider } from 'components/toast/ToastContext' -import history from 'utils/history' import { MainContentContextProvider } from '../pages/MainContentContext' import { AppContextProvider } from './AppContextProvider' import { AudiusQueryProvider } from './AudiusQueryProvider' +import { useHistoryContext } from './HistoryProvider' import { ReduxProvider } from './ReduxProvider' import { ThemeProvider } from './ThemeProvider' import { TrpcProvider } from './TrpcProvider' @@ -23,6 +23,7 @@ type AppContextProps = { } export const AppProviders = ({ children }: AppContextProps) => { + const { history } = useHistoryContext() return ( diff --git a/packages/web/src/app/HistoryProvider.tsx b/packages/web/src/app/HistoryProvider.tsx new file mode 100644 index 00000000000..e0ee08050aa --- /dev/null +++ b/packages/web/src/app/HistoryProvider.tsx @@ -0,0 +1,30 @@ +import { createContext, memo, useContext } from 'react' + +import { History } from 'history' + +import { useSsrContext } from 'ssr/SsrContext' +import { createHistory } from 'utils/history' + +export type HistoryContextType = { + history: History +} + +export const useHistoryContext = () => { + return useContext(HistoryContext) +} + +export const HistoryContext = createContext({ + history: null as any +}) + +export const HistoryContextProvider = memo( + (props: { children: JSX.Element }) => { + const { history: ssrHistory } = useSsrContext() + const history = ssrHistory || createHistory() + return ( + + {props.children} + + ) + } +) diff --git a/packages/web/src/app/ReduxProvider.tsx b/packages/web/src/app/ReduxProvider.tsx index 014bd7fa23c..05d284b4fb2 100644 --- a/packages/web/src/app/ReduxProvider.tsx +++ b/packages/web/src/app/ReduxProvider.tsx @@ -9,15 +9,18 @@ import logger from 'utils/logger' import { useSsrContext } from '../ssr/SsrContext' +import { useHistoryContext } from './HistoryProvider' + let store: ReturnType let persistor: ReturnType // TODO: Figure out persist gate? Do we need to block on loading from localstorage? export const ReduxProvider = ({ children }: { children: ReactNode }) => { const { isServerSide, pageProps } = useSsrContext() + const { history } = useHistoryContext() if (!store) { - store = configureStore(pageProps) + store = configureStore(history, pageProps) persistor = persistStore(store) // Mount store to window for easy access diff --git a/packages/web/src/common/store/queue/sagas.ts b/packages/web/src/common/store/queue/sagas.ts index 4724f97c853..dca5b0a5d3d 100644 --- a/packages/web/src/common/store/queue/sagas.ts +++ b/packages/web/src/common/store/queue/sagas.ts @@ -30,6 +30,7 @@ import { all, call, put, select, takeEvery, takeLatest } from 'typed-redux-saga' import { make } from 'common/store/analytics/actions' import { getRecommendedTracks } from 'common/store/recommendation/sagas' import { isPreview } from 'common/utils/isPreview' +import { getLocation } from 'store/routing/selectors' const { getCollectible, @@ -221,9 +222,12 @@ export function* watchPlay() { 'getLineupSelectorForRoute' ) if (!getLineupSelectorForRoute) return + + const location = yield* select(getLocation) + // @ts-ignore todo const lineup: LineupState<{ id: number }> = yield* select( - getLineupSelectorForRoute() + getLineupSelectorForRoute(location) ) if (!lineup) return if (lineup.entries.length > 0) { diff --git a/packages/web/src/components/app-redirect-popover/components/AppRedirectPopover.tsx b/packages/web/src/components/app-redirect-popover/components/AppRedirectPopover.tsx index f28e738d03e..25dd85855a3 100644 --- a/packages/web/src/components/app-redirect-popover/components/AppRedirectPopover.tsx +++ b/packages/web/src/components/app-redirect-popover/components/AppRedirectPopover.tsx @@ -6,6 +6,7 @@ import { matchPath } from 'react-router-dom' import { animated, useTransition } from 'react-spring' import { useSessionStorage } from 'react-use' +import { useHistoryContext } from 'app/HistoryProvider' import AppIcon from 'assets/img/appIcon240.png' import { isMobile } from 'utils/clientUtil' import { APP_REDIRECT, getPathname, SIGN_UP_PAGE } from 'utils/route' @@ -92,6 +93,7 @@ export const AppRedirectPopover = (props: AppRedirectPopoverProps) => { onBeforeClickApp = () => {}, onBeforeClickDismissed = () => {} } = props + const { history } = useHistoryContext() const [isDismissed, setIsDismissed] = useSessionStorage( 'app-redirect-popover', false @@ -127,7 +129,7 @@ export const AppRedirectPopover = (props: AppRedirectPopoverProps) => { const onClick = () => { onBeforeClickApp() - const pathname = getPathname() + const pathname = getPathname(history.location) const newHref = `https://redirect.audius.co${APP_REDIRECT}${pathname}` // If we're on the signup page, copy the URL to clipboard on app redirect diff --git a/packages/web/src/components/mobile-page-container/MobilePageContainer.tsx b/packages/web/src/components/mobile-page-container/MobilePageContainer.tsx index d75bfa2c492..93c1791a7cb 100644 --- a/packages/web/src/components/mobile-page-container/MobilePageContainer.tsx +++ b/packages/web/src/components/mobile-page-container/MobilePageContainer.tsx @@ -5,6 +5,7 @@ import cn from 'classnames' import { Helmet } from 'react-helmet' import { connect } from 'react-redux' +import { useHistoryContext } from 'app/HistoryProvider' import { ScrollContext } from 'components/scroll-provider/ScrollProvider' import { AppState } from 'store/types' import { getPathname } from 'utils/route' @@ -69,8 +70,9 @@ const MobilePageContainer = ({ hasDefaultHeader = false, hasPlayBar }: MobilePageContainerProps) => { + const { history } = useHistoryContext() const { getScrollForRoute, setScrollForRoute } = useContext(ScrollContext)! - const [getInitialPathname] = useInstanceVar(getPathname()) + const [getInitialPathname] = useInstanceVar(getPathname(history.location)) const [getLastScroll, setLastScroll] = useInstanceVar(0) // On mount, restore the last scroll position @@ -83,7 +85,7 @@ const MobilePageContainer = ({ useEffect(() => { // Store Y scroll in instance var as we scroll const onScroll = () => { - const path = getPathname() + const path = getPathname(history.location) // We can stay mounted after switching // paths, so check for this case if (path === getInitialPathname()) { @@ -98,7 +100,13 @@ const MobilePageContainer = ({ setScrollForRoute(getInitialPathname(), getLastScroll()) window.removeEventListener('scroll', onScroll) } - }, [setLastScroll, getInitialPathname, setScrollForRoute, getLastScroll]) + }, [ + setLastScroll, + getInitialPathname, + setScrollForRoute, + getLastScroll, + history + ]) const paddingBottom = `${ BOTTOM_BAR_HEIGHT + diff --git a/packages/web/src/components/play-bar/desktop/PlayBar.jsx b/packages/web/src/components/play-bar/desktop/PlayBar.jsx index 7278639f2e5..4c39807ad19 100644 --- a/packages/web/src/components/play-bar/desktop/PlayBar.jsx +++ b/packages/web/src/components/play-bar/desktop/PlayBar.jsx @@ -35,6 +35,7 @@ import ShuffleButtonProvider from 'components/play-bar/shuffle-button/ShuffleBut import { audioPlayer } from 'services/audio-player' import { getFeatureEnabled } from 'services/remote-config/featureFlagHelpers' import { getLineupSelectorForRoute } from 'store/lineup/lineupForRoute' +import { getLocationPathname } from 'store/routing/selectors' import { setupHotkeys } from 'utils/hotkeyUtil' import { collectibleDetailsPage, profilePage } from 'utils/route' import { isMatrix, shouldShowDark } from 'utils/theme/theme' @@ -463,8 +464,9 @@ const makeMapStateToProps = () => { const mapStateToProps = (state) => { const premiumTrackSignatureMap = getPremiumTrackSignatureMap(state) + const location = getLocationPathname(state) const lineupEntries = - getLineupEntries(getLineupSelectorForRoute(state), state) ?? [] + getLineupEntries(getLineupSelectorForRoute(location), state) ?? [] // The lineup has accessible tracks when there is at least one track // the user has access to i.e. a non-gated track or an unlocked gated track. diff --git a/packages/web/src/public-site/pages/landing-page/LandingPage.tsx b/packages/web/src/public-site/pages/landing-page/LandingPage.tsx index f779e97f177..899badcfa87 100644 --- a/packages/web/src/public-site/pages/landing-page/LandingPage.tsx +++ b/packages/web/src/public-site/pages/landing-page/LandingPage.tsx @@ -30,6 +30,7 @@ type LandingPageV2Props = { } const LandingPage = (props: LandingPageV2Props) => { + const { history } = useHistoryContext() useEffect(() => { document.documentElement.style.height = 'auto' return () => { @@ -58,13 +59,13 @@ const LandingPage = (props: LandingPageV2Props) => { window.location.search.includes(FANBURST_UTM_SOURCE) ) { if (window.history && window.history.pushState) { - window.history.pushState('', '/', getPathname()) + window.history.pushState('', '/', getPathname(history.location)) } else { window.location.hash = '' } setShowFanburstBanner(true) } - }, [setShowFanburstBanner]) + }, [setShowFanburstBanner, history]) const onDismissFanburstBanner = () => setShowFanburstBanner(false) const [hasImageLoaded, setHasImageLoaded] = useState(false) diff --git a/packages/web/src/services/webVitals.ts b/packages/web/src/services/webVitals.ts index f460e842303..b15ada2abc6 100644 --- a/packages/web/src/services/webVitals.ts +++ b/packages/web/src/services/webVitals.ts @@ -5,6 +5,8 @@ import { track } from 'services/analytics/amplitude' import { findRoute, getPathname } from 'utils/route' // Establish the "initial load" route + +// TODO: Fix remaining getPathname(), doesMatchRoute, pushUniqueRoute const route = findRoute(getPathname()) const sendToAnalytics = ({ name, delta }: { name: string; delta: number }) => { diff --git a/packages/web/src/ssr/SsrContext.tsx b/packages/web/src/ssr/SsrContext.tsx index f95607a6ba9..987a421b6c8 100644 --- a/packages/web/src/ssr/SsrContext.tsx +++ b/packages/web/src/ssr/SsrContext.tsx @@ -1,22 +1,32 @@ import { createContext, memo, useContext } from 'react' import { Nullable, SsrPageProps } from '@audius/common' +import { History } from 'history' export type SsrContextType = { path: Nullable isServerSide: boolean + /** + * The page props for the current request. This is available on both the server and the client. + */ pageProps: SsrPageProps + /** + * The history object for the current request. This is only available on the server. + * On the client, use useHistoryContext instead. + */ + history: Nullable } export const useSsrContext = () => { return useContext(SsrContext) } -export const SsrContext = createContext({ +export const SsrContext = createContext({ path: null, - isServerSide: true, - pageProps: {} -} as SsrContextType) + isServerSide: false, + pageProps: {}, + history: null +}) export const SsrContextProvider = memo( (props: { value: SsrContextType; children: JSX.Element }) => { diff --git a/packages/web/src/ssr/_default.page.server.tsx b/packages/web/src/ssr/_default.page.server.tsx index be36f181c09..cd02f13dbe6 100644 --- a/packages/web/src/ssr/_default.page.server.tsx +++ b/packages/web/src/ssr/_default.page.server.tsx @@ -1,10 +1,9 @@ import { SsrPageProps } from '@audius/common' +import { createMemoryHistory } from 'history' import ReactDOMServer from 'react-dom/server' import { escapeInject, dangerouslySkipEscape } from 'vike/server' import { PageContextServer } from 'vike/types' -import history from 'utils/history' - import indexHtml from '../../index.html?raw' import { Root } from '../Root' @@ -15,14 +14,15 @@ export const passToClient = ['pageProps', 'urlPathname'] export function render( pageContext: PageContextServer & { pageProps: SsrPageProps } ) { - const { Page, pageProps, urlPathname } = pageContext + const { pageProps, urlPathname } = pageContext - // TODO: Shared history instance is causing page not to change on new route - history.replace(urlPathname) + const history = createMemoryHistory({ + initialEntries: [urlPathname] + }) const pageHtml = ReactDOMServer.renderToString( diff --git a/packages/web/src/store/configureStore.ts b/packages/web/src/store/configureStore.ts index 48411b23775..b64eda2389d 100644 --- a/packages/web/src/store/configureStore.ts +++ b/packages/web/src/store/configureStore.ts @@ -3,6 +3,7 @@ import { SsrPageProps } from '@audius/common/dist/models/SsrPageProps' import { composeWithDevToolsLogOnlyInProduction } from '@redux-devtools/extension' import { configureScope, addBreadcrumb } from '@sentry/browser' import { routerMiddleware } from 'connected-react-router' +import { History } from 'history' import { createStore, applyMiddleware, Action, Store } from 'redux' import createSagaMiddleware from 'redux-saga' import createSentryMiddleware from 'redux-sentry-middleware' @@ -14,7 +15,6 @@ import * as errorActions from 'store/errors/actions' import { reportToSentry } from 'store/errors/reportToSentry' import createRootReducer from 'store/reducers' import rootSaga from 'store/sagas' -import history from 'utils/history' import { storeContext } from './storeContext' import { AppState } from './types' @@ -92,7 +92,10 @@ const sentryMiddleware = createSentryMiddleware( } ) -export const configureStore = (ssrPageProps?: SsrPageProps) => { +export const configureStore = ( + history: History, + ssrPageProps?: SsrPageProps +) => { const onSagaError = ( error: Error, errorInfo: { diff --git a/packages/web/src/store/lineup/lineupForRoute.js b/packages/web/src/store/lineup/lineupForRoute.js index 558ff1dc7fa..df95e7dceb0 100644 --- a/packages/web/src/store/lineup/lineupForRoute.js +++ b/packages/web/src/store/lineup/lineupForRoute.js @@ -37,9 +37,9 @@ const { getSearchTracksLineup } = searchResultsPageSelectors const { getLineup } = trackPageSelectors const { getCurrentDiscoverTrendingLineup } = trendingPageSelectors -export const getLineupSelectorForRoute = () => { +export const getLineupSelectorForRoute = (location) => { const matchPage = (path) => { - const match = matchPath(getPathname(), { + const match = matchPath(getPathname(location), { path, exact: true }) diff --git a/packages/web/src/store/routing/selectors.ts b/packages/web/src/store/routing/selectors.ts index 985bfbc953e..1183f0dd278 100644 --- a/packages/web/src/store/routing/selectors.ts +++ b/packages/web/src/store/routing/selectors.ts @@ -1,5 +1,7 @@ import { AppState } from 'store/types' import { getPathname } from 'utils/route' +export const getLocation = (state: AppState) => state.router.location + export const getLocationPathname = (state: AppState) => getPathname(state.router.location) diff --git a/packages/web/src/utils/history.ts b/packages/web/src/utils/history.ts index 67e832aa599..dc842209273 100644 --- a/packages/web/src/utils/history.ts +++ b/packages/web/src/utils/history.ts @@ -2,29 +2,24 @@ import { BrowserHistoryBuildOptions, createBrowserHistory, createHashHistory, - createMemoryHistory, - HashHistoryBuildOptions, - History + HashHistoryBuildOptions } from 'history' const USE_HASH_ROUTING = process.env.VITE_USE_HASH_ROUTING === 'true' const basename = process.env.VITE_PUBLIC_URL -let history: History -if (USE_HASH_ROUTING) { - const config: HashHistoryBuildOptions = {} - if (basename) { - config.basename = basename +export const createHistory = () => { + if (USE_HASH_ROUTING) { + const config: HashHistoryBuildOptions = {} + if (basename) { + config.basename = basename + } + return createHashHistory(config) + } else { + const config: BrowserHistoryBuildOptions = {} + if (basename) { + config.basename = basename + } + return createBrowserHistory(config) } - history = createHashHistory(config) -} else if (typeof window !== 'undefined') { - const config: BrowserHistoryBuildOptions = {} - if (basename) { - config.basename = basename - } - history = createBrowserHistory(config) -} else { - history = createMemoryHistory() } - -export default history diff --git a/packages/web/src/utils/route.ts b/packages/web/src/utils/route.ts index ab6cf3b83ab..0000f40132b 100644 --- a/packages/web/src/utils/route.ts +++ b/packages/web/src/utils/route.ts @@ -1,10 +1,8 @@ import { ID, encodeUrlName, getHash } from '@audius/common' import { push as pushRoute } from 'connected-react-router' -import { Location as HistoryLocation } from 'history' +import { Location } from 'history' import { matchPath } from 'react-router' -import history from './history' - const USE_HASH_ROUTING = process.env.VITE_USE_HASH_ROUTING === 'true' // Host/protocol. @@ -413,8 +411,12 @@ export const chatPage = (id: string) => { return `/messages/${id}` } -export const doesMatchRoute = (route: string, exact = true) => { - return matchPath(getPathname(), { +export const doesMatchRoute = ( + location: Location, + route: string, + exact = true +) => { + return matchPath(getPathname(location), { path: route, exact }) @@ -427,9 +429,7 @@ export const stripBaseUrl = (url: string) => url.replace(BASE_URL, '') * if using hash routing * @param {Location} location */ -export const getPathname = ( - location: Location | HistoryLocation = history.location -) => { +export const getPathname = (location: Location) => { return BASENAME ? location.pathname.replace(BASENAME, '') : location.pathname } @@ -469,8 +469,8 @@ export const pushWindowRoute = (route: string) => { /** * Only calls push route if unique (not current route) */ -export const pushUniqueRoute = (route: string) => { - const pathname = getPathname() +export const pushUniqueRoute = (location: Location, route: string) => { + const pathname = getPathname(location) if (route !== pathname) { return pushRoute(route) } From 614275da0d49307d6762475d6f41ad11119ef42a Mon Sep 17 00:00:00 2001 From: sliptype Date: Fri, 8 Dec 2023 16:54:23 -0600 Subject: [PATCH 14/74] Finish history context --- packages/web/src/app/App.tsx | 13 +- packages/web/src/app/HistoryProvider.tsx | 2 + .../web/src/app/web-player/WebPlayer.test.tsx | 3 +- .../components/CollectiblesPage.tsx | 7 +- .../src/components/now-playing/NowPlaying.tsx | 15 +- .../components/play-bar/desktop/PlayBar.jsx | 173 +++++++++--------- .../PremiumContentPurchaseModal.tsx | 6 +- .../search-bar/ConnectedSearchBar.jsx | 6 +- .../components/WalletManagementTile.tsx | 8 +- .../src/pages/feed-page/FeedPageProvider.jsx | 5 +- .../pages/search-page/SearchPageProvider.jsx | 36 ++-- .../components/mobile/SearchPageContent.tsx | 4 +- packages/web/src/pages/search-page/helpers.ts | 15 +- .../trending-page/TrendingPageProvider.jsx | 4 +- packages/web/src/services/webVitals.ts | 39 ++-- 15 files changed, 196 insertions(+), 140 deletions(-) diff --git a/packages/web/src/app/App.tsx b/packages/web/src/app/App.tsx index 0128cf7afbc..624032659ea 100644 --- a/packages/web/src/app/App.tsx +++ b/packages/web/src/app/App.tsx @@ -8,17 +8,14 @@ import { Route, Switch } from 'react-router-dom' import { CoinbasePayButtonProvider } from 'components/coinbase-pay-button' import { SomethingWrong } from 'pages/something-wrong/SomethingWrong' -// TODO: turn into a component to utilize SsrContext -// import '../services/webVitals' - import { remoteConfigInstance } from 'services/remote-config/remote-config-instance' import { SIGN_IN_PAGE, SIGN_UP_PAGE } from 'utils/route' import { AppErrorBoundary } from './AppErrorBoundary' import { AppProviders } from './AppProviders' import WebPlayer from './web-player/WebPlayer' - -import '../services/webVitals' +import { useHistoryContext } from './HistoryProvider' +import { initWebVitals } from 'services/webVitals' const SignOnPage = lazy(() => import('pages/sign-on-page')) const SignOn = lazy(() => import('pages/sign-on/SignOn')) @@ -26,6 +23,12 @@ const OAuthLoginPage = lazy(() => import('pages/oauth-login-page')) const DemoTrpcPage = lazy(() => import('pages/demo-trpc/DemoTrpcPage')) export const AppInner = () => { + const { history } = useHistoryContext() + + useEffect(() => { + initWebVitals(history.location) + }, [history]) + const { isEnabled: isSignInRedesignEnabled, isLoaded } = useFeatureFlag( FeatureFlags.SIGN_UP_REDESIGN ) diff --git a/packages/web/src/app/HistoryProvider.tsx b/packages/web/src/app/HistoryProvider.tsx index e0ee08050aa..dbc2ce6ef81 100644 --- a/packages/web/src/app/HistoryProvider.tsx +++ b/packages/web/src/app/HistoryProvider.tsx @@ -17,6 +17,8 @@ export const HistoryContext = createContext({ history: null as any }) +// TODO: does this cause rerenders on route change? +// TODO: could puth getPathname in here export const HistoryContextProvider = memo( (props: { children: JSX.Element }) => { const { history: ssrHistory } = useSsrContext() diff --git a/packages/web/src/app/web-player/WebPlayer.test.tsx b/packages/web/src/app/web-player/WebPlayer.test.tsx index b4096f41491..66f1505acf4 100644 --- a/packages/web/src/app/web-player/WebPlayer.test.tsx +++ b/packages/web/src/app/web-player/WebPlayer.test.tsx @@ -4,7 +4,7 @@ import { Provider } from 'react-redux' import { describe, it, vitest } from 'vitest' import { store } from 'store/configureStore' -import history from 'utils/history' +import { createHistory } from 'utils/history' import WebPlayer from './WebPlayer' @@ -28,6 +28,7 @@ vitest.mock('services/solana-client/SolanaClient', () => ({ describe('smoke test', () => { it('renders without crashing', () => { + const history = createHistory() const rootNode = document.createElement('div') ReactDOM.render( diff --git a/packages/web/src/components/collectibles/components/CollectiblesPage.tsx b/packages/web/src/components/collectibles/components/CollectiblesPage.tsx index 5c656d92f6f..ecfba532b36 100644 --- a/packages/web/src/components/collectibles/components/CollectiblesPage.tsx +++ b/packages/web/src/components/collectibles/components/CollectiblesPage.tsx @@ -60,6 +60,7 @@ import { import zIndex from 'utils/zIndex' import styles from './CollectiblesPage.module.css' +import { useHistoryContext } from 'app/HistoryProvider' const { getCollectible } = collectibleDetailsUISelectors const { setCollectible } = collectibleDetailsUIActions @@ -132,6 +133,7 @@ const CollectiblesPage = (props: CollectiblesPageProps) => { const solanaCollectibleList = useMemo(() => { return profile?.solanaCollectibleList ?? null }, [profile]) + const { history } = useHistoryContext() const collectibleList = useMemo(() => { return ethCollectibleList || solanaCollectibleList @@ -489,7 +491,10 @@ const CollectiblesPage = (props: CollectiblesPageProps) => { // Handle rendering details modal based on route useEffect(() => { - const match = doesMatchRoute(PROFILE_PAGE_COLLECTIBLE_DETAILS) + const match = doesMatchRoute( + history.location, + PROFILE_PAGE_COLLECTIBLE_DETAILS + ) if (match) { // Ignore needed bc typescript doesn't think that match.params has collectibleId property // @ts-ignore diff --git a/packages/web/src/components/now-playing/NowPlaying.tsx b/packages/web/src/components/now-playing/NowPlaying.tsx index ff023591bce..b3735ed70be 100644 --- a/packages/web/src/components/now-playing/NowPlaying.tsx +++ b/packages/web/src/components/now-playing/NowPlaying.tsx @@ -1,5 +1,6 @@ import { useCallback, useEffect, useRef, useState } from 'react' +import { Location } from 'history' import { ID, FavoriteSource, @@ -62,6 +63,7 @@ import { withNullGuard } from 'utils/withNullGuard' import styles from './NowPlaying.module.css' import ActionsBar from './components/ActionsBar' +import { useHistoryContext } from 'app/HistoryProvider' const { makeGetCurrent } = queueSelectors const { getBuffering, getCounter, getPlaying, getPlaybackRate } = playerSelectors @@ -134,6 +136,7 @@ const NowPlaying = g( dominantColors }) => { const { uid, track, user, collectible } = currentQueueItem + const { history } = useHistoryContext // Keep a ref for the artwork and dynamically resize the width of the // image as the height changes (which is flexed). @@ -281,15 +284,18 @@ const NowPlaying = g( const goToTrackPage = () => { onClose() if (track) { - goToRoute(track.permalink) + goToRoute(history.location, track.permalink) } else { - goToRoute(collectibleDetailsPage(user.handle, collectible?.id ?? '')) + goToRoute( + history.location, + collectibleDetailsPage(user.handle, collectible?.id ?? '') + ) } } const goToProfilePage = () => { onClose() - goToRoute(profilePage(handle)) + goToRoute(history.location, profilePage(handle)) } const onClickOverflow = useCallback(() => { @@ -640,7 +646,8 @@ function mapDispatchToProps(dispatch: Dispatch) { overflowActionCallbacks: callbacks }) ), - goToRoute: (route: string) => dispatch(pushRoute(route)) + goToRoute: (location: Location, route: string) => + dispatch(pushRoute(location, route)) } } diff --git a/packages/web/src/components/play-bar/desktop/PlayBar.jsx b/packages/web/src/components/play-bar/desktop/PlayBar.jsx index 4c39807ad19..2e451f381a4 100644 --- a/packages/web/src/components/play-bar/desktop/PlayBar.jsx +++ b/packages/web/src/components/play-bar/desktop/PlayBar.jsx @@ -26,6 +26,7 @@ import { push as pushRoute } from 'connected-react-router' import { connect } from 'react-redux' import { make } from 'common/store/analytics/actions' +import { ClientOnly } from 'components/client-only/ClientOnly' import PlayButton from 'components/play-bar/PlayButton' import VolumeBar from 'components/play-bar/VolumeBar' import NextButtonProvider from 'components/play-bar/next-button/NextButtonProvider' @@ -360,99 +361,101 @@ class PlayBar extends Component { return (
-
- -
- -
-
- +
+
-
-
- {isLongFormContent && isNewPodcastControlsEnabled ? null : ( - - )} -
-
- -
-
- +
+
-
- -
-
- {isLongFormContent && isNewPodcastControlsEnabled ? ( - - ) : ( - +
+ {isLongFormContent && isNewPodcastControlsEnabled ? null : ( + + )} +
+
+ +
+
+ - )} +
+
+ +
+
+ {isLongFormContent && isNewPodcastControlsEnabled ? ( + + ) : ( + + )} +
-
- -
- - -
+ +
+ + +
+
) diff --git a/packages/web/src/components/premium-content-purchase-modal/PremiumContentPurchaseModal.tsx b/packages/web/src/components/premium-content-purchase-modal/PremiumContentPurchaseModal.tsx index 79291331875..ca32dba5b1f 100644 --- a/packages/web/src/components/premium-content-purchase-modal/PremiumContentPurchaseModal.tsx +++ b/packages/web/src/components/premium-content-purchase-modal/PremiumContentPurchaseModal.tsx @@ -43,6 +43,7 @@ import { AudioMatchSection } from './components/AudioMatchSection' import { PurchaseContentFormFields } from './components/PurchaseContentFormFields' import { PurchaseContentFormFooter } from './components/PurchaseContentFormFooter' import { usePurchaseContentFormState } from './hooks/usePurchaseContentFormState' +import { useHistoryContext } from 'app/HistoryProvider' const { startRecoveryIfNecessary, cleanup: cleanupUSDCRecovery } = buyUSDCActions @@ -85,6 +86,7 @@ const RenderForm = ({ const currentPageIndex = pageToPageIndex(page) const { resetForm } = useFormikContext() + const { history } = useHistoryContext() // Reset form on track change useEffect(() => resetForm, [track.track_id, resetForm]) @@ -92,9 +94,9 @@ const RenderForm = ({ // Navigate to track on successful purchase behind the modal useEffect(() => { if (stage === PurchaseContentStage.FINISH && permalink) { - dispatch(pushUniqueRoute(permalink)) + dispatch(pushUniqueRoute(history.location, permalink)) } - }, [stage, permalink, dispatch]) + }, [stage, permalink, dispatch, history]) const handleClose = useCallback(() => { dispatch(setPurchasePage({ page: PurchaseContentPage.PURCHASE })) diff --git a/packages/web/src/components/search-bar/ConnectedSearchBar.jsx b/packages/web/src/components/search-bar/ConnectedSearchBar.jsx index fac38162a42..88ada00265a 100644 --- a/packages/web/src/components/search-bar/ConnectedSearchBar.jsx +++ b/packages/web/src/components/search-bar/ConnectedSearchBar.jsx @@ -24,8 +24,10 @@ import Bar from 'components/search/SearchBar' import { collectionPage, profilePage, getPathname } from 'utils/route' import styles from './ConnectedSearchBar.module.css' +import { HistoryContext } from 'app/HistoryProvider' class ConnectedSearchBar extends Component { + static contextType = HistoryContext state = { value: '' } @@ -35,7 +37,7 @@ class ConnectedSearchBar extends Component { // Clear search when navigating away from the search results page. history.listen((location, action) => { - const match = matchPath(getPathname(), { + const match = matchPath(getPathname(this.context.history.location), { path: '/search/:query' }) if (!match) { @@ -44,7 +46,7 @@ class ConnectedSearchBar extends Component { }) // Set the initial search bar value if we loaded into a search page. - const match = matchPath(getPathname(), { + const match = matchPath(getPathname(this.context.history.location), { path: '/search/:query' }) if (has(match, 'params.query')) { diff --git a/packages/web/src/pages/audio-rewards-page/components/WalletManagementTile.tsx b/packages/web/src/pages/audio-rewards-page/components/WalletManagementTile.tsx index 59198ba6589..4d6fccefdf3 100644 --- a/packages/web/src/pages/audio-rewards-page/components/WalletManagementTile.tsx +++ b/packages/web/src/pages/audio-rewards-page/components/WalletManagementTile.tsx @@ -45,6 +45,8 @@ import { import TokenHoverTooltip from './TokenHoverTooltip' import styles from './WalletManagementTile.module.css' +import { useHistory } from 'react-router-dom' +import { useHistoryContext } from 'app/HistoryProvider' const { getHasAssociatedWallets } = tokenDashboardPageSelectors const { pressReceive, pressSend, pressConnectWallets } = tokenDashboardPageActions @@ -190,17 +192,19 @@ const OnRampTooltipButton = ({ bannedState }: OnRampTooltipButtonProps) => { const dispatch = useDispatch() + const { history } = useHistoryContext() + const onClick = useCallback(() => { dispatch( startBuyAudioFlow({ provider, onSuccess: { - action: pushUniqueRoute(TRENDING_PAGE), + action: pushUniqueRoute(history.location, TRENDING_PAGE), message: messages.findArtists } }) ) - }, [dispatch, provider]) + }, [dispatch, provider, history]) const bannedRegionText = provider === OnRampProvider.COINBASE ? messages.coinbasePayRegionNotSupported diff --git a/packages/web/src/pages/feed-page/FeedPageProvider.jsx b/packages/web/src/pages/feed-page/FeedPageProvider.jsx index 2fe0a46154a..cfd18042abf 100644 --- a/packages/web/src/pages/feed-page/FeedPageProvider.jsx +++ b/packages/web/src/pages/feed-page/FeedPageProvider.jsx @@ -16,6 +16,7 @@ import { } from 'connected-react-router' import { connect } from 'react-redux' import { withRouter, matchPath } from 'react-router-dom' +import { HistoryContext } from 'app/HistoryProvider' import { make } from 'common/store/analytics/actions' import { openSignOn } from 'common/store/pages/signon/actions' @@ -39,6 +40,8 @@ const messages = { * children as `FeedPageContentProps`. */ class FeedPageProvider extends PureComponent { + static contextType = HistoryContext + goToTrending = () => { this.props.history.push({ pathname: TRENDING_PAGE @@ -50,7 +53,7 @@ class FeedPageProvider extends PureComponent { } matchesRoute = (route) => { - return matchPath(getPathname(), { + return matchPath(getPathname(this.context.history.location), { path: route }) } diff --git a/packages/web/src/pages/search-page/SearchPageProvider.jsx b/packages/web/src/pages/search-page/SearchPageProvider.jsx index fd6f189c5f1..cce91200ecf 100644 --- a/packages/web/src/pages/search-page/SearchPageProvider.jsx +++ b/packages/web/src/pages/search-page/SearchPageProvider.jsx @@ -23,6 +23,7 @@ import { SEARCH_PAGE, doesMatchRoute } from 'utils/route' +import { HistoryContext } from 'app/HistoryProvider' import * as helpers from './helpers' const { makeGetCurrent } = queueSelectors @@ -38,9 +39,13 @@ const { makeGetLineupMetadatas } = lineupSelectors const getUserId = accountSelectors.getUserId class SearchPageProvider extends Component { + static contextType = HistoryContext + constructor(props) { super(props) - const searchResultsCategory = helpers.getCategory() + const searchResultsCategory = helpers.getCategory( + this.context.history.location + ) this.state = { searchResultsCategory @@ -54,13 +59,15 @@ class SearchPageProvider extends Component { // Make sure the serach bar shows on every search-navigation if (window.scrollTo) window.scrollTo(0, 0) const isTagSearch = helpers.isTagSearch() - const searchMatch = helpers.getSearchText() + const searchMatch = helpers.getSearchText(this.context.history.location) - const category = helpers.getCategory() + const category = helpers.getCategory(this.context.history.location) this.setState({ searchResultsCategory: category }) if (!!searchMatch || isTagSearch) { - const query = isTagSearch ? helpers.getSearchTag() : searchMatch + const query = isTagSearch + ? helpers.getSearchTag(this.context.history.location) + : searchMatch this.props.dispatch(tracksActions.reset()) if (category !== SearchKind.TRACKS) { const limit = helpers.getResultsLimit(this.props.isMobile, category) @@ -72,8 +79,10 @@ class SearchPageProvider extends Component { }) const isTagSearch = helpers.isTagSearch() - const query = isTagSearch ? helpers.getSearchTag() : helpers.getSearchText() - const category = helpers.getCategory() + const query = isTagSearch + ? helpers.getSearchTag(this.context.history.location) + : helpers.getSearchText(this.context.history.location) + const category = helpers.getCategory(this.context.history.location) if (category !== SearchKind.TRACKS) { const limit = helpers.getResultsLimit(this.props.isMobile, category) query && this.search(isTagSearch, query, category, limit) @@ -107,9 +116,13 @@ class SearchPageProvider extends Component { handleViewMoreResults = (category) => { return () => { const { history } = this.props - const query = helpers.getQuery() + const query = helpers.getQuery(this.context.history.location) history.push(`/search/${query}/${category}`) - this.setState({ searchResultsCategory: helpers.getCategory() }) + this.setState({ + searchResultsCategory: helpers.getCategory( + this.context.history.location + ) + }) this.props.recordMoreResults(query, category) } } @@ -122,10 +135,11 @@ class SearchPageProvider extends Component { // Note that if the user navigates and the page route does not match the // search page, then we should not redirect & allow react router to render // the correct page. - const query = helpers.getQuery() + const query = helpers.getQuery(this.context.history.location) if ( !query && - (doesMatchRoute(SEARCH_CATEGORY_PAGE) || doesMatchRoute(SEARCH_PAGE)) + (doesMatchRoute(this.context.history.location, SEARCH_CATEGORY_PAGE) || + doesMatchRoute(this.context.history.location, SEARCH_PAGE)) ) { return } @@ -133,7 +147,7 @@ class SearchPageProvider extends Component { const ContentClass = this.props.children const injectedProps = { ...this.props, - searchText: helpers.getQuery(), + searchText: helpers.getQuery(this.context.history.location), handleViewMoreResults: this.handleViewMoreResults, searchResultsCategory: this.state.searchResultsCategory, isTagSearch: helpers.isTagSearch() diff --git a/packages/web/src/pages/search-page/components/mobile/SearchPageContent.tsx b/packages/web/src/pages/search-page/components/mobile/SearchPageContent.tsx index 864c443199a..c8092bea6a2 100644 --- a/packages/web/src/pages/search-page/components/mobile/SearchPageContent.tsx +++ b/packages/web/src/pages/search-page/components/mobile/SearchPageContent.tsx @@ -43,6 +43,7 @@ import { } from 'utils/route' import styles from './SearchPageContent.module.css' +import { useHistoryContext } from 'app/HistoryProvider' export type SearchPageContentProps = { tracks: LineupState<{}> @@ -130,6 +131,7 @@ const TracksSearchPage = ({ containerRef, isTagSearch }: SearchPageContentProps) => { + const { history } = useHistoryContext() const numTracks = Object.keys(tracks.entries).length const loadingStatus = (() => { // We need to account for the odd case where search.status === success but @@ -169,7 +171,7 @@ const TracksSearchPage = ({ loadMore={(offset: number, limit: number) => dispatch( tracksActions.fetchLineupMetadatas(offset, limit, false, { - category: getCategory(), + category: getCategory(history.location.pathname), query: trimToAlphaNumeric(searchText), isTagSearch }) diff --git a/packages/web/src/pages/search-page/helpers.ts b/packages/web/src/pages/search-page/helpers.ts index 1642bd28953..2d0f77803ff 100644 --- a/packages/web/src/pages/search-page/helpers.ts +++ b/packages/web/src/pages/search-page/helpers.ts @@ -26,12 +26,12 @@ export const isTagSearch = () => { return !!window.location.hash } -export const getCategory = () => { +export const getCategory = (pathname: string) => { let category if (isTagSearch()) { category = window.location.hash.slice(1).split('/')[1] } else { - const categoryMatch = matchPath(getPathname(), { + const categoryMatch = matchPath(pathname, { path: '/search/:query/:category', exact: true }) as match @@ -55,17 +55,16 @@ export const getCategory = () => { return SearchKind.ALL } -export const getSearchTag = () => { +export const getSearchTag = (pathname: string) => { // Trim off the leading '#' and remove any other paths (e.g. category) if (USE_HASH_ROUTING) { - const pathname = getPathname() return pathname.split('#')[1].split('/')[0] } return window.location.hash.slice(1).split('/')[0] } -export const getSearchText = () => { - const match = matchPath(getPathname(), { +export const getSearchText = (pathname: string) => { + const match = matchPath(pathname, { path: '/search/:query' }) as match if (!match) return '' @@ -83,8 +82,8 @@ export const getSearchText = () => { // Returns a full query (e.g. `#rap` or `rap`), as opposed to // `getSearchTag` which strips leading # from tags -export const getQuery = () => - isTagSearch() ? `#${getSearchTag()}` : getSearchText() +export const getQuery = (pathname: string) => + isTagSearch() ? `#${getSearchTag(pathname)}` : getSearchText(pathname) export const getResultsLimit = (isMobile: boolean, category: SearchKind) => { return isMobile diff --git a/packages/web/src/pages/trending-page/TrendingPageProvider.jsx b/packages/web/src/pages/trending-page/TrendingPageProvider.jsx index 3b87f6b1023..5c0588be387 100644 --- a/packages/web/src/pages/trending-page/TrendingPageProvider.jsx +++ b/packages/web/src/pages/trending-page/TrendingPageProvider.jsx @@ -18,6 +18,7 @@ import { } from 'connected-react-router' import { connect } from 'react-redux' import { matchPath, withRouter } from 'react-router-dom' +import { HistoryContext } from 'app/HistoryProvider' import { make } from 'common/store/analytics/actions' import { openSignOn } from 'common/store/pages/signon/actions' @@ -68,6 +69,7 @@ const callLineupAction = (timeRange, action, ...args) => { * children as `TrendingPageContentProps`. */ class TrendingPageProvider extends PureComponent { + static contextType = HistoryContext goToSignUp = () => { this.props.openSignOn(false) } @@ -77,7 +79,7 @@ class TrendingPageProvider extends PureComponent { } matchesRoute = (route) => { - return matchPath(getPathname(), { + return matchPath(getPathname(this.context.history.location), { path: route }) } diff --git a/packages/web/src/services/webVitals.ts b/packages/web/src/services/webVitals.ts index b15ada2abc6..44496a95d01 100644 --- a/packages/web/src/services/webVitals.ts +++ b/packages/web/src/services/webVitals.ts @@ -3,24 +3,31 @@ import { getCLS, getFID, getLCP, getFCP, getTTFB } from 'web-vitals' import { track } from 'services/analytics/amplitude' import { findRoute, getPathname } from 'utils/route' +import { Location } from 'history' // Establish the "initial load" route +export const initWebVitals = (location: Location) => { + const route = findRoute(getPathname(location)) -// TODO: Fix remaining getPathname(), doesMatchRoute, pushUniqueRoute -const route = findRoute(getPathname()) + const sendToAnalytics = ({ + name, + delta + }: { + name: string + delta: number + }) => { + console.info(name, delta) + track(Name.WEB_VITALS, { + metric: name, + value: delta, + route + }) + } -const sendToAnalytics = ({ name, delta }: { name: string; delta: number }) => { - console.info(name, delta) - track(Name.WEB_VITALS, { - metric: name, - value: delta, - route - }) + // See https://web.dev/vitals/ + getCLS(sendToAnalytics) + getFID(sendToAnalytics) + getLCP(sendToAnalytics) + getFCP(sendToAnalytics) + getTTFB(sendToAnalytics) } - -// See https://web.dev/vitals/ -getCLS(sendToAnalytics) -getFID(sendToAnalytics) -getLCP(sendToAnalytics) -getFCP(sendToAnalytics) -getTTFB(sendToAnalytics) From 9922dd73ad9ac62af409a05d082dfd1ca4f933f7 Mon Sep 17 00:00:00 2001 From: sliptype Date: Fri, 8 Dec 2023 17:01:36 -0600 Subject: [PATCH 15/74] Fix store singleton --- packages/web/.eslintrc.js | 3 ++- packages/web/src/app/ReduxProvider.tsx | 17 +++++++---------- packages/web/src/app/web-player/WebPlayer.jsx | 3 +-- .../web/src/app/web-player/WebPlayer.module.css | 7 ------- packages/web/src/assets/styles/index.css | 7 +++++++ packages/web/src/ssr/_default.page.client.tsx | 2 +- packages/web/src/ssr/profile.page.route.tsx | 12 ------------ packages/web/src/ssr/track.page.route.tsx | 6 +++++- packages/web/vite.config.ts | 1 + packages/web/wrangler.toml | 2 -- 10 files changed, 24 insertions(+), 36 deletions(-) delete mode 100644 packages/web/src/ssr/profile.page.route.tsx diff --git a/packages/web/.eslintrc.js b/packages/web/.eslintrc.js index 54d662558c8..0f11cdfb03c 100644 --- a/packages/web/.eslintrc.js +++ b/packages/web/.eslintrc.js @@ -26,7 +26,8 @@ module.exports = { ['utils', './src/utils'], ['workers', './src/workers'], ['pages', './src/pages'], - ['ssr', './src/ssr'] + ['ssr', './src/ssr'], + ['app', './src/app'] ], extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'] } diff --git a/packages/web/src/app/ReduxProvider.tsx b/packages/web/src/app/ReduxProvider.tsx index 05d284b4fb2..4cfb9d5f51d 100644 --- a/packages/web/src/app/ReduxProvider.tsx +++ b/packages/web/src/app/ReduxProvider.tsx @@ -1,8 +1,7 @@ -import { ReactNode } from 'react' +import { ReactNode, useState } from 'react' import { Provider } from 'react-redux' import { persistStore } from 'redux-persist' -import { PersistGate } from 'redux-persist/integration/react' import { configureStore } from 'store/configureStore' import logger from 'utils/logger' @@ -11,17 +10,17 @@ import { useSsrContext } from '../ssr/SsrContext' import { useHistoryContext } from './HistoryProvider' -let store: ReturnType -let persistor: ReturnType - // TODO: Figure out persist gate? Do we need to block on loading from localstorage? export const ReduxProvider = ({ children }: { children: ReactNode }) => { const { isServerSide, pageProps } = useSsrContext() const { history } = useHistoryContext() + const [store, setStore] = useState>() + if (!store) { - store = configureStore(history, pageProps) - persistor = persistStore(store) + const store = configureStore(history, pageProps) + setStore(store) + persistStore(store) // Mount store to window for easy access if (typeof window !== 'undefined') { @@ -32,7 +31,5 @@ export const ReduxProvider = ({ children }: { children: ReactNode }) => { logger(store) } - return store && persistor ? ( - {children} - ) : null + return store ? {children} : null } diff --git a/packages/web/src/app/web-player/WebPlayer.jsx b/packages/web/src/app/web-player/WebPlayer.jsx index 15f17fc5c1e..e07f12633a5 100644 --- a/packages/web/src/app/web-player/WebPlayer.jsx +++ b/packages/web/src/app/web-player/WebPlayer.jsx @@ -35,6 +35,7 @@ import { DownloadAppBanner } from 'components/banner/DownloadAppBanner' import { UpdateAppBanner } from 'components/banner/UpdateAppBanner' import { Web3ErrorBanner } from 'components/banner/Web3ErrorBanner' import { ChatListener } from 'components/chat-listener/ChatListener' +import { ClientOnly } from 'components/client-only/ClientOnly' import CookieBanner from 'components/cookie-banner/CookieBanner' import { DevModeMananger } from 'components/dev-mode-manager/DevModeManager' import { HeaderContextConsumer } from 'components/header/mobile/HeaderContextProvider' @@ -183,8 +184,6 @@ import { getTheme as getSystemTheme } from 'utils/theme/theme' import styles from './WebPlayer.module.css' -import { ClientOnly } from 'components/client-only/ClientOnly' - const { setTheme } = themeActions const { getTheme } = themeSelectors diff --git a/packages/web/src/app/web-player/WebPlayer.module.css b/packages/web/src/app/web-player/WebPlayer.module.css index bc34ddb5298..94db3a145fb 100644 --- a/packages/web/src/app/web-player/WebPlayer.module.css +++ b/packages/web/src/app/web-player/WebPlayer.module.css @@ -1,10 +1,3 @@ -body { - background: var(--background); - backface-visibility: hidden; - /** Turn off user select so the web app behaves more like "an app" */ - user-select: none; -} - .modalRoot { position: absolute; height: 100%; diff --git a/packages/web/src/assets/styles/index.css b/packages/web/src/assets/styles/index.css index 38d731054b1..6e767ff880f 100644 --- a/packages/web/src/assets/styles/index.css +++ b/packages/web/src/assets/styles/index.css @@ -19,3 +19,10 @@ h5, h6 { color: var(--neutral); } + +body { + background: var(--background); + backface-visibility: hidden; + /** Turn off user select so the web app behaves more like "an app" */ + user-select: none; +} diff --git a/packages/web/src/ssr/_default.page.client.tsx b/packages/web/src/ssr/_default.page.client.tsx index c7573537c8b..3e0e1d4a9a5 100644 --- a/packages/web/src/ssr/_default.page.client.tsx +++ b/packages/web/src/ssr/_default.page.client.tsx @@ -13,7 +13,7 @@ const HYDRATE_CLIENT = true export async function render( pageContext: PageContextClient & { pageProps: { track: FullSdk.TrackFull } } ) { - const { Page, pageProps, urlPathname } = pageContext + const { pageProps, urlPathname } = pageContext if (HYDRATE_CLIENT) { hydrateRoot( diff --git a/packages/web/src/ssr/profile.page.route.tsx b/packages/web/src/ssr/profile.page.route.tsx deleted file mode 100644 index f64746c69dc..00000000000 --- a/packages/web/src/ssr/profile.page.route.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { resolveRoute } from 'vike/routing' - -import { staticRoutes } from 'utils/route' - -export default (pageContext) => { - // Don't render profile page if the route matches any of the static routes - if (staticRoutes.has(pageContext.urlPathname)) { - return false - } - - return resolveRoute('/@handle', pageContext.urlPathname) -} diff --git a/packages/web/src/ssr/track.page.route.tsx b/packages/web/src/ssr/track.page.route.tsx index 0526c9c86f6..dfe8c78fcdb 100644 --- a/packages/web/src/ssr/track.page.route.tsx +++ b/packages/web/src/ssr/track.page.route.tsx @@ -1,9 +1,13 @@ import { resolveRoute } from 'vike/routing' import { PageContextServer } from 'vike/types' +import { staticRoutes } from 'utils/route' + export default (pageContext: PageContextServer) => { - if (pageContext.urlPathname.match(/index\.css\.map$/)) { + // Don't render track page if the route matches any of the static routes + if (staticRoutes.has(pageContext.urlPathname)) { return false } + return resolveRoute('/@handle/@slug', pageContext.urlPathname) } diff --git a/packages/web/vite.config.ts b/packages/web/vite.config.ts index 749214ab399..db9991f41db 100644 --- a/packages/web/vite.config.ts +++ b/packages/web/vite.config.ts @@ -97,6 +97,7 @@ export default defineConfig(({ mode }) => { store: '/src/store', workers: '/src/workers', utils: '/src/utils', + ssr: '/src/ssr', os: require.resolve('os-browserify'), path: require.resolve('path-browserify'), diff --git a/packages/web/wrangler.toml b/packages/web/wrangler.toml index 33d6c106298..0db0458d63e 100644 --- a/packages/web/wrangler.toml +++ b/packages/web/wrangler.toml @@ -1,8 +1,6 @@ compatibility_date = "2023-10-25" account_id = "3811365464a8e56b2b27a5590e328e49" -workers_dev = true main = "./scripts/workers-site/index.js" -node_compat = true [site] bucket = "./build/client" From 06a7b57bfcfa37f01c01e49cb13b4ba2d3397a73 Mon Sep 17 00:00:00 2001 From: sliptype Date: Tue, 12 Dec 2023 16:53:09 -0600 Subject: [PATCH 16/74] Update cross-fetch and vike --- package-lock.json | 1036 ++++++++++++++++++++---------------- packages/libs/package.json | 2 +- packages/web/package.json | 3 +- 3 files changed, 583 insertions(+), 458 deletions(-) diff --git a/package-lock.json b/package-lock.json index a8aadb0adfe..0bf8aaf0d1d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2914,11 +2914,6 @@ "resolved": "https://registry.npmjs.org/@brillout/json-serializer/-/json-serializer-0.5.8.tgz", "integrity": "sha512-vEuXw30ok+mJfJutOxXKBb4lBJ0HymA7lev9PcYK6W/hzjhCTPk9Bdk85HrcNcKZWRQiwoWtw0F2Di4TRJ7ssQ==" }, - "node_modules/@brillout/picocolors": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@brillout/picocolors/-/picocolors-1.0.9.tgz", - "integrity": "sha512-Lt/W5JsA75hcDJ2cOAlE4TqSMl6c9K+rXGRo/cU2fApnmhbRcNdkR4UHQDAwtWfZyUKWaxdwSui+jp+74J1pZg==" - }, "node_modules/@brillout/require-shim": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@brillout/require-shim/-/require-shim-0.1.2.tgz", @@ -3273,11 +3268,6 @@ "node": ">=10.0.0" } }, - "node_modules/@cloudflare/workers-types": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-2.2.2.tgz", - "integrity": "sha512-kaMn2rueJ0PL1TYVGknTCh0X0x0d9G+FNXAFep7/4uqecEZoQb/63o6rOmMuiqI09zLuHV6xhKRXinokV/MY9A==" - }, "node_modules/@cnakazawa/watch": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", @@ -113163,438 +113153,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/vike": { - "version": "0.4.146", - "resolved": "https://registry.npmjs.org/vike/-/vike-0.4.146.tgz", - "integrity": "sha512-1vaktcDy/eitSzVaUppKJWu+6vfwxKC4kV6uzAqj3RIK+WgteH3vF6IMZ0jnjjzCpeDRCIByN8PF4c0CtzRfHA==", - "dependencies": { - "@brillout/import": "0.2.3", - "@brillout/json-serializer": "^0.5.8", - "@brillout/picocolors": "^1.0.9", - "@brillout/require-shim": "^0.1.2", - "@brillout/vite-plugin-import-build": "^0.2.20", - "acorn": "^8.8.2", - "cac": "^6.7.14", - "es-module-lexer": "^1.3.0", - "esbuild": "^0.17.18", - "fast-glob": "^3.2.12", - "sirv": "^2.0.2", - "source-map-support": "^0.5.21" - }, - "bin": { - "vike": "node/cli/bin-entry.js" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "react-streaming": ">=0.3.5", - "vite": ">=3.1.0" - }, - "peerDependenciesMeta": { - "react-streaming": { - "optional": true - } - } - }, - "node_modules/vike/node_modules/@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", - "cpu": [ - "loong64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", - "cpu": [ - "mips64el" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vike/node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/vike/node_modules/esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" - } - }, - "node_modules/vike/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==", - "dependencies": { - "@polka/url": "^1.0.0-next.20", - "mrmime": "^1.0.0", - "totalist": "^3.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/vike/node_modules/totalist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", - "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", - "engines": { - "node": ">=6" - } - }, "node_modules/vite": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", @@ -141187,7 +140745,7 @@ "bs58": "4.0.1", "cipher-base": "1.0.4", "crc-32": "1.2.2", - "cross-fetch": "3.1.5", + "cross-fetch": "4.0.0", "elliptic": "6.5.4", "esm": "3.2.25", "eth-sig-util": "2.5.4", @@ -142417,6 +141975,14 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, + "packages/libs/node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, "packages/libs/node_modules/eslint": { "version": "8.19.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.19.0.tgz", @@ -143345,6 +142911,25 @@ "node": ">= 10.13" } }, + "packages/libs/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "packages/libs/node_modules/normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -144203,6 +143788,11 @@ "node": ">=8.0" } }, + "packages/libs/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "packages/libs/node_modules/ts-mocha": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-9.0.2.tgz", @@ -144337,6 +143927,20 @@ "uuid": "dist/bin/uuid" } }, + "packages/libs/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "packages/libs/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "packages/libs/node_modules/workerpool": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", @@ -153502,7 +153106,7 @@ "@audius/sdk": "*", "@audius/stems": "*", "@audius/trpc-server": "*", - "@cloudflare/kv-asset-handler": "~0.0.11", + "@cloudflare/kv-asset-handler": "0.2.0", "@coinbase/cbpay-js": "1.2.0", "@emotion/css": "^11.11.2", "@emotion/styled": "^11.11.0", @@ -153545,6 +153149,7 @@ "clamp": "1.0.1", "classnames": "2.2.6", "connected-react-router": "6.9.3", + "cross-fetch": "^4.0.0", "electron-log": "3.0.9", "electron-updater": "4.3.5", "exif-parser": "0.1.12", @@ -153617,7 +153222,7 @@ "type-fest": "2.16.0", "typed-redux-saga": "1.3.1", "typesafe-actions": "5.1.0", - "vike": "^0.4.146", + "vike": "0.4.150", "walletlink": "2.0.3", "wasm-loader": "1.3.0", "web-vitals": "0.2.2", @@ -153701,14 +153306,347 @@ "vitest": "0.34.6" } }, + "packages/web/node_modules/@brillout/picocolors": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@brillout/picocolors/-/picocolors-1.0.10.tgz", + "integrity": "sha512-dh+JJlsBf3QYX+91Ezma8RLKNOjGDoBBmORv/NzRpQuasdyzwQCMXGGjsDu12ZhGz92TqQbL9pv79rvbheI21A==" + }, "packages/web/node_modules/@cloudflare/kv-asset-handler": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.0.12.tgz", - "integrity": "sha512-3XCs9TRhQh/yUs1ST9cIMLB8C5c1JRKcDYTPJbAmcgI0kO2FPCSZz+kyNb9x25DuGQeqOMMwmxHPtiOfTki/Gw==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.2.0.tgz", + "integrity": "sha512-MVbXLbTcAotOPUj0pAMhVtJ+3/kFkwJqc5qNOleOZTv6QkZZABDMS21dSrSlVswEHwrpWC03e4fWytjqKvuE2A==", "dependencies": { - "@cloudflare/workers-types": "^2.0.0", - "@types/mime": "^2.0.2", - "mime": "^2.4.6" + "mime": "^3.0.0" + } + }, + "packages/web/node_modules/@esbuild/android-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/android-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/android-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/darwin-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/darwin-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/freebsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/linux-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/linux-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/linux-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/linux-loong64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/linux-mips64el": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/linux-ppc64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/linux-riscv64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/linux-s390x": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/linux-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", + "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/netbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/openbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/sunos-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/win32-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/win32-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "packages/web/node_modules/@esbuild/win32-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, "packages/web/node_modules/@humanwhocodes/config-array": { @@ -154220,6 +154158,38 @@ "node": ">=11" } }, + "packages/web/node_modules/@project-serum/anchor/node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, + "packages/web/node_modules/@project-serum/anchor/node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "packages/web/node_modules/@project-serum/anchor/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "packages/web/node_modules/@types/classnames": { "version": "2.2.10", "resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.2.10.tgz", @@ -154231,17 +154201,23 @@ "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-2.2.6.tgz", "integrity": "sha512-+oY0FDTO2GYKEV0YPvSshGq9t7YozVkgvXLty7zogQNuCxBhT9/3INX9Q7H1aRZ4SUDRXAKlJuA4EA5nTt7SNw==" }, - "packages/web/node_modules/@types/mime": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", - "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==" - }, "packages/web/node_modules/@types/node": { "version": "12.12.35", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.35.tgz", "integrity": "sha512-ASYsaKecA7TUsDrqIGPNk3JeEox0z/0XR/WsJJ8BIX/9+SkMSImQXKWfU/yBrSyc7ZSE/NPqLu36Nur0miCFfQ==", "dev": true }, + "packages/web/node_modules/acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "packages/web/node_modules/ajv": { "version": "7.2.4", "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.2.4.tgz", @@ -154339,6 +154315,33 @@ "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", "hasInstallScript": true }, + "packages/web/node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "packages/web/node_modules/cross-fetch/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "packages/web/node_modules/decode-uri-component": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", @@ -154362,6 +154365,42 @@ "node": ">=4.0.0" } }, + "packages/web/node_modules/esbuild": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", + "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" + } + }, "packages/web/node_modules/eslint": { "version": "8.19.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.19.0.tgz", @@ -154564,6 +154603,17 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, + "packages/web/node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, "packages/web/node_modules/minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", @@ -154652,6 +154702,19 @@ "node": ">=8" } }, + "packages/web/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==", + "dependencies": { + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, "packages/web/node_modules/split-on-first": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", @@ -154680,6 +154743,19 @@ "node": ">=8" } }, + "packages/web/node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "engines": { + "node": ">=6" + } + }, + "packages/web/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "packages/web/node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", @@ -154695,6 +154771,54 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "packages/web/node_modules/vike": { + "version": "0.4.150", + "resolved": "https://registry.npmjs.org/vike/-/vike-0.4.150.tgz", + "integrity": "sha512-R2cfpRWTZb0WOgMDsh5oLGq9yJV4aPjEyjpnvy0Rkntv9YpX4EXp9MmNHUTqNJJqBeURtJKHQpfPbFRgbPjIbQ==", + "dependencies": { + "@brillout/import": "0.2.3", + "@brillout/json-serializer": "^0.5.8", + "@brillout/picocolors": "^1.0.10", + "@brillout/require-shim": "^0.1.2", + "@brillout/vite-plugin-import-build": "^0.2.20", + "acorn": "^8.8.2", + "cac": "^6.7.14", + "es-module-lexer": "^1.3.0", + "esbuild": "^0.17.18", + "fast-glob": "^3.2.12", + "sirv": "^2.0.2", + "source-map-support": "^0.5.21" + }, + "bin": { + "vike": "node/cli/bin-entry.js" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "react-streaming": ">=0.3.5", + "vite": ">=3.1.0" + }, + "peerDependenciesMeta": { + "react-streaming": { + "optional": true + } + } + }, + "packages/web/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "packages/web/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } } } } diff --git a/packages/libs/package.json b/packages/libs/package.json index 057273a129e..a6f160ecd9d 100644 --- a/packages/libs/package.json +++ b/packages/libs/package.json @@ -85,7 +85,7 @@ "bs58": "4.0.1", "cipher-base": "1.0.4", "crc-32": "1.2.2", - "cross-fetch": "3.1.5", + "cross-fetch": "4.0.0", "elliptic": "6.5.4", "esm": "3.2.25", "eth-sig-util": "2.5.4", diff --git a/packages/web/package.json b/packages/web/package.json index 6343a0f1adf..72132f85e45 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -100,6 +100,7 @@ "clamp": "1.0.1", "classnames": "2.2.6", "connected-react-router": "6.9.3", + "cross-fetch": "^4.0.0", "electron-log": "3.0.9", "electron-updater": "4.3.5", "exif-parser": "0.1.12", @@ -172,7 +173,7 @@ "type-fest": "2.16.0", "typed-redux-saga": "1.3.1", "typesafe-actions": "5.1.0", - "vike": "^0.4.146", + "vike": "0.4.150", "walletlink": "2.0.3", "wasm-loader": "1.3.0", "web-vitals": "0.2.2", From be13a3a07dbee9f68202477e15171a4a1948e293 Mon Sep 17 00:00:00 2001 From: sliptype Date: Tue, 12 Dec 2023 16:55:49 -0600 Subject: [PATCH 17/74] Enable node_compat --- packages/web/wrangler.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/web/wrangler.toml b/packages/web/wrangler.toml index 0db0458d63e..169f39c105b 100644 --- a/packages/web/wrangler.toml +++ b/packages/web/wrangler.toml @@ -1,6 +1,7 @@ compatibility_date = "2023-10-25" account_id = "3811365464a8e56b2b27a5590e328e49" main = "./scripts/workers-site/index.js" +node_compat = true [site] bucket = "./build/client" From 3085388d2247e36159228a1c70b807aae24364b3 Mon Sep 17 00:00:00 2001 From: sliptype Date: Wed, 13 Dec 2023 15:14:18 -0600 Subject: [PATCH 18/74] Fix lottie ssr --- packages/web/patches/lottie-web+5.12.2.patch | 35 ++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 packages/web/patches/lottie-web+5.12.2.patch diff --git a/packages/web/patches/lottie-web+5.12.2.patch b/packages/web/patches/lottie-web+5.12.2.patch new file mode 100644 index 00000000000..f8ccc7224bf --- /dev/null +++ b/packages/web/patches/lottie-web+5.12.2.patch @@ -0,0 +1,35 @@ +diff --git a/node_modules/lottie-web/build/player/lottie.js b/node_modules/lottie-web/build/player/lottie.js +index cddf7ca..03ac76e 100644 +--- a/node_modules/lottie-web/build/player/lottie.js ++++ b/node_modules/lottie-web/build/player/lottie.js +@@ -1313,6 +1313,10 @@ + + var ImagePreloader = function () { + var proxyImage = function () { ++ if (typeof document === 'undefined') { ++ return undefined ++ } ++ + var canvas = createTag('canvas'); + canvas.width = 1; + canvas.height = 1; +@@ -5299,7 +5303,7 @@ + + var queryString = ''; + +- if (standalone) { ++ if (standalone && typeof document !== 'undefined') { + var scripts = document.getElementsByTagName('script'); + var index = scripts.length - 1; + var myScript = scripts[index] || { +@@ -13885,7 +13889,9 @@ + } + + extendPrototype([BaseElement, TransformElement, CVBaseElement, HierarchyElement, FrameElement, RenderableElement, ITextElement], CVTextElement); +- CVTextElement.prototype.tHelper = createTag('canvas').getContext('2d'); ++ if (typeof document !== 'undefined') { ++ CVTextElement.prototype.tHelper = createTag('canvas').getContext('2d'); ++ } + + CVTextElement.prototype.buildNewText = function () { + var documentData = this.textProperty.currentData; From c2b9842518199eb468a567e979939690c147f834 Mon Sep 17 00:00:00 2001 From: sliptype Date: Wed, 13 Dec 2023 15:30:15 -0600 Subject: [PATCH 19/74] Fix lottie render pt 2 --- packages/web/patches/lottie-web+5.12.2.patch | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/web/patches/lottie-web+5.12.2.patch b/packages/web/patches/lottie-web+5.12.2.patch index f8ccc7224bf..cd7d9577842 100644 --- a/packages/web/patches/lottie-web+5.12.2.patch +++ b/packages/web/patches/lottie-web+5.12.2.patch @@ -1,5 +1,5 @@ diff --git a/node_modules/lottie-web/build/player/lottie.js b/node_modules/lottie-web/build/player/lottie.js -index cddf7ca..03ac76e 100644 +index cddf7ca..c9ad885 100644 --- a/node_modules/lottie-web/build/player/lottie.js +++ b/node_modules/lottie-web/build/player/lottie.js @@ -1313,6 +1313,10 @@ @@ -13,6 +13,15 @@ index cddf7ca..03ac76e 100644 var canvas = createTag('canvas'); canvas.width = 1; canvas.height = 1; +@@ -5276,7 +5280,7 @@ + lottie.version = '5.12.2'; + + function checkReady() { +- if (document.readyState === 'complete') { ++ if (typeof document !== 'undefined' && document.readyState === 'complete') { + clearInterval(readyStateCheckInterval); + searchAnimations(); + } @@ -5299,7 +5303,7 @@ var queryString = ''; From 5830f0a532036b3fbaa9f8199d916e76b8c60c15 Mon Sep 17 00:00:00 2001 From: sliptype Date: Wed, 13 Dec 2023 15:32:11 -0600 Subject: [PATCH 20/74] Use vike v1 design --- package-lock.json | 37 ++++ packages/web/package.json | 1 + packages/web/pages/index.page.tsx | 0 ...lt.page.client.tsx => +onRenderClient.tsx} | 2 +- ...ault.page.server.tsx => +onRenderHtml.tsx} | 0 packages/web/src/components/link/UserLink.tsx | 4 +- .../src/components/nav/desktop/LeftNav.tsx | 122 ++++++------ packages/web/src/components/page/Page.tsx | 13 +- .../src/components/track/GiantTrackTile.tsx | 59 +++--- .../pages/landing-page/LandingPage.tsx | 1 + packages/web/src/ssr/index/+Page.tsx | 3 + .../ssr/index/+route.ts} | 0 packages/web/src/ssr/track.page.server.tsx | 27 --- packages/web/src/ssr/track.page.tsx | 186 ------------------ packages/web/src/ssr/track/+Page.tsx | 3 + .../web/src/ssr/track/+onBeforeRender.tsx | 42 ++++ .../+onRenderClient.tsx} | 15 +- .../+onRenderHtml.tsx} | 8 +- .../+route.tsx} | 0 19 files changed, 210 insertions(+), 313 deletions(-) delete mode 100644 packages/web/pages/index.page.tsx rename packages/web/renderer/{_default.page.client.tsx => +onRenderClient.tsx} (93%) rename packages/web/renderer/{_default.page.server.tsx => +onRenderHtml.tsx} (100%) create mode 100644 packages/web/src/ssr/index/+Page.tsx rename packages/web/{pages/index.page.route.ts => src/ssr/index/+route.ts} (100%) delete mode 100644 packages/web/src/ssr/track.page.server.tsx delete mode 100644 packages/web/src/ssr/track.page.tsx create mode 100644 packages/web/src/ssr/track/+Page.tsx create mode 100644 packages/web/src/ssr/track/+onBeforeRender.tsx rename packages/web/src/ssr/{_default.page.client.tsx => track/+onRenderClient.tsx} (65%) rename packages/web/src/ssr/{_default.page.server.tsx => track/+onRenderHtml.tsx} (87%) rename packages/web/src/ssr/{track.page.route.tsx => track/+route.tsx} (100%) diff --git a/package-lock.json b/package-lock.json index 0bf8aaf0d1d..31be253c8b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63370,6 +63370,14 @@ "url": "https://github.com/sponsors/gjtorikian/" } }, + "node_modules/isbot-fast": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/isbot-fast/-/isbot-fast-1.2.0.tgz", + "integrity": "sha512-twjuQzy2gKMDVfKGQyQqrx6Uy4opu/fiVUTTpdqtFsd7OQijIp5oXvb27n5EemYXaijh5fomndJt/SPRLsEdSg==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/isemail": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", @@ -97222,6 +97230,20 @@ "react-dom": ">= 16.8.0" } }, + "node_modules/react-streaming": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/react-streaming/-/react-streaming-0.3.18.tgz", + "integrity": "sha512-4qugTyVx0r1i/o+PzrcqwThqLgjNdqNgzCYnIFASImSB9yPkhUqFIKyLXm6sQIcZ8gu2E2xdSvCdikfmVYER5g==", + "dependencies": { + "@brillout/import": "^0.2.3", + "@brillout/json-serializer": "^0.5.1", + "isbot-fast": "1.2.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, "node_modules/react-style-singleton": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", @@ -113153,6 +113175,20 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/vike-react": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/vike-react/-/vike-react-0.3.7.tgz", + "integrity": "sha512-m2RbQ5s3h3bFC+bxKjsqOUttYuWvuSKdBN2mCnUOTO1zIFxPIG8HyiVrYLXKRG//FT1Ae55YuQdx/hb5Qc8edQ==", + "dependencies": { + "react-streaming": "^0.3.16" + }, + "peerDependencies": { + "react": "18.x.x", + "react-dom": "18.x.x", + "vike": "^0.4.149", + "vite": "^4.3.8" + } + }, "node_modules/vite": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", @@ -153223,6 +153259,7 @@ "typed-redux-saga": "1.3.1", "typesafe-actions": "5.1.0", "vike": "0.4.150", + "vike-react": "^0.3.7", "walletlink": "2.0.3", "wasm-loader": "1.3.0", "web-vitals": "0.2.2", diff --git a/packages/web/package.json b/packages/web/package.json index 72132f85e45..93d42ae26eb 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -174,6 +174,7 @@ "typed-redux-saga": "1.3.1", "typesafe-actions": "5.1.0", "vike": "0.4.150", + "vike-react": "^0.3.7", "walletlink": "2.0.3", "wasm-loader": "1.3.0", "web-vitals": "0.2.2", diff --git a/packages/web/pages/index.page.tsx b/packages/web/pages/index.page.tsx deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/packages/web/renderer/_default.page.client.tsx b/packages/web/renderer/+onRenderClient.tsx similarity index 93% rename from packages/web/renderer/_default.page.client.tsx rename to packages/web/renderer/+onRenderClient.tsx index 734e56000b7..d42088df91d 100644 --- a/packages/web/renderer/_default.page.client.tsx +++ b/packages/web/renderer/+onRenderClient.tsx @@ -13,7 +13,7 @@ window.global ||= window window.Buffer = Buffer window.process = { ...processBrowser, env: process.env } -export async function render() { +export function render() { const container = document.getElementById('root') if (container) { const root = createRoot(container) diff --git a/packages/web/renderer/_default.page.server.tsx b/packages/web/renderer/+onRenderHtml.tsx similarity index 100% rename from packages/web/renderer/_default.page.server.tsx rename to packages/web/renderer/+onRenderHtml.tsx diff --git a/packages/web/src/components/link/UserLink.tsx b/packages/web/src/components/link/UserLink.tsx index c81de623ea5..7ed2528826d 100644 --- a/packages/web/src/components/link/UserLink.tsx +++ b/packages/web/src/components/link/UserLink.tsx @@ -4,6 +4,7 @@ import cn from 'classnames' import { ArtistPopover } from 'components/artist/ArtistPopover' import { Text } from 'components/typography' import UserBadges from 'components/user-badges/UserBadges' +import { useSsrContext } from 'ssr/SsrContext' import { useSelector } from 'utils/reducer' import { profilePage } from 'utils/route' @@ -20,6 +21,7 @@ type UserLinkProps = Omit & { } export const UserLink = (props: UserLinkProps) => { + const { isServerSide } = useSsrContext() const { userId, textAs = 'span', @@ -50,7 +52,7 @@ export const UserLink = (props: UserLinkProps) => { ) - return popover && handle ? ( + return !isServerSide && popover && handle ? ( {linkElement} ) : ( linkElement diff --git a/packages/web/src/components/nav/desktop/LeftNav.tsx b/packages/web/src/components/nav/desktop/LeftNav.tsx index 5ad81a24b57..85c3105df5f 100644 --- a/packages/web/src/components/nav/desktop/LeftNav.tsx +++ b/packages/web/src/components/nav/desktop/LeftNav.tsx @@ -125,72 +125,76 @@ const LeftNav = (props: NavColumnProps) => {
)} diff --git a/packages/web/src/components/track/GiantTrackTile.tsx b/packages/web/src/components/track/GiantTrackTile.tsx index 543cf1adbdb..f23a4fdd986 100644 --- a/packages/web/src/components/track/GiantTrackTile.tsx +++ b/packages/web/src/components/track/GiantTrackTile.tsx @@ -560,34 +560,39 @@ export const GiantTrackTile = ({ {renderStatsRow()}
-
- {renderShareButton()} - {renderMakePublicButton()} - {doesUserHaveAccess && renderRepostButton()} - {doesUserHaveAccess && renderFavoriteButton()} - - {/* prop types for overflow menu don't work correctly + +
+ {renderShareButton()} + {renderMakePublicButton()} + {doesUserHaveAccess && renderRepostButton()} + {doesUserHaveAccess && renderFavoriteButton()} + + {/* prop types for overflow menu don't work correctly so we need to cast here */} - - {(ref, triggerPopup) => ( -
-
- )} -
-
-
+ + {(ref, triggerPopup) => ( +
+
+ )} +
+
+
+
{aiAttributionUserId ? ( diff --git a/packages/web/src/public-site/pages/landing-page/LandingPage.tsx b/packages/web/src/public-site/pages/landing-page/LandingPage.tsx index 899badcfa87..831077739a7 100644 --- a/packages/web/src/public-site/pages/landing-page/LandingPage.tsx +++ b/packages/web/src/public-site/pages/landing-page/LandingPage.tsx @@ -3,6 +3,7 @@ import { useState, useEffect, useCallback } from 'react' import cn from 'classnames' import { ParallaxProvider } from 'react-scroll-parallax' +import { useHistoryContext } from 'app/HistoryProvider' import { FanburstBanner } from 'components/banner/FanburstBanner' import { CookieBanner } from 'components/cookie-banner/CookieBanner' import Footer from 'public-site/components/Footer' diff --git a/packages/web/src/ssr/index/+Page.tsx b/packages/web/src/ssr/index/+Page.tsx new file mode 100644 index 00000000000..06b8116b441 --- /dev/null +++ b/packages/web/src/ssr/index/+Page.tsx @@ -0,0 +1,3 @@ +export default function render() { + return null +} diff --git a/packages/web/pages/index.page.route.ts b/packages/web/src/ssr/index/+route.ts similarity index 100% rename from packages/web/pages/index.page.route.ts rename to packages/web/src/ssr/index/+route.ts diff --git a/packages/web/src/ssr/track.page.server.tsx b/packages/web/src/ssr/track.page.server.tsx deleted file mode 100644 index 6693fcb5383..00000000000 --- a/packages/web/src/ssr/track.page.server.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import type { Maybe } from '@audius/common' -import { sdk, full as FullSdk } from '@audius/sdk' -import { PageContextServer } from 'vike/types' - -const audiusSdk = sdk({ - appName: 'audius.co' -}) - -export type TrackPageProps = { - track: Maybe -} - -export async function onBeforeRender(pageContext: PageContextServer) { - const { handle, slug } = pageContext.routeParams - - const { data: tracks } = await audiusSdk.full.tracks.getBulkTracks({ - permalink: [`${handle}/${slug}`] - }) - - const pageProps = { track: tracks?.[0] } - - return { - pageContext: { - pageProps - } - } -} diff --git a/packages/web/src/ssr/track.page.tsx b/packages/web/src/ssr/track.page.tsx deleted file mode 100644 index 35f20a90802..00000000000 --- a/packages/web/src/ssr/track.page.tsx +++ /dev/null @@ -1,186 +0,0 @@ -import React from 'react' - -import { - FieldVisibility, - Genre, - PremiumConditions, - decodeHashId -} from '@audius/common' -import cn from 'classnames' - -import RepostFavoritesStats from 'components/repost-favorites-stats/RepostFavoritesStats' -import { Tile } from 'components/tile' -import { CardTitle } from 'components/track/CardTitle' -import styles from 'components/track/GiantTrackTile.module.css' -import { Text } from 'components/typography' -import trackPageStyles from 'pages/track-page/components/desktop/TrackPage.module.css' -import { profilePage } from 'utils/route' - -import { TrackPageProps } from './track.page.server' - -export function Page(props: TrackPageProps) { - const { track } = props - - if (!track) { - return null - } - - // return ( - // {}} - // onPreview={() => {}} - // onShare={() => {}} - // onRepost={() => {}} - // onSave={() => {}} - // onFollow={() => {}} - // onUnfollow={() => {}} - // onDownload={() => {}} - // onMakePublic={() => {}} - // onClickReposts={() => {}} - // onClickFavorites={() => {}} - // /> - // ) - - const { - title, - id, - coverArtSizes, - _coSign, - isUnlisted, - remixOf, - isPremium, - genre, - premiumConditions - } = track - - return ( -
- -
- {/* */} -
-
- {/* */} -
-

{title}

-
- -
- - {/*
- - {isLongFormContent && isNewPodcastControlsEnabled - ? renderListenCount() - : null} -
*/} -
- {/*
- {aiAttributionUserId ? ( - } - className={styles.badgeAi} - textLabel={messages.generatedWithAi} - /> - ) : null} - {badge ? ( - - ) : null} -
*/} -
- - {/*
-
- - {renderReleased()} - {renderGenre()} - {renderMood()} - {credits ? ( - - ) : null} -
- {description ? ( - - {description} - - ) : null} -
*/} -
-
- ) -} diff --git a/packages/web/src/ssr/track/+Page.tsx b/packages/web/src/ssr/track/+Page.tsx new file mode 100644 index 00000000000..06b8116b441 --- /dev/null +++ b/packages/web/src/ssr/track/+Page.tsx @@ -0,0 +1,3 @@ +export default function render() { + return null +} diff --git a/packages/web/src/ssr/track/+onBeforeRender.tsx b/packages/web/src/ssr/track/+onBeforeRender.tsx new file mode 100644 index 00000000000..95804a2aa89 --- /dev/null +++ b/packages/web/src/ssr/track/+onBeforeRender.tsx @@ -0,0 +1,42 @@ +import type { Maybe } from '@audius/common' +import { sdk, full as FullSdk, Logger } from '@audius/sdk' +import { PageContextServer } from 'vike/types' + +const logger = new Logger({ logLevel: 'debug' }) + +// TODO: Configure for different envs +const audiusSdk = sdk({ + appName: 'audius.co', + services: { + logger + } +}) + +export type TrackPageProps = { + track: Maybe +} + +export async function onBeforeRender(pageContext: PageContextServer) { + const { handle, slug } = pageContext.routeParams + + try { + const { data: tracks } = await audiusSdk.full.tracks.getBulkTracks({ + permalink: [`${handle}/${slug}`] + }) + + const pageProps = { track: tracks?.[0] } + + return { + pageContext: { + pageProps + } + } + } catch (e) { + console.error('sdk error', handle, slug, e) + return { + pageContext: { + pageProps: {} + } + } + } +} diff --git a/packages/web/src/ssr/_default.page.client.tsx b/packages/web/src/ssr/track/+onRenderClient.tsx similarity index 65% rename from packages/web/src/ssr/_default.page.client.tsx rename to packages/web/src/ssr/track/+onRenderClient.tsx index 3e0e1d4a9a5..6c2d7c2c0b8 100644 --- a/packages/web/src/ssr/_default.page.client.tsx +++ b/packages/web/src/ssr/track/+onRenderClient.tsx @@ -2,15 +2,24 @@ import { full as FullSdk } from '@audius/sdk' import { hydrateRoot } from 'react-dom/client' import { PageContextClient } from 'vike/types' -import { Root } from '../Root' +import { Root } from '../../Root' +import { SsrContextProvider } from '../SsrContext' -import { SsrContextProvider } from './SsrContext' +import '../../index.css' + +import { Buffer } from 'buffer' + +import processBrowser from 'process/browser' + +window.global ||= window +window.Buffer = Buffer +window.process = { ...processBrowser, env: process.env } // Set this to false to turn off client hydration // Useful for testing the SSR output const HYDRATE_CLIENT = true -export async function render( +export default async function render( pageContext: PageContextClient & { pageProps: { track: FullSdk.TrackFull } } ) { const { pageProps, urlPathname } = pageContext diff --git a/packages/web/src/ssr/_default.page.server.tsx b/packages/web/src/ssr/track/+onRenderHtml.tsx similarity index 87% rename from packages/web/src/ssr/_default.page.server.tsx rename to packages/web/src/ssr/track/+onRenderHtml.tsx index cd02f13dbe6..8b0dc7cd492 100644 --- a/packages/web/src/ssr/_default.page.server.tsx +++ b/packages/web/src/ssr/track/+onRenderHtml.tsx @@ -4,14 +4,14 @@ import ReactDOMServer from 'react-dom/server' import { escapeInject, dangerouslySkipEscape } from 'vike/server' import { PageContextServer } from 'vike/types' -import indexHtml from '../../index.html?raw' -import { Root } from '../Root' +import indexHtml from '../../../index.html?raw' +import { Root } from '../../Root' -import { SsrContextProvider } from './SsrContext' +import { SsrContextProvider } from '../SsrContext' export const passToClient = ['pageProps', 'urlPathname'] -export function render( +export default function render( pageContext: PageContextServer & { pageProps: SsrPageProps } ) { const { pageProps, urlPathname } = pageContext diff --git a/packages/web/src/ssr/track.page.route.tsx b/packages/web/src/ssr/track/+route.tsx similarity index 100% rename from packages/web/src/ssr/track.page.route.tsx rename to packages/web/src/ssr/track/+route.tsx From 1229d699e07360a90e0e7dd405ea3d37943feb96 Mon Sep 17 00:00:00 2001 From: sliptype Date: Wed, 13 Dec 2023 15:43:47 -0600 Subject: [PATCH 21/74] Log better errors --- packages/web/scripts/workers-site/ssr.js | 2 +- packages/web/src/ssr/track/+onBeforeRender.tsx | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/web/scripts/workers-site/ssr.js b/packages/web/scripts/workers-site/ssr.js index 1cf434c890a..330ef6f07ac 100644 --- a/packages/web/scripts/workers-site/ssr.js +++ b/packages/web/scripts/workers-site/ssr.js @@ -8,7 +8,7 @@ export async function handleSsr(url) { const { httpResponse } = pageContext if (!httpResponse) { - return null + return new Response(pageContext.errorWhileRendering, { status: 500 }) } else { const { body, statusCode: status, headers } = httpResponse return new Response(body, { headers, status }) diff --git a/packages/web/src/ssr/track/+onBeforeRender.tsx b/packages/web/src/ssr/track/+onBeforeRender.tsx index 95804a2aa89..0b500984a16 100644 --- a/packages/web/src/ssr/track/+onBeforeRender.tsx +++ b/packages/web/src/ssr/track/+onBeforeRender.tsx @@ -32,7 +32,15 @@ export async function onBeforeRender(pageContext: PageContextServer) { } } } catch (e) { - console.error('sdk error', handle, slug, e) + console.error( + 'Error fetching track for track page SSR', + 'handle', + handle, + 'slug', + slug, + 'error', + e + ) return { pageContext: { pageProps: {} From 066c7a8be1b5acf62cc8c5806be751dbb0c89743 Mon Sep 17 00:00:00 2001 From: sliptype Date: Wed, 13 Dec 2023 17:34:49 -0600 Subject: [PATCH 22/74] Clean up vike v1 design usage --- packages/web/src/ssr/{track => }/+onRenderClient.tsx | 9 +++++---- packages/web/src/ssr/{track => }/+onRenderHtml.tsx | 6 +++--- packages/web/src/ssr/index/+Page.tsx | 1 + .../web/{renderer => src/ssr/index}/+onRenderClient.tsx | 8 +++++--- .../web/{renderer => src/ssr/index}/+onRenderHtml.tsx | 6 +++--- packages/web/src/ssr/index/+route.ts | 3 ++- packages/web/src/ssr/track/+Page.tsx | 1 + 7 files changed, 20 insertions(+), 14 deletions(-) rename packages/web/src/ssr/{track => }/+onRenderClient.tsx (85%) rename packages/web/src/ssr/{track => }/+onRenderHtml.tsx (89%) rename packages/web/{renderer => src/ssr/index}/+onRenderClient.tsx (72%) rename packages/web/{renderer => src/ssr/index}/+onRenderHtml.tsx (75%) diff --git a/packages/web/src/ssr/track/+onRenderClient.tsx b/packages/web/src/ssr/+onRenderClient.tsx similarity index 85% rename from packages/web/src/ssr/track/+onRenderClient.tsx rename to packages/web/src/ssr/+onRenderClient.tsx index 6c2d7c2c0b8..dcfa476e574 100644 --- a/packages/web/src/ssr/track/+onRenderClient.tsx +++ b/packages/web/src/ssr/+onRenderClient.tsx @@ -2,10 +2,11 @@ import { full as FullSdk } from '@audius/sdk' import { hydrateRoot } from 'react-dom/client' import { PageContextClient } from 'vike/types' -import { Root } from '../../Root' -import { SsrContextProvider } from '../SsrContext' +import { Root } from '../Root' -import '../../index.css' +import { SsrContextProvider } from './SsrContext' + +import '../index.css' import { Buffer } from 'buffer' @@ -17,7 +18,7 @@ window.process = { ...processBrowser, env: process.env } // Set this to false to turn off client hydration // Useful for testing the SSR output -const HYDRATE_CLIENT = true +const HYDRATE_CLIENT = false export default async function render( pageContext: PageContextClient & { pageProps: { track: FullSdk.TrackFull } } diff --git a/packages/web/src/ssr/track/+onRenderHtml.tsx b/packages/web/src/ssr/+onRenderHtml.tsx similarity index 89% rename from packages/web/src/ssr/track/+onRenderHtml.tsx rename to packages/web/src/ssr/+onRenderHtml.tsx index 8b0dc7cd492..b1637d1232c 100644 --- a/packages/web/src/ssr/track/+onRenderHtml.tsx +++ b/packages/web/src/ssr/+onRenderHtml.tsx @@ -4,10 +4,10 @@ import ReactDOMServer from 'react-dom/server' import { escapeInject, dangerouslySkipEscape } from 'vike/server' import { PageContextServer } from 'vike/types' -import indexHtml from '../../../index.html?raw' -import { Root } from '../../Root' +import indexHtml from '../../index.html?raw' +import { Root } from '../Root' -import { SsrContextProvider } from '../SsrContext' +import { SsrContextProvider } from './SsrContext' export const passToClient = ['pageProps', 'urlPathname'] diff --git a/packages/web/src/ssr/index/+Page.tsx b/packages/web/src/ssr/index/+Page.tsx index 06b8116b441..3d380236636 100644 --- a/packages/web/src/ssr/index/+Page.tsx +++ b/packages/web/src/ssr/index/+Page.tsx @@ -1,3 +1,4 @@ +// Empty page, everything is handled in +onRenderHtml and +onRenderClient export default function render() { return null } diff --git a/packages/web/renderer/+onRenderClient.tsx b/packages/web/src/ssr/index/+onRenderClient.tsx similarity index 72% rename from packages/web/renderer/+onRenderClient.tsx rename to packages/web/src/ssr/index/+onRenderClient.tsx index d42088df91d..14da41453a8 100644 --- a/packages/web/renderer/+onRenderClient.tsx +++ b/packages/web/src/ssr/index/+onRenderClient.tsx @@ -1,13 +1,15 @@ -// By default, simply render the SPA without SSR +// For all routes except the explicitly defined ones (Track) +// simply render the SPA without SSR import 'setimmediate' import { Buffer } from 'buffer' import processBrowser from 'process/browser' import { createRoot } from 'react-dom/client' -import { Root } from '../src/Root' -import '../src/index.css' +import { Root } from '../../Root' + +import '../../index.css' window.global ||= window window.Buffer = Buffer diff --git a/packages/web/renderer/+onRenderHtml.tsx b/packages/web/src/ssr/index/+onRenderHtml.tsx similarity index 75% rename from packages/web/renderer/+onRenderHtml.tsx rename to packages/web/src/ssr/index/+onRenderHtml.tsx index 4e3a411c144..5791e19ecff 100644 --- a/packages/web/renderer/+onRenderHtml.tsx +++ b/packages/web/src/ssr/index/+onRenderHtml.tsx @@ -1,9 +1,9 @@ -// By default, don't do any server side rendering -// Just serve the static HTML +// For all routes except the explicitly defined ones (Track) +// simply render the SPA without SSR import { escapeInject, dangerouslySkipEscape } from 'vike/server' -import indexHtml from '../index.html?raw' +import indexHtml from '../../../index.html?raw' export function render() { const pattern = /%(\S+?)%/g diff --git a/packages/web/src/ssr/index/+route.ts b/packages/web/src/ssr/index/+route.ts index 2d1b6370b4c..76163e4fc18 100644 --- a/packages/web/src/ssr/index/+route.ts +++ b/packages/web/src/ssr/index/+route.ts @@ -1,3 +1,4 @@ -// All routes exported here will skip SSR +// All routes skip SSR +// Except the explicitly defined routes (Track) export default '/*' diff --git a/packages/web/src/ssr/track/+Page.tsx b/packages/web/src/ssr/track/+Page.tsx index 06b8116b441..3d380236636 100644 --- a/packages/web/src/ssr/track/+Page.tsx +++ b/packages/web/src/ssr/track/+Page.tsx @@ -1,3 +1,4 @@ +// Empty page, everything is handled in +onRenderHtml and +onRenderClient export default function render() { return null } From 04fed69e6bd7d812b8e3622e20adfa980dc36c88 Mon Sep 17 00:00:00 2001 From: sliptype Date: Thu, 14 Dec 2023 11:12:58 -0600 Subject: [PATCH 23/74] Fix setImmediate error --- packages/web/src/ssr/+onRenderClient.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/web/src/ssr/+onRenderClient.tsx b/packages/web/src/ssr/+onRenderClient.tsx index dcfa476e574..93223e031c4 100644 --- a/packages/web/src/ssr/+onRenderClient.tsx +++ b/packages/web/src/ssr/+onRenderClient.tsx @@ -1,4 +1,8 @@ +import { Buffer } from 'buffer' + +import 'setimmediate' import { full as FullSdk } from '@audius/sdk' +import processBrowser from 'process/browser' import { hydrateRoot } from 'react-dom/client' import { PageContextClient } from 'vike/types' @@ -8,17 +12,13 @@ import { SsrContextProvider } from './SsrContext' import '../index.css' -import { Buffer } from 'buffer' - -import processBrowser from 'process/browser' - window.global ||= window window.Buffer = Buffer window.process = { ...processBrowser, env: process.env } // Set this to false to turn off client hydration // Useful for testing the SSR output -const HYDRATE_CLIENT = false +const HYDRATE_CLIENT = true export default async function render( pageContext: PageContextClient & { pageProps: { track: FullSdk.TrackFull } } From 78821ee514a1d303fc348f241cc96ffe9d0eaa64 Mon Sep 17 00:00:00 2001 From: sliptype Date: Thu, 14 Dec 2023 11:16:22 -0600 Subject: [PATCH 24/74] Simple ClientOnly --- .../src/components/client-only/ClientOnly.tsx | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/web/src/components/client-only/ClientOnly.tsx b/packages/web/src/components/client-only/ClientOnly.tsx index cd3f3c1d993..09b716a6d98 100644 --- a/packages/web/src/components/client-only/ClientOnly.tsx +++ b/packages/web/src/components/client-only/ClientOnly.tsx @@ -1,18 +1,25 @@ -import { ReactNode, Suspense, useEffect, useState } from 'react' +import { ReactNode, useEffect, useState } from 'react' type ClientOnlyProps = { children: ReactNode fallback?: ReactNode } +/** + * A simple wrapper that only renders its children on the client. + * This is used to disable certain parts of the app from rendering on the server. + * + * If you need to lazy load something on the client only, use vike-react/ClientOnly + */ export const ClientOnly = (props: ClientOnlyProps) => { - const { children, fallback } = props + const { children, fallback = null } = props - const [clientChildren, setClientChildren] = useState(fallback) + const [isClientSide, setIsClientSide] = useState(false) + // useEffect only runs on the client useEffect(() => { - setClientChildren(children) + setIsClientSide(true) }, []) - return {clientChildren} + return <>{isClientSide ? children : fallback} } From 4e254696c533844c50eaeb7ab683202d2d44cb94 Mon Sep 17 00:00:00 2001 From: sliptype Date: Thu, 14 Dec 2023 11:30:30 -0600 Subject: [PATCH 25/74] Fix Popup ssr --- packages/stems/src/components/ClientOnly.tsx | 18 ---- packages/stems/src/components/Popup/Popup.tsx | 100 ++++++++++-------- 2 files changed, 53 insertions(+), 65 deletions(-) delete mode 100644 packages/stems/src/components/ClientOnly.tsx diff --git a/packages/stems/src/components/ClientOnly.tsx b/packages/stems/src/components/ClientOnly.tsx deleted file mode 100644 index 55323e9b9ca..00000000000 --- a/packages/stems/src/components/ClientOnly.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { ReactNode, Suspense, useEffect, useState } from 'react' - -type ClientOnlyProps = { - children: () => ReactNode - fallback?: ReactNode -} - -export const ClientOnly = (props: ClientOnlyProps) => { - const { children, fallback } = props - - const [clientChildren, setClientChildren] = useState(() => () => fallback) - - useEffect(() => { - setClientChildren(() => children) - }, []) - - return {clientChildren()} -} diff --git a/packages/stems/src/components/Popup/Popup.tsx b/packages/stems/src/components/Popup/Popup.tsx index 702db91dcfe..138ec63dc02 100644 --- a/packages/stems/src/components/Popup/Popup.tsx +++ b/packages/stems/src/components/Popup/Popup.tsx @@ -13,7 +13,6 @@ import ReactDOM from 'react-dom' // eslint-disable-next-line no-restricted-imports -- TODO: migrate to @react-spring/web import { useTransition, animated } from 'react-spring' -import { ClientOnly } from 'components/ClientOnly' import { IconButton } from 'components/IconButton' import { IconRemove } from 'components/Icons' import { useClickOutside } from 'hooks/useClickOutside' @@ -260,6 +259,8 @@ export const Popup = forwardRef(function Popup( zIndex, containerRef } = props + const [isClientSide, setIsClientSide] = useState(false) + const handleClose = useCallback(() => { onClose() setTimeout(() => { @@ -417,54 +418,59 @@ export const Popup = forwardRef(function Popup( } }, [dismissOnMouseLeave, onClose]) + // useEffect only runs on the client + useEffect(() => { + setIsClientSide(true) + }, []) + // Portal the popup out of the dom structure so that it has a separate stacking context return ( - - {() => - ReactDOM.createPortal( -
- {transitions.map(({ item, key, props }) => - item ? ( - - {showHeader && ( -
- {hideCloseButton ? null : ( - } - /> - )} -
- {title} + <> + {isClientSide + ? ReactDOM.createPortal( +
+ {transitions.map(({ item, key, props }) => + item ? ( + + {showHeader && ( +
+ {hideCloseButton ? null : ( + } + /> + )} +
+ {title} +
-
- )} - {children} - - ) : null - )} -
, - document.body - ) - } - + )} + {children} + + ) : null + )} +
, + document.body + ) + : null} + ) }) From f1d464ae7595fa4b74a1f710a830ffd532fc952e Mon Sep 17 00:00:00 2001 From: sliptype Date: Thu, 14 Dec 2023 12:16:24 -0600 Subject: [PATCH 26/74] Configure sdk ssr for different envs --- .../web/src/ssr/track/+onBeforeRender.tsx | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/packages/web/src/ssr/track/+onBeforeRender.tsx b/packages/web/src/ssr/track/+onBeforeRender.tsx index 0b500984a16..b64445d71b1 100644 --- a/packages/web/src/ssr/track/+onBeforeRender.tsx +++ b/packages/web/src/ssr/track/+onBeforeRender.tsx @@ -1,14 +1,31 @@ import type { Maybe } from '@audius/common' -import { sdk, full as FullSdk, Logger } from '@audius/sdk' +import { + sdk, + full as FullSdk, + DiscoveryNodeSelector, + productionConfig, + stagingConfig, + developmentConfig +} from '@audius/sdk' import { PageContextServer } from 'vike/types' -const logger = new Logger({ logLevel: 'debug' }) +const sdkConfigs = { + production: productionConfig, + staging: stagingConfig, + development: developmentConfig +} + +const discoveryNodeSelector = new DiscoveryNodeSelector({ + bootstrapServices: ( + sdkConfigs[process.env.VITE_ENVIRONMENT as keyof typeof sdkConfigs] ?? + productionConfig + ).discoveryNodes +}) -// TODO: Configure for different envs const audiusSdk = sdk({ - appName: 'audius.co', + appName: process.env.VITE_PUBLIC_HOSTNAME ?? 'audius.co', services: { - logger + discoveryNodeSelector } }) From f61f6cfd81869f8bca5f52f0870d5ae82b1a2109 Mon Sep 17 00:00:00 2001 From: sliptype Date: Thu, 14 Dec 2023 15:04:30 -0600 Subject: [PATCH 27/74] Fix search routing bugs --- .../pages/search-page/SearchPageProvider.jsx | 14 ++++----- packages/web/src/pages/search-page/helpers.ts | 29 ++++++++++--------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/packages/web/src/pages/search-page/SearchPageProvider.jsx b/packages/web/src/pages/search-page/SearchPageProvider.jsx index cce91200ecf..5aae6686dcc 100644 --- a/packages/web/src/pages/search-page/SearchPageProvider.jsx +++ b/packages/web/src/pages/search-page/SearchPageProvider.jsx @@ -16,6 +16,7 @@ import { connect } from 'react-redux' import { Redirect } from 'react-router' import { withRouter } from 'react-router-dom' +import { HistoryContext } from 'app/HistoryProvider' import { make } from 'common/store/analytics/actions' import { NOT_FOUND_PAGE, @@ -23,7 +24,6 @@ import { SEARCH_PAGE, doesMatchRoute } from 'utils/route' -import { HistoryContext } from 'app/HistoryProvider' import * as helpers from './helpers' const { makeGetCurrent } = queueSelectors @@ -41,11 +41,9 @@ const getUserId = accountSelectors.getUserId class SearchPageProvider extends Component { static contextType = HistoryContext - constructor(props) { + constructor(props, context) { super(props) - const searchResultsCategory = helpers.getCategory( - this.context.history.location - ) + const searchResultsCategory = helpers.getCategory(context.history.location) this.state = { searchResultsCategory @@ -58,7 +56,7 @@ class SearchPageProvider extends Component { this.unlisten = this.props.history.listen((location, action) => { // Make sure the serach bar shows on every search-navigation if (window.scrollTo) window.scrollTo(0, 0) - const isTagSearch = helpers.isTagSearch() + const isTagSearch = helpers.isTagSearch(this.context.history.location) const searchMatch = helpers.getSearchText(this.context.history.location) const category = helpers.getCategory(this.context.history.location) @@ -78,7 +76,7 @@ class SearchPageProvider extends Component { this.props.scrollToTop() }) - const isTagSearch = helpers.isTagSearch() + const isTagSearch = helpers.isTagSearch(this.context.history.location) const query = isTagSearch ? helpers.getSearchTag(this.context.history.location) : helpers.getSearchText(this.context.history.location) @@ -150,7 +148,7 @@ class SearchPageProvider extends Component { searchText: helpers.getQuery(this.context.history.location), handleViewMoreResults: this.handleViewMoreResults, searchResultsCategory: this.state.searchResultsCategory, - isTagSearch: helpers.isTagSearch() + isTagSearch: helpers.isTagSearch(this.context.history.location) } return } diff --git a/packages/web/src/pages/search-page/helpers.ts b/packages/web/src/pages/search-page/helpers.ts index 2d0f77803ff..4c9ad6d4ad4 100644 --- a/packages/web/src/pages/search-page/helpers.ts +++ b/packages/web/src/pages/search-page/helpers.ts @@ -1,4 +1,5 @@ import { SearchKind } from '@audius/common' +import { Location } from 'history' import { matchPath } from 'react-router' import { getPathname } from 'utils/route' @@ -17,21 +18,21 @@ const DESKTOP_ALL_CATEGORY_RESULTS_LIMIT = 15 const MOBILE_ALL_CATEGORY_RESULTS_LIMIT = 15 const DESKTOP_SINGLE_CATEGORY_RESULTS_LIMIT = 40 -export const isTagSearch = () => { +export const isTagSearch = (location: Location) => { if (USE_HASH_ROUTING) { // URL will look like /#/search/#tag, so check if there are // more than two things when we split on # - return window.location.hash.split('#').length > 2 + return location.hash.split('#').length > 2 } - return !!window.location.hash + return !!location.hash } -export const getCategory = (pathname: string) => { +export const getCategory = (location: Location) => { let category - if (isTagSearch()) { - category = window.location.hash.slice(1).split('/')[1] + if (isTagSearch(location)) { + category = location.hash.slice(1).split('/')[1] } else { - const categoryMatch = matchPath(pathname, { + const categoryMatch = matchPath(getPathname(location), { path: '/search/:query/:category', exact: true }) as match @@ -55,16 +56,16 @@ export const getCategory = (pathname: string) => { return SearchKind.ALL } -export const getSearchTag = (pathname: string) => { +export const getSearchTag = (location: Location) => { // Trim off the leading '#' and remove any other paths (e.g. category) if (USE_HASH_ROUTING) { - return pathname.split('#')[1].split('/')[0] + return getPathname(location).split('#')[1].split('/')[0] } - return window.location.hash.slice(1).split('/')[0] + return location.hash.slice(1).split('/')[0] } -export const getSearchText = (pathname: string) => { - const match = matchPath(pathname, { +export const getSearchText = (location: Location) => { + const match = matchPath(getPathname(location), { path: '/search/:query' }) as match if (!match) return '' @@ -82,8 +83,8 @@ export const getSearchText = (pathname: string) => { // Returns a full query (e.g. `#rap` or `rap`), as opposed to // `getSearchTag` which strips leading # from tags -export const getQuery = (pathname: string) => - isTagSearch() ? `#${getSearchTag(pathname)}` : getSearchText(pathname) +export const getQuery = (location: Location) => + isTagSearch(location) ? `#${getSearchTag(location)}` : getSearchText(location) export const getResultsLimit = (isMobile: boolean, category: SearchKind) => { return isMobile From 0b5dea7df393511602a31dac84865b26031ea386 Mon Sep 17 00:00:00 2001 From: sliptype Date: Thu, 14 Dec 2023 15:14:39 -0600 Subject: [PATCH 28/74] Fix feed redirect --- packages/web/src/app/web-player/WebPlayer.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/web/src/app/web-player/WebPlayer.jsx b/packages/web/src/app/web-player/WebPlayer.jsx index e07f12633a5..d638b247c44 100644 --- a/packages/web/src/app/web-player/WebPlayer.jsx +++ b/packages/web/src/app/web-player/WebPlayer.jsx @@ -958,9 +958,9 @@ class WebPlayer extends Component { // pathname is not HOME_PAGE. Double check that it is and if not, // just trigger a react router push to the current pathname pathname: - getPathname(this.props.history) === HOME_PAGE + getPathname(this.props.history.location) === HOME_PAGE ? FEED_PAGE - : getPathname(this.props.history), + : getPathname(this.props.history.location), search: includeSearch(this.props.location.search) ? this.props.location.search : '' From 98447f5f04c1877cc07209141f07e0d3f862d56e Mon Sep 17 00:00:00 2001 From: sliptype Date: Tue, 19 Dec 2023 16:30:21 -0600 Subject: [PATCH 29/74] Tweaks --- packages/web/scripts/workers-site/index.js | 2 +- packages/web/src/ssr/+passToClient.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 packages/web/src/ssr/+passToClient.tsx diff --git a/packages/web/scripts/workers-site/index.js b/packages/web/scripts/workers-site/index.js index a7e99585604..89e2c0bb777 100644 --- a/packages/web/scripts/workers-site/index.js +++ b/packages/web/scripts/workers-site/index.js @@ -4,7 +4,7 @@ import { handleSsr } from './ssr' /* globals GA, GA_ACCESS_TOKEN, EMBED, DISCOVERY_NODES, HTMLRewriter */ -const DEBUG = true +const DEBUG = false const BROWSER_CACHE_TTL_SECONDS = 60 * 60 * 24 const discoveryNodes = DISCOVERY_NODES.split(',') diff --git a/packages/web/src/ssr/+passToClient.tsx b/packages/web/src/ssr/+passToClient.tsx new file mode 100644 index 00000000000..2a1dde4cec3 --- /dev/null +++ b/packages/web/src/ssr/+passToClient.tsx @@ -0,0 +1 @@ +export const passToClient = ['pageProps', 'urlPathname'] From b012854ba90e17acfdfaea94a8b02e4624c957d4 Mon Sep 17 00:00:00 2001 From: sliptype Date: Thu, 4 Jan 2024 13:53:14 -0600 Subject: [PATCH 30/74] Convert worker to module syntax --- packages/web/scripts/workers-site/index.js | 91 +++++++++++++--------- 1 file changed, 53 insertions(+), 38 deletions(-) diff --git a/packages/web/scripts/workers-site/index.js b/packages/web/scripts/workers-site/index.js index 89e2c0bb777..f36c2db7dee 100644 --- a/packages/web/scripts/workers-site/index.js +++ b/packages/web/scripts/workers-site/index.js @@ -1,16 +1,12 @@ -import { getAssetFromKV, mapRequestToAsset } from '@cloudflare/kv-asset-handler' - -import { handleSsr } from './ssr' - -/* globals GA, GA_ACCESS_TOKEN, EMBED, DISCOVERY_NODES, HTMLRewriter */ +import { getAssetFromKV } from '@cloudflare/kv-asset-handler' +import manifestJSON from '__STATIC_CONTENT_MANIFEST' +const assetManifest = JSON.parse(manifestJSON) +import { handleSsr } from './ssr.js' +const SSR = true const DEBUG = false const BROWSER_CACHE_TTL_SECONDS = 60 * 60 * 24 -const discoveryNodes = DISCOVERY_NODES.split(',') -const discoveryNode = - discoveryNodes[Math.floor(Math.random() * discoveryNodes.length)] - let h1 = null const routes = [ @@ -32,21 +28,6 @@ const routes = [ } ] -addEventListener('fetch', (event) => { - try { - event.respondWith(handleEvent(event)) - } catch (e) { - if (DEBUG) { - return event.respondWith( - new Response(e.message || e.toString(), { - status: 500 - }) - ) - } - event.respondWith(new Response('Internal Error', { status: 500 })) - } -}) - function matchRoute(input) { for (const route of routes) { const match = route.pattern.exec(input) @@ -228,8 +209,8 @@ class SEOHandlerHead { } } -async function handleEvent(event) { - const url = new URL(event.request.url) +async function handleEvent(request, env, ctx) { + const url = new URL(request.url) const { pathname, search, hash } = url const isUndefined = pathname === '/undefined' @@ -237,14 +218,18 @@ async function handleEvent(event) { return Response.redirect(url.origin, 302) } + const discoveryNodes = env.DISCOVERY_NODES.split(',') + const discoveryNode = + discoveryNodes[Math.floor(Math.random() * discoveryNodes.length)] + const isSitemap = pathname.startsWith('/sitemaps') if (isSitemap) { const destinationURL = discoveryNode + pathname + search + hash - const newRequest = new Request(destinationURL, event.request) + const newRequest = new Request(destinationURL, request) return await fetch(newRequest) } - const userAgent = event.request.headers.get('User-Agent') || '' + const userAgent = request.headers.get('User-Agent') || '' const is204 = pathname === '/204' if (is204) { @@ -257,18 +242,18 @@ async function handleEvent(event) { const isBot = checkIsBot(userAgent) if (isBot) { - const destinationURL = GA + pathname + search + hash - const newRequest = new Request(destinationURL, event.request) - newRequest.headers.set('host', GA) - newRequest.headers.set('x-access-token', GA_ACCESS_TOKEN) + const destinationURL = env.GA + pathname + search + hash + const newRequest = new Request(destinationURL, request) + newRequest.headers.set('host', env.GA) + newRequest.headers.set('x-access-token', env.GA_ACCESS_TOKEN) return await fetch(newRequest) } const isEmbed = pathname.startsWith('/embed') if (isEmbed) { - const destinationURL = EMBED + pathname + search + hash - const newRequest = new Request(destinationURL, event.request) + const destinationURL = env.EMBED + pathname + search + hash + const newRequest = new Request(destinationURL, request) return await fetch(newRequest) } @@ -283,16 +268,31 @@ async function handleEvent(event) { } } - if (!isAssetUrl(event.request.url)) { - const response = await handleSsr(event.request.url) - if (response !== null) return response + if (!isAssetUrl(request.url)) { + if (SSR) { + const response = await handleSsr(request.url) + if (response !== null) return response + } else { + // TODO: return normal SPA + return new Response('hi') + } } else { // Adjust browser cache on assets that don't change frequently and/or // are given unique hashes when they do. - const asset = await getAssetFromKV(event, options) + const asset = await getAssetFromKV( + { + request, + waitUntil: ctx.waitUntil.bind(ctx) + }, + { + ASSET_NAMESPACE: env.__STATIC_CONTENT, + ASSET_MANIFEST: assetManifest + } + ) const response = new Response(asset.body, asset) response.headers.set('cache-control', BROWSER_CACHE_TTL_SECONDS) + return response } } catch (e) { @@ -310,3 +310,18 @@ function isAssetUrl(url) { pathname.startsWith('/manifest.json') ) } + +export default { + fetch(request, env, ctx) { + try { + return handleEvent(request, env, ctx) + } catch (e) { + if (DEBUG) { + return new Response(e.message || e.toString(), { + status: 500 + }) + } + return new Response('Internal Error', { status: 500 }) + } + } +} From ecd14b9494d83e657e3c77cceaa33a96d85a16b8 Mon Sep 17 00:00:00 2001 From: sliptype Date: Sat, 6 Jan 2024 14:48:27 -0600 Subject: [PATCH 31/74] Set up dual worker ssr --- packages/web/scripts/workers-site/index.js | 5 ++- .../{scripts/workers-site => src/ssr}/ssr.js | 5 ++- packages/web/src/ssr/worker.js | 34 +++++++++++++++++++ packages/web/src/ssr/wrangler.toml | 12 +++++++ packages/web/wrangler.toml | 3 ++ 5 files changed, 55 insertions(+), 4 deletions(-) rename packages/web/{scripts/workers-site => src/ssr}/ssr.js (78%) create mode 100644 packages/web/src/ssr/worker.js create mode 100644 packages/web/src/ssr/wrangler.toml diff --git a/packages/web/scripts/workers-site/index.js b/packages/web/scripts/workers-site/index.js index f36c2db7dee..4ba6fb4586e 100644 --- a/packages/web/scripts/workers-site/index.js +++ b/packages/web/scripts/workers-site/index.js @@ -1,7 +1,6 @@ import { getAssetFromKV } from '@cloudflare/kv-asset-handler' import manifestJSON from '__STATIC_CONTENT_MANIFEST' const assetManifest = JSON.parse(manifestJSON) -import { handleSsr } from './ssr.js' const SSR = true const DEBUG = false @@ -270,8 +269,8 @@ async function handleEvent(request, env, ctx) { if (!isAssetUrl(request.url)) { if (SSR) { - const response = await handleSsr(request.url) - if (response !== null) return response + const ssrResponse = await env.SSR.fetch(request.clone()) + return ssrResponse } else { // TODO: return normal SPA return new Response('hi') diff --git a/packages/web/scripts/workers-site/ssr.js b/packages/web/src/ssr/ssr.js similarity index 78% rename from packages/web/scripts/workers-site/ssr.js rename to packages/web/src/ssr/ssr.js index 330ef6f07ac..7a9e4c4a2e0 100644 --- a/packages/web/scripts/workers-site/ssr.js +++ b/packages/web/src/ssr/ssr.js @@ -1,9 +1,12 @@ -import { renderPage } from 'vike/server' +import { renderPage } from './node_modules/vike/server' export async function handleSsr(url) { const pageContextInit = { urlOriginal: url } + + // const { renderPage } = await import('vike/server') + const pageContext = await renderPage(pageContextInit) const { httpResponse } = pageContext diff --git a/packages/web/src/ssr/worker.js b/packages/web/src/ssr/worker.js new file mode 100644 index 00000000000..af0fdc2f823 --- /dev/null +++ b/packages/web/src/ssr/worker.js @@ -0,0 +1,34 @@ +import { renderPage } from 'vike/server' + +const DEBUG = true + +addEventListener('fetch', (event) => { + try { + event.respondWith(handleEvent(event)) + } catch (e) { + if (DEBUG) { + return event.respondWith( + new Response(e.message || e.toString(), { + status: 500 + }) + ) + } + event.respondWith(new Response('Internal Error', { status: 500 })) + } +}) + +async function handleEvent(event) { + const pageContextInit = { + urlOriginal: event.request.url + } + + const pageContext = await renderPage(pageContextInit) + + const { httpResponse } = pageContext + if (!httpResponse) { + throw new Error(pageContext.errorWhileRendering) + } else { + const { body, statusCode: status, headers } = httpResponse + return new Response(body, { headers, status }) + } +} diff --git a/packages/web/src/ssr/wrangler.toml b/packages/web/src/ssr/wrangler.toml new file mode 100644 index 00000000000..05e89560a8a --- /dev/null +++ b/packages/web/src/ssr/wrangler.toml @@ -0,0 +1,12 @@ +compatibility_date = "2023-10-25" +account_id = "3811365464a8e56b2b27a5590e328e49" +main = "./worker.js" +node_compat = true + +[site] +bucket = "../../build/client" + +# Invoke with npx wrangler dev --watch --env test +[env.test] +name = "audius-web-ssr" +route = "ssr.audius.co/*" \ No newline at end of file diff --git a/packages/web/wrangler.toml b/packages/web/wrangler.toml index 169f39c105b..83deabf6fc8 100644 --- a/packages/web/wrangler.toml +++ b/packages/web/wrangler.toml @@ -26,4 +26,7 @@ vars = { ENVIRONMENT = "production", GA = "https://general-admission.audius.co", # Invoke with npx wrangler dev --watch --env test [env.test] name = "test" +services = [ + { binding = "SSR", service = "audius-web-ssr" } +] vars = { ENVIRONMENT = "production", GA = "https://general-admission.audius.co", EMBED = "https://embed.audius.workers.dev", DISCOVERY_NODES = "https://discoveryprovider.audius.co,https://discoveryprovider2.audius.co,https://discoveryprovider3.audius.co" } \ No newline at end of file From 054e15ad5eda8f875ed0879b565ad29b72749fb7 Mon Sep 17 00:00:00 2001 From: sliptype Date: Sat, 6 Jan 2024 16:12:34 -0600 Subject: [PATCH 32/74] Get parallel SPA/SSR builds working + dual worker --- packages/web/.gitignore | 1 + packages/web/index.html | 25 ++- packages/web/package.json | 1 + packages/web/scripts/workers-site/index.js | 77 ++++--- packages/web/src/ssr/+onRenderHtml.tsx | 2 +- packages/web/src/ssr/index.html | 208 +++++++++++++++++++ packages/web/src/ssr/index/+onRenderHtml.tsx | 2 +- packages/web/src/ssr/worker.js | 44 +++- packages/web/src/ssr/wrangler.toml | 2 +- packages/web/vite.config.ts | 7 +- packages/web/wrangler.toml | 2 +- 11 files changed, 323 insertions(+), 48 deletions(-) create mode 100644 packages/web/src/ssr/index.html diff --git a/packages/web/.gitignore b/packages/web/.gitignore index fb103863500..eafe7808c5e 100644 --- a/packages/web/.gitignore +++ b/packages/web/.gitignore @@ -23,6 +23,7 @@ /build-ci /build-production /build-mobile-production +/build-ssr /storybook-static /build-ipfs-staging /build-ipfs-staging.zip diff --git a/packages/web/index.html b/packages/web/index.html index f10a20b9d59..dbc1b93d106 100644 --- a/packages/web/index.html +++ b/packages/web/index.html @@ -54,6 +54,13 @@ + + @@ -122,6 +132,8 @@ const adroll_pix_id = '%VITE_ADROLL_PIX_ID%' const adroll_version = '2.0' if ( + nodeEnv === 'production' && + reactEnv === 'production' && !adroll_adv_id.includes('%') && !adroll_pix_id.includes('%') ) { @@ -194,6 +206,7 @@
+ diff --git a/packages/web/package.json b/packages/web/package.json index 93d42ae26eb..ef1b91f5ac0 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -14,6 +14,7 @@ "preview:prod": "npm run build:prod && vite preview --outDir build-production", "prebuild": "npm run publish-scripts", "build": "vite build && cp package.json build/package.json", + "build:ssr": "npm run write-sha && env-cmd ./.env/.env.git env-cmd ./.env/.env.prod env-cmd ./.env/.env.ssr turbo run build", "build:dev": "npm run write-sha && env-cmd ./.env/.env.git env-cmd ./.env/.env.dev turbo run build && rm -rf build-development && mv build build-development", "build:stage": "npm run write-sha && env-cmd ./.env/.env.git env-cmd ./.env/.env.stage turbo run build && rm -rf build-staging && mv build build-staging", "build:prod": "npm run write-sha && env-cmd ./.env/.env.git env-cmd ./.env/.env.prod turbo run build && rm -rf build-production && mv build build-production", diff --git a/packages/web/scripts/workers-site/index.js b/packages/web/scripts/workers-site/index.js index 4ba6fb4586e..fe6bc643c39 100644 --- a/packages/web/scripts/workers-site/index.js +++ b/packages/web/scripts/workers-site/index.js @@ -1,5 +1,8 @@ -import { getAssetFromKV } from '@cloudflare/kv-asset-handler' +import { getAssetFromKV, mapRequestToAsset } from '@cloudflare/kv-asset-handler' import manifestJSON from '__STATIC_CONTENT_MANIFEST' + +/* globals HTMLRewriter */ + const assetManifest = JSON.parse(manifestJSON) const SSR = true @@ -50,7 +53,7 @@ function checkIsBot(val) { return botTest.test(val) } -async function getMetadata(pathname) { +async function getMetadata(pathname, discoveryNode) { if (pathname.startsWith('/scripts')) { return { metadata: null, name: null } } @@ -120,12 +123,16 @@ class SEOHandlerBody { } class SEOHandlerHead { - constructor(pathname) { + constructor(pathname, discoveryNode) { self.pathname = pathname + self.discoveryNode = discoveryNode } async element(element) { - const { metadata, name } = await getMetadata(self.pathname) + const { metadata, name } = await getMetadata( + self.pathname, + self.discoveryNode + ) if (!metadata || !name || !metadata.data || metadata.data.length === 0) { // We didn't parse this to anything we have custom tags for, so just return the default tags @@ -267,38 +274,56 @@ async function handleEvent(request, env, ctx) { } } - if (!isAssetUrl(request.url)) { - if (SSR) { - const ssrResponse = await env.SSR.fetch(request.clone()) - return ssrResponse - } else { - // TODO: return normal SPA - return new Response('hi') - } + if (SSR) { + const ssrResponse = await env.SSR.fetch(request.clone()) + return ssrResponse } else { - // Adjust browser cache on assets that don't change frequently and/or - // are given unique hashes when they do. - const asset = await getAssetFromKV( - { - request, - waitUntil: ctx.waitUntil.bind(ctx) - }, - { - ASSET_NAMESPACE: env.__STATIC_CONTENT, - ASSET_MANIFEST: assetManifest + if (!isAssetUrl(request.url)) { + // Map all non-asset requests to the root path + options.mapRequestToAsset = (request) => { + const url = new URL(request.url) + url.pathname = `/` + return mapRequestToAsset(new Request(url, request)) } - ) - const response = new Response(asset.body, asset) - response.headers.set('cache-control', BROWSER_CACHE_TTL_SECONDS) + const asset = await getAsset(request, env, ctx, options) + + const rewritten = new HTMLRewriter() + .on('head', new SEOHandlerHead(pathname, discoveryNode)) + .on('body', new SEOHandlerBody()) + .transform(asset) + + return rewritten + } else { + const asset = await getAsset(request, env, ctx, options) - return response + // Adjust browser cache on assets that don't change frequently and/or + // are given unique hashes when they do. + const response = new Response(asset.body, asset) + response.headers.set('cache-control', BROWSER_CACHE_TTL_SECONDS) + + return response + } } } catch (e) { return new Response(e.message || e.toString(), { status: 500 }) } } +async function getAsset(request, env, ctx, options) { + return await getAssetFromKV( + { + request, + waitUntil: ctx.waitUntil.bind(ctx) + }, + { + ASSET_NAMESPACE: env.__STATIC_CONTENT, + ASSET_MANIFEST: assetManifest, + ...options + } + ) +} + function isAssetUrl(url) { const { pathname } = new URL(url) return ( diff --git a/packages/web/src/ssr/+onRenderHtml.tsx b/packages/web/src/ssr/+onRenderHtml.tsx index b1637d1232c..4fbe7c4d196 100644 --- a/packages/web/src/ssr/+onRenderHtml.tsx +++ b/packages/web/src/ssr/+onRenderHtml.tsx @@ -4,10 +4,10 @@ import ReactDOMServer from 'react-dom/server' import { escapeInject, dangerouslySkipEscape } from 'vike/server' import { PageContextServer } from 'vike/types' -import indexHtml from '../../index.html?raw' import { Root } from '../Root' import { SsrContextProvider } from './SsrContext' +import indexHtml from './index.html?raw' export const passToClient = ['pageProps', 'urlPathname'] diff --git a/packages/web/src/ssr/index.html b/packages/web/src/ssr/index.html new file mode 100644 index 00000000000..87208809645 --- /dev/null +++ b/packages/web/src/ssr/index.html @@ -0,0 +1,208 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/packages/web/src/ssr/index/+onRenderHtml.tsx b/packages/web/src/ssr/index/+onRenderHtml.tsx index 5791e19ecff..1c4b147bda3 100644 --- a/packages/web/src/ssr/index/+onRenderHtml.tsx +++ b/packages/web/src/ssr/index/+onRenderHtml.tsx @@ -3,7 +3,7 @@ import { escapeInject, dangerouslySkipEscape } from 'vike/server' -import indexHtml from '../../../index.html?raw' +import indexHtml from '../index.html?raw' export function render() { const pattern = /%(\S+?)%/g diff --git a/packages/web/src/ssr/worker.js b/packages/web/src/ssr/worker.js index af0fdc2f823..ae8d0ea7a5e 100644 --- a/packages/web/src/ssr/worker.js +++ b/packages/web/src/ssr/worker.js @@ -1,6 +1,8 @@ +import { getAssetFromKV } from '@cloudflare/kv-asset-handler' import { renderPage } from 'vike/server' const DEBUG = true +const BROWSER_CACHE_TTL_SECONDS = 60 * 60 * 24 addEventListener('fetch', (event) => { try { @@ -18,17 +20,41 @@ addEventListener('fetch', (event) => { }) async function handleEvent(event) { - const pageContextInit = { - urlOriginal: event.request.url - } + if (!isAssetUrl(event.request.url)) { + // If the request is not for an asset, then it's a request for a page + + const pageContextInit = { + urlOriginal: event.request.url + } - const pageContext = await renderPage(pageContextInit) + const pageContext = await renderPage(pageContextInit) - const { httpResponse } = pageContext - if (!httpResponse) { - throw new Error(pageContext.errorWhileRendering) + const { httpResponse } = pageContext + if (!httpResponse) { + throw new Error(pageContext.errorWhileRendering) + } else { + const { body, statusCode: status, headers } = httpResponse + return new Response(body, { headers, status }) + } } else { - const { body, statusCode: status, headers } = httpResponse - return new Response(body, { headers, status }) + // Adjust browser cache on assets that don't change frequently and/or + // are given unique hashes when they do. + const asset = await getAssetFromKV(event) + + const response = new Response(asset.body, asset) + response.headers.set('cache-control', BROWSER_CACHE_TTL_SECONDS) + + return response } } + +function isAssetUrl(url) { + const { pathname } = new URL(url) + return ( + pathname.startsWith('/assets') || + pathname.startsWith('/scripts') || + pathname.startsWith('/fonts') || + pathname.startsWith('/favicons') || + pathname.startsWith('/manifest.json') + ) +} diff --git a/packages/web/src/ssr/wrangler.toml b/packages/web/src/ssr/wrangler.toml index 05e89560a8a..4b74a4ac3b5 100644 --- a/packages/web/src/ssr/wrangler.toml +++ b/packages/web/src/ssr/wrangler.toml @@ -4,7 +4,7 @@ main = "./worker.js" node_compat = true [site] -bucket = "../../build/client" +bucket = "../../build-ssr/client" # Invoke with npx wrangler dev --watch --env test [env.test] diff --git a/packages/web/vite.config.ts b/packages/web/vite.config.ts index db9991f41db..89c12ddead6 100644 --- a/packages/web/vite.config.ts +++ b/packages/web/vite.config.ts @@ -13,13 +13,14 @@ export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd(), 'VITE_') const port = parseInt(env.VITE_PORT ?? '3000') const analyze = env.VITE_BUNDLE_ANALYZE === 'true' + const ssr = env.VITE_SSR === 'true' env.VITE_PUBLIC_URL = env.VITE_PUBLIC_URL ?? '' return { base: env.VITE_PUBLIC_URL || '/', build: { - outDir: 'build', - sourcemap: true, + outDir: ssr ? 'build-ssr' : 'build', + sourcemap: false, commonjsOptions: { include: [/node_modules/], transformMixedEsModules: true @@ -71,7 +72,7 @@ export default defineConfig(({ mode }) => { plugins: ['@emotion/babel-plugin'] } }), - vike(), + ...(ssr ? [vike()] : []), ...((analyze ? [ visualizer({ diff --git a/packages/web/wrangler.toml b/packages/web/wrangler.toml index 83deabf6fc8..2e0a1cd442b 100644 --- a/packages/web/wrangler.toml +++ b/packages/web/wrangler.toml @@ -4,7 +4,7 @@ main = "./scripts/workers-site/index.js" node_compat = true [site] -bucket = "./build/client" +bucket = "./build" [env.staging] name = "audius-staging" From 67935916e579965e9ef95c417aec02e6ff8f5cd0 Mon Sep 17 00:00:00 2001 From: sliptype Date: Sat, 6 Jan 2024 16:19:47 -0600 Subject: [PATCH 33/74] Gate SSR on crawlers --- packages/web/scripts/workers-site/index.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/web/scripts/workers-site/index.js b/packages/web/scripts/workers-site/index.js index fe6bc643c39..6ab2b0d4895 100644 --- a/packages/web/scripts/workers-site/index.js +++ b/packages/web/scripts/workers-site/index.js @@ -53,6 +53,14 @@ function checkIsBot(val) { return botTest.test(val) } +function checkIsCrawler(val) { + if (!val) { + return false + } + const crawlerTest = /Googlebot/i + return crawlerTest.test(val) +} + async function getMetadata(pathname, discoveryNode) { if (pathname.startsWith('/scripts')) { return { metadata: null, name: null } @@ -274,7 +282,8 @@ async function handleEvent(request, env, ctx) { } } - if (SSR) { + // For now, only SSR for crawlers + if (SSR && checkIsCrawler(userAgent)) { const ssrResponse = await env.SSR.fetch(request.clone()) return ssrResponse } else { From 132a448916c9b0a881c50482e065de5aeba9d8fd Mon Sep 17 00:00:00 2001 From: sliptype Date: Sat, 6 Jan 2024 17:07:43 -0600 Subject: [PATCH 34/74] Allow forcing ssr via user agent --- packages/web/scripts/workers-site/index.js | 2 +- packages/web/src/ssr/worker.js | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/web/scripts/workers-site/index.js b/packages/web/scripts/workers-site/index.js index 6ab2b0d4895..97952cf7e35 100644 --- a/packages/web/scripts/workers-site/index.js +++ b/packages/web/scripts/workers-site/index.js @@ -57,7 +57,7 @@ function checkIsCrawler(val) { if (!val) { return false } - const crawlerTest = /Googlebot/i + const crawlerTest = /Googlebot|forceSSR/i return crawlerTest.test(val) } diff --git a/packages/web/src/ssr/worker.js b/packages/web/src/ssr/worker.js index ae8d0ea7a5e..2641dfbfc89 100644 --- a/packages/web/src/ssr/worker.js +++ b/packages/web/src/ssr/worker.js @@ -1,3 +1,11 @@ +/** + * This worker handles SSR + * + * It's separate from the main worker because the app bundle is heavy + * and causes slow cold starts. This way we can conditionally do SSR + * and avoid cold starts in the general case. + */ + import { getAssetFromKV } from '@cloudflare/kv-asset-handler' import { renderPage } from 'vike/server' From 6732a5013b32044dad81c82e7378c0dc6c8a5415 Mon Sep 17 00:00:00 2001 From: sliptype Date: Mon, 8 Jan 2024 15:31:32 -0600 Subject: [PATCH 35/74] Fix persist gate --- packages/web/src/app/ReduxProvider.tsx | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/web/src/app/ReduxProvider.tsx b/packages/web/src/app/ReduxProvider.tsx index 4cfb9d5f51d..9f90a510700 100644 --- a/packages/web/src/app/ReduxProvider.tsx +++ b/packages/web/src/app/ReduxProvider.tsx @@ -1,7 +1,8 @@ import { ReactNode, useState } from 'react' import { Provider } from 'react-redux' -import { persistStore } from 'redux-persist' +import { Persistor, persistStore } from 'redux-persist' +import { PersistGate } from 'redux-persist/integration/react' import { configureStore } from 'store/configureStore' import logger from 'utils/logger' @@ -10,17 +11,18 @@ import { useSsrContext } from '../ssr/SsrContext' import { useHistoryContext } from './HistoryProvider' -// TODO: Figure out persist gate? Do we need to block on loading from localstorage? export const ReduxProvider = ({ children }: { children: ReactNode }) => { - const { isServerSide, pageProps } = useSsrContext() + const { pageProps } = useSsrContext() const { history } = useHistoryContext() const [store, setStore] = useState>() + const [persistor, setPersistor] = useState() if (!store) { const store = configureStore(history, pageProps) setStore(store) - persistStore(store) + const persistor = persistStore(store) + setPersistor(persistor) // Mount store to window for easy access if (typeof window !== 'undefined') { @@ -31,5 +33,11 @@ export const ReduxProvider = ({ children }: { children: ReactNode }) => { logger(store) } - return store ? {children} : null + return store && persistor ? ( + + + {() => children} + + + ) : null } From 269b6b54c327548cb51598bbd61e0bcfdd5eede9 Mon Sep 17 00:00:00 2001 From: sliptype Date: Mon, 8 Jan 2024 16:15:21 -0600 Subject: [PATCH 36/74] Clean up get index.html --- packages/web/package.json | 6 +++--- packages/web/src/app/HistoryProvider.tsx | 3 +-- packages/web/src/ssr/+onRenderHtml.tsx | 19 +++++-------------- packages/web/src/ssr/getIndexHtml.ts | 16 ++++++++++++++++ .../web/src/ssr/index/+onRenderClient.tsx | 1 + packages/web/src/ssr/index/+onRenderHtml.tsx | 16 ++-------------- packages/web/src/ssr/ssr.js | 4 ++-- packages/web/src/ssr/wrangler.toml | 3 +-- 8 files changed, 31 insertions(+), 37 deletions(-) create mode 100644 packages/web/src/ssr/getIndexHtml.ts diff --git a/packages/web/package.json b/packages/web/package.json index ef1b91f5ac0..f7a1e3f2fb3 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -8,9 +8,9 @@ "scripts": { "publish-scripts": "./scripts/publishScripts.sh", "start": "vite", - "start:dev": "npm run write-sha && npm run publish-scripts && env-cmd ./.env/.env.git env-cmd --no-override ./.env/.env.dev turbo run start", - "start:stage": "npm run write-sha && npm run publish-scripts && env-cmd ./.env/.env.git env-cmd --no-override ./.env/.env.stage turbo run start", - "start:prod": "npm run write-sha && npm run publish-scripts && env-cmd ./.env/.env.git env-cmd --no-override ./.env/.env.prod env-cmd ./.env/.env.source-maps turbo run start", + "start:dev": "npm run write-sha && npm run publish-scripts && env-cmd ./.env/.env.git env-cmd --no-override ./.env/.env.dev env-cmd ./.env/.env.ssr turbo run start", + "start:stage": "npm run write-sha && npm run publish-scripts && env-cmd ./.env/.env.git env-cmd --no-override ./.env/.env.stage env-cmd ./.env/.env.ssr turbo run start", + "start:prod": "npm run write-sha && npm run publish-scripts && env-cmd ./.env/.env.git env-cmd --no-override ./.env/.env.prod env-cmd ./.env/.env.ssr env-cmd ./.env/.env.source-maps turbo run start", "preview:prod": "npm run build:prod && vite preview --outDir build-production", "prebuild": "npm run publish-scripts", "build": "vite build && cp package.json build/package.json", diff --git a/packages/web/src/app/HistoryProvider.tsx b/packages/web/src/app/HistoryProvider.tsx index dbc2ce6ef81..2d85f503d24 100644 --- a/packages/web/src/app/HistoryProvider.tsx +++ b/packages/web/src/app/HistoryProvider.tsx @@ -17,8 +17,7 @@ export const HistoryContext = createContext({ history: null as any }) -// TODO: does this cause rerenders on route change? -// TODO: could puth getPathname in here +// TODO: could put getPathname in here export const HistoryContextProvider = memo( (props: { children: JSX.Element }) => { const { history: ssrHistory } = useSsrContext() diff --git a/packages/web/src/ssr/+onRenderHtml.tsx b/packages/web/src/ssr/+onRenderHtml.tsx index 4fbe7c4d196..5967da4ad13 100644 --- a/packages/web/src/ssr/+onRenderHtml.tsx +++ b/packages/web/src/ssr/+onRenderHtml.tsx @@ -7,7 +7,7 @@ import { PageContextServer } from 'vike/types' import { Root } from '../Root' import { SsrContextProvider } from './SsrContext' -import indexHtml from './index.html?raw' +import { getIndexHtml } from './getIndexHtml' export const passToClient = ['pageProps', 'urlPathname'] @@ -28,19 +28,10 @@ export default function render( ) - const pattern = /%(\S+?)%/g - const env = process.env - - // Replace all %VITE_*% with the corresponding environment variable - const html = indexHtml - .replace(pattern, (text: string, key) => { - if (key in env) { - return env[key] ?? text - } - // TODO: throw warning - return text - }) - .replace(`
`, `
${pageHtml}
`) + const html = getIndexHtml().replace( + `
`, + `
${pageHtml}
` + ) return escapeInject`${dangerouslySkipEscape(html)}` } diff --git a/packages/web/src/ssr/getIndexHtml.ts b/packages/web/src/ssr/getIndexHtml.ts new file mode 100644 index 00000000000..f755438758f --- /dev/null +++ b/packages/web/src/ssr/getIndexHtml.ts @@ -0,0 +1,16 @@ +// TODO: generalize SPA/SSR indexHtml +import indexHtml from './index.html?raw' + +const pattern = /%(\S+?)%/g +const env = process.env + +export const getIndexHtml = () => { + // Replace all %VITE_*% with the corresponding environment variable + return indexHtml.replace(pattern, (text: string, key) => { + if (key in env) { + return env[key] ?? text + } + console.warn(`Missing environment variable: ${key}`) + return text + }) +} diff --git a/packages/web/src/ssr/index/+onRenderClient.tsx b/packages/web/src/ssr/index/+onRenderClient.tsx index 14da41453a8..dd6a1c6bdca 100644 --- a/packages/web/src/ssr/index/+onRenderClient.tsx +++ b/packages/web/src/ssr/index/+onRenderClient.tsx @@ -1,5 +1,6 @@ // For all routes except the explicitly defined ones (Track) // simply render the SPA without SSR +// TODO: Use vike SPA setting import 'setimmediate' import { Buffer } from 'buffer' diff --git a/packages/web/src/ssr/index/+onRenderHtml.tsx b/packages/web/src/ssr/index/+onRenderHtml.tsx index 1c4b147bda3..dfd23635c42 100644 --- a/packages/web/src/ssr/index/+onRenderHtml.tsx +++ b/packages/web/src/ssr/index/+onRenderHtml.tsx @@ -3,21 +3,9 @@ import { escapeInject, dangerouslySkipEscape } from 'vike/server' -import indexHtml from '../index.html?raw' +import { getIndexHtml } from 'ssr/getIndexHtml' export function render() { - const pattern = /%(\S+?)%/g - const env = process.env - - // Replace all %VITE_*% with the corresponding environment variable - const html = indexHtml.replace(pattern, (text, key) => { - if (key in env) { - return env[key] - } else { - // TODO: throw warning - return text - } - }) - + const html = getIndexHtml() return escapeInject`${dangerouslySkipEscape(html)}` } diff --git a/packages/web/src/ssr/ssr.js b/packages/web/src/ssr/ssr.js index 7a9e4c4a2e0..1623d61147e 100644 --- a/packages/web/src/ssr/ssr.js +++ b/packages/web/src/ssr/ssr.js @@ -5,12 +5,12 @@ export async function handleSsr(url) { urlOriginal: url } - // const { renderPage } = await import('vike/server') - const pageContext = await renderPage(pageContextInit) const { httpResponse } = pageContext if (!httpResponse) { + // TODO: throw sentry error + // TODO: Once SSR is user-facing, show a nice error page return new Response(pageContext.errorWhileRendering, { status: 500 }) } else { const { body, statusCode: status, headers } = httpResponse diff --git a/packages/web/src/ssr/wrangler.toml b/packages/web/src/ssr/wrangler.toml index 4b74a4ac3b5..283c7b82691 100644 --- a/packages/web/src/ssr/wrangler.toml +++ b/packages/web/src/ssr/wrangler.toml @@ -8,5 +8,4 @@ bucket = "../../build-ssr/client" # Invoke with npx wrangler dev --watch --env test [env.test] -name = "audius-web-ssr" -route = "ssr.audius.co/*" \ No newline at end of file +name = "audius-web-ssr" \ No newline at end of file From 18cee30c16f378b85349207008826a2cdf68757d Mon Sep 17 00:00:00 2001 From: sliptype Date: Mon, 8 Jan 2024 16:59:13 -0600 Subject: [PATCH 37/74] Only force retrieve on initial ssr load --- .../common/src/store/pages/track/actions.ts | 7 +++++++ .../common/src/store/pages/track/reducer.ts | 20 ++++++++++++++----- .../common/src/store/pages/track/selectors.ts | 4 ++++ .../common/src/store/pages/track/types.ts | 1 + .../cache/tracks/utils/retrieveTracks.ts | 18 +++++++++++++---- .../pages/track-page/TrackPageProvider.tsx | 9 +-------- 6 files changed, 42 insertions(+), 17 deletions(-) diff --git a/packages/common/src/store/pages/track/actions.ts b/packages/common/src/store/pages/track/actions.ts index d456088cfbf..9069c7b6b1a 100644 --- a/packages/common/src/store/pages/track/actions.ts +++ b/packages/common/src/store/pages/track/actions.ts @@ -7,6 +7,8 @@ export const SET_TRACK_ID = 'TRACK_PAGE/SET_TRACK_ID' export const SET_TRACK_PERMALINK = 'TRACK_PAGE/SET_TRACK_PERMALINK' export const MAKE_TRACK_PUBLIC = 'TRACK_PAGE/MAKE_TRACK_PUBLIC' export const SET_TRACK_TRENDING_RANKS = 'TRACK_PAGE/SET_TRACK_TRENDING_RANKS' +export const SET_IS_INITIAL_FETCH_AFTER_SSR = + 'TRACK_PAGE/SET_IS_INITIAL_FETCH_AFTER_SSR' export const FETCH_TRACK = 'TRACK_PAGE/FETCH_TRACK' export const FETCH_TRACK_SUCCEEDED = 'TRACK_PAGE/FETCH_TRACK_SUCCEEDED' @@ -74,3 +76,8 @@ export const setTrackTrendingRanks = (trendingTrackRanks) => ({ type: SET_TRACK_TRENDING_RANKS, trendingTrackRanks }) + +export const setIsInitialFetchAfterSsr = (isInitialFetchAfterSsr: boolean) => ({ + type: SET_IS_INITIAL_FETCH_AFTER_SSR, + isInitialFetchAfterSsr +}) diff --git a/packages/common/src/store/pages/track/reducer.ts b/packages/common/src/store/pages/track/reducer.ts index 50b0a7adcae..ee0ba019ea6 100644 --- a/packages/common/src/store/pages/track/reducer.ts +++ b/packages/common/src/store/pages/track/reducer.ts @@ -13,11 +13,13 @@ import { SET_TRACK_PERMALINK, RESET, SET_TRACK_RANK, - SET_TRACK_TRENDING_RANKS + SET_TRACK_TRENDING_RANKS, + SET_IS_INITIAL_FETCH_AFTER_SSR } from './actions' import { PREFIX as tracksPrefix } from './lineup/actions' +import TrackPageState from './types' -const initialState = { +const initialState: TrackPageState = { trackId: null, rank: { week: null, @@ -29,7 +31,8 @@ const initialState = { month: null, year: null }, - tracks: initialLineupState + tracks: initialLineupState, + isInitialFetchAfterSsr: false } const actionsMap = { @@ -69,6 +72,12 @@ const actionsMap = { ...initialState, tracks: tracksLineupReducer(undefined, action) } + }, + [SET_IS_INITIAL_FETCH_AFTER_SSR](state, action) { + return { + ...state, + isInitialFetchAfterSsr: action.isInitialFetchAfterSsr + } } } @@ -76,11 +85,12 @@ const tracksLineupReducer = asLineup(tracksPrefix, tracksReducer) const buildInitialState = (ssrPageProps?: SsrPageProps) => { // If we have preloaded data from the server, populate the initial - // cache state with it + // page state with it if (ssrPageProps?.track) { return { ...initialState, - trackId: decodeHashId(ssrPageProps.track.id) + trackId: decodeHashId(ssrPageProps.track.id), + isInitialFetchAfterSsr: true } } return initialState diff --git a/packages/common/src/store/pages/track/selectors.ts b/packages/common/src/store/pages/track/selectors.ts index 3a9f74837c2..d169674203e 100644 --- a/packages/common/src/store/pages/track/selectors.ts +++ b/packages/common/src/store/pages/track/selectors.ts @@ -60,3 +60,7 @@ export const getTrendingTrackRanks = (state: CommonState) => { } export const getSourceSelector = (state: CommonState) => `${PREFIX}:${getTrackId(state)}` + +export const getIsInitialFetchAfterSsr = (state: CommonState) => { + return getBaseState(state).isInitialFetchAfterSsr +} diff --git a/packages/common/src/store/pages/track/types.ts b/packages/common/src/store/pages/track/types.ts index 97015bd79fc..7643013a793 100644 --- a/packages/common/src/store/pages/track/types.ts +++ b/packages/common/src/store/pages/track/types.ts @@ -14,4 +14,5 @@ export default interface TrackPageState { year: ID[] | null } tracks: LineupState<{ id: ID }> + isInitialFetchAfterSsr: boolean } diff --git a/packages/web/src/common/store/cache/tracks/utils/retrieveTracks.ts b/packages/web/src/common/store/cache/tracks/utils/retrieveTracks.ts index 95c7ae5cf38..00156b0fd52 100644 --- a/packages/web/src/common/store/cache/tracks/utils/retrieveTracks.ts +++ b/packages/web/src/common/store/cache/tracks/utils/retrieveTracks.ts @@ -9,7 +9,9 @@ import { getContext, cacheSelectors, cacheTracksSelectors, - cacheTracksActions + cacheTracksActions, + trackPageSelectors, + trackPageActions } from '@audius/common' import { call, put, select, spawn } from 'typed-redux-saga' @@ -27,6 +29,8 @@ const { getEntryTimestamp } = cacheSelectors const { getTracks: getTracksSelector } = cacheTracksSelectors const { setPermalink } = cacheTracksActions const getUserId = accountSelectors.getUserId +const { getIsInitialFetchAfterSsr } = trackPageSelectors +const { setIsInitialFetchAfterSsr } = trackPageActions type UnlistedTrackRequest = { id: ID; url_title: string; handle: string } type RetrieveTracksArgs = { @@ -55,6 +59,9 @@ export function* retrieveTrackByHandleAndSlug({ forceRetrieveFromSource = false }: RetrieveTrackByHandleAndSlugArgs) { const permalink = `/${handle}/${slug}` + + // Check if this is the first fetch after server side rendering the track page + const isInitialFetchAfterSsr = yield* select(getIsInitialFetchAfterSsr) const tracks = (yield* call( // @ts-ignore retrieve should be refactored to ts first retrieve, @@ -84,10 +91,12 @@ export function* retrieveTrackByHandleAndSlug({ }, kind: Kind.TRACKS, idField: 'track_id', - forceRetrieveFromSource, + // If this is the first fetch after server side rendering the track page, + // force retrieve from source to ensure we have personalized data + forceRetrieveFromSource: + forceRetrieveFromSource ?? isInitialFetchAfterSsr, shouldSetLoading: true, - // TODO: only deleteExistingEntry on initial page load - deleteExistingEntry: true, + deleteExistingEntry: isInitialFetchAfterSsr, getEntriesTimestamp: function* (ids: ID[]) { const selected = yield* select( (state: CommonState, ids: ID[]) => @@ -107,6 +116,7 @@ export function* retrieveTrackByHandleAndSlug({ if (isLegacyPermalink) { yield* put(setPermalink(permalink, track.track_id)) } + yield* put(setIsInitialFetchAfterSsr(false)) return tracks.map((track) => reformat(track, audiusBackendInstance)) } } diff --git a/packages/web/src/pages/track-page/TrackPageProvider.tsx b/packages/web/src/pages/track-page/TrackPageProvider.tsx index 992a04fdf5c..18a20bfc32b 100644 --- a/packages/web/src/pages/track-page/TrackPageProvider.tsx +++ b/packages/web/src/pages/track-page/TrackPageProvider.tsx @@ -542,14 +542,7 @@ function mapDispatchToProps(dispatch: Dispatch) { canBeUnlisted: boolean ) => dispatch( - trackPageActions.fetchTrack( - trackId, - slug, - ownerHandle, - canBeUnlisted, - // TODO: only force retrieve on initial load - true - ) + trackPageActions.fetchTrack(trackId, slug, ownerHandle, canBeUnlisted) ), setTrackId: (trackId: number) => dispatch(trackPageActions.setTrackId(trackId)), From 75846725fcaf812fa1e2f4253411b43e9fff65f4 Mon Sep 17 00:00:00 2001 From: sliptype Date: Tue, 9 Jan 2024 17:00:16 -0600 Subject: [PATCH 38/74] Add isMobile to SsrContext, update isMobile usages --- .../services/audius-backend/AudiusBackend.ts | 7 +- .../src/services/remote-config/defaults.ts | 1 - .../src/services/remote-config/types.ts | 5 - packages/common/src/store/storeContext.ts | 3 +- .../src/services/audius-backend-instance.ts | 1 - packages/mobile/src/store/storeContext.ts | 3 +- packages/web/src/Root.tsx | 6 +- packages/web/src/app/ReduxProvider.tsx | 4 +- packages/web/src/app/web-player/WebPlayer.jsx | 87 +++++++-------- .../web/src/common/store/analytics/sagas.ts | 4 +- .../common/store/pages/audio-rewards/sagas.ts | 5 +- .../src/common/store/pages/signon/reducer.js | 5 +- .../add-funds-modal/AddFundsModal.tsx | 8 +- .../web/src/components/add-funds/AddFunds.tsx | 6 +- .../components/address-tile/AddressTile.tsx | 6 +- .../animated-switch/RouterContextProvider.tsx | 4 +- .../components/AppRedirectPopover.tsx | 5 +- .../components/banner/AppBannerWrapper.tsx | 15 +-- .../src/components/banner/Web3ErrorBanner.tsx | 7 +- .../BrowserPushConfirmationModal.tsx | 5 +- .../components/cookie-banner/CookieBanner.tsx | 10 +- .../src/components/cover-photo/CoverPhoto.tsx | 17 ++- .../web/src/components/dog-ear/DogEar.tsx | 6 +- .../header/mobile/HeaderContextProvider.tsx | 3 +- packages/web/src/components/lineup/Lineup.tsx | 20 ++-- .../src/components/lineup/LineupProvider.tsx | 6 +- packages/web/src/components/lineup/hooks.ts | 5 +- .../LockedContentModal.tsx | 9 +- .../web/src/components/nav/store/context.tsx | 3 +- .../Notification/FavoriteNotification.tsx | 7 +- .../Notification/FollowNotification.tsx | 7 +- .../Notification/RepostNotification.tsx | 7 +- .../Notification/components/UserNameLink.tsx | 5 +- .../payment-method/PaymentMethod.tsx | 10 +- .../components/play-bar/PlayBarProvider.tsx | 6 +- .../PremiumContentPurchaseModal.tsx | 17 ++- .../selectable-pill/SelectablePill.tsx | 5 +- .../src/components/share-modal/ShareModal.tsx | 5 +- .../ShareSoundToTikTokModal.tsx | 6 +- .../subscribe-button/SubscribeButton.tsx | 5 +- .../USDCManualTransfer.tsx | 16 +-- .../web/src/components/user-list/UserList.tsx | 13 ++- packages/web/src/hooks/useWithMobileStyle.ts | 8 +- .../audio-rewards-page/AudioRewardsPage.tsx | 5 +- .../src/pages/audio-rewards-page/Tiers.tsx | 6 +- .../src/pages/audio-rewards-page/Tiles.tsx | 18 ++-- .../components/ExplainerTile.tsx | 5 +- .../components/WalletManagementTile.tsx | 23 ++-- .../AudioMatchingRewardsModalContent.tsx | 5 +- .../ChallengeRewardsModal.tsx | 6 +- .../components/modals/ModalDrawer.tsx | 5 +- .../components/modals/TrendingRewards.tsx | 10 +- .../components/modals/VerifiedUpload.tsx | 9 +- .../components/modals/VipDiscordModal.tsx | 5 +- .../CollectiblesPlaylistPage.tsx | 7 +- .../pages/collection-page/CollectionPage.tsx | 9 +- .../DeactivateAccountPage.tsx | 7 +- .../explore-page/ExploreCollectionsPage.tsx | 21 +--- .../src/pages/explore-page/ExplorePage.tsx | 19 +--- packages/web/src/pages/feed-page/FeedPage.tsx | 20 +--- .../src/pages/feed-page/FeedPageProvider.jsx | 14 ++- .../src/pages/history-page/HistoryPage.tsx | 17 +-- .../src/pages/not-found-page/NotFoundPage.tsx | 6 +- .../components/PurchasesTab.tsx | 5 +- .../pay-and-earn-page/components/SalesTab.tsx | 5 +- .../components/WithdrawalsTab.tsx | 5 +- .../web/src/pages/saved-page/SavedPage.tsx | 19 +--- .../pages/saved-page/SavedPageProvider.tsx | 5 +- .../src/pages/settings-page/SettingsPage.tsx | 19 +--- .../components/desktop/SettingsPage.tsx | 5 +- packages/web/src/pages/sign-on/SignOn.tsx | 5 +- .../pages/sign-on/components/ProfilePage.tsx | 4 +- .../web/src/pages/track-page/TrackPage.tsx | 20 +--- .../pages/track-page/TrackPageProvider.tsx | 11 +- .../src/pages/trending-page/TrendingPage.tsx | 20 +--- .../trending-page/TrendingPageProvider.jsx | 14 ++- .../components/RewardsBanner.tsx | 8 +- .../TrendingPlaylistPage.tsx | 6 +- .../TrendingUndergroundPage.tsx | 6 +- .../web/src/services/analytics/amplitude.ts | 35 +++++- packages/web/src/services/analytics/index.ts | 47 ++------ .../web/src/services/analytics/segment.ts | 100 ------------------ .../audius-backend/audius-backend-instance.ts | 3 +- packages/web/src/ssr/+onRenderClient.tsx | 5 +- packages/web/src/ssr/+onRenderHtml.tsx | 17 ++- packages/web/src/ssr/SsrContext.tsx | 2 + .../web/src/ssr/index/+onRenderClient.tsx | 1 + packages/web/src/store/account/sagas.ts | 10 +- .../store/application/ui/scrollLock/sagas.ts | 10 +- packages/web/src/store/configureStore.ts | 5 +- packages/web/src/store/storeContext.ts | 15 ++- packages/web/src/utils/clientUtil.ts | 47 ++++---- packages/web/src/utils/share.ts | 5 +- 93 files changed, 470 insertions(+), 589 deletions(-) delete mode 100644 packages/web/src/services/analytics/segment.ts diff --git a/packages/common/src/services/audius-backend/AudiusBackend.ts b/packages/common/src/services/audius-backend/AudiusBackend.ts index 44e6082a3f8..29f3f0ec166 100644 --- a/packages/common/src/services/audius-backend/AudiusBackend.ts +++ b/packages/common/src/services/audius-backend/AudiusBackend.ts @@ -249,7 +249,6 @@ type AudiusBackendParams = { identityServiceUrl: Maybe generalAdmissionUrl: Maybe isElectron: Maybe - isMobile: Maybe localStorage?: LocalStorage monitoringCallbacks: MonitoringCallbacks nativeMobile: Maybe @@ -294,7 +293,6 @@ export const audiusBackend = ({ identityServiceUrl, generalAdmissionUrl, isElectron, - isMobile, localStorage, monitoringCallbacks, nativeMobile, @@ -3166,7 +3164,8 @@ export const audiusBackend = ({ endpoints, AAOEndpoint, parallelization, - feePayerOverride + feePayerOverride, + source }: { challenges: { challenge_id: ChallengeRewardID @@ -3183,12 +3182,12 @@ export const audiusBackend = ({ parallelization: number feePayerOverride: Nullable isFinalAttempt: boolean + source: 'mobile' | 'electron' | 'web' }) { await waitForLibsInit() try { if (!challenges.length) return - const source = isMobile ? 'mobile' : isElectron ? 'electron' : 'web' const reporter = new ClientRewardsReporter({ libs: audiusLibs, recordAnalytics, diff --git a/packages/common/src/services/remote-config/defaults.ts b/packages/common/src/services/remote-config/defaults.ts index 2b729d29bc5..0aae34cce80 100644 --- a/packages/common/src/services/remote-config/defaults.ts +++ b/packages/common/src/services/remote-config/defaults.ts @@ -113,7 +113,6 @@ export const remoteConfigBooleanDefaults: { [BooleanKeys.DISPLAY_WEB3_PROVIDER_WALLET_LINK]: true, [BooleanKeys.DISPLAY_SOLANA_WEB3_PROVIDER_PHANTOM]: true, [BooleanKeys.SKIP_ROLLOVER_NODES_SANITY_CHECK]: false, - [BooleanKeys.USE_AMPLITUDE]: true, [BooleanKeys.AUDIO_TRANSACTIONS_ENABLED]: false, [BooleanKeys.ENABLE_DISCOVERY_NODE_MAX_SLOT_DIFF_PLAYS]: false } diff --git a/packages/common/src/services/remote-config/types.ts b/packages/common/src/services/remote-config/types.ts index 9c07e298a8e..146d425340f 100644 --- a/packages/common/src/services/remote-config/types.ts +++ b/packages/common/src/services/remote-config/types.ts @@ -245,11 +245,6 @@ export enum BooleanKeys { */ SKIP_ROLLOVER_NODES_SANITY_CHECK = 'SKIP_ROLLOVER_NODES_SANITY_CHECK', - /** - * Boolean to use amplitude as the metrics tracking. - */ - USE_AMPLITUDE = 'USE_AMPLITUDE', - /** * Boolean to enable "Transactions" button on Audio page. */ diff --git a/packages/common/src/store/storeContext.ts b/packages/common/src/store/storeContext.ts index fcc4bb59e03..faf81ede7d6 100644 --- a/packages/common/src/store/storeContext.ts +++ b/packages/common/src/store/storeContext.ts @@ -32,7 +32,7 @@ export type CommonStoreContext = { fallbackFlag?: FeatureFlags ) => Promise analytics: { - init: () => Promise + init: (isMobile: boolean) => Promise track: (event: AnalyticsEvent, callback?: () => void) => Promise identify: ( handle: string, @@ -80,4 +80,5 @@ export type CommonStoreContext = { urls: string[] ) => Promise<{ file: File; url: string }> } + isMobile: boolean } diff --git a/packages/mobile/src/services/audius-backend-instance.ts b/packages/mobile/src/services/audius-backend-instance.ts index 9df8ed82d9a..e51e51664b3 100644 --- a/packages/mobile/src/services/audius-backend-instance.ts +++ b/packages/mobile/src/services/audius-backend-instance.ts @@ -58,7 +58,6 @@ export const audiusBackendInstance = audiusBackend({ identityServiceUrl: Config.IDENTITY_SERVICE, generalAdmissionUrl: Config.GENERAL_ADMISSION, isElectron: false, - isMobile: true, localStorage: AsyncStorage, monitoringCallbacks, nativeMobile: true, diff --git a/packages/mobile/src/store/storeContext.ts b/packages/mobile/src/store/storeContext.ts index 3d3f26b8707..b29ebb8f72b 100644 --- a/packages/mobile/src/store/storeContext.ts +++ b/packages/mobile/src/store/storeContext.ts @@ -55,5 +55,6 @@ export const storeContext: CommonStoreContext = { audiusSdk, imageUtils: { generatePlaylistArtwork - } + }, + isMobile: true } diff --git a/packages/web/src/Root.tsx b/packages/web/src/Root.tsx index f9b58fe9d7d..20a32a11e1d 100644 --- a/packages/web/src/Root.tsx +++ b/packages/web/src/Root.tsx @@ -7,7 +7,7 @@ import { Location } from 'history' import { useAsync } from 'react-use' import { localStorage } from 'services/local-storage' -import { useIsMobile, isElectron } from 'utils/clientUtil' +import { isElectron, useIsMobile } from 'utils/clientUtil' import { getPathname, HOME_PAGE, publicSiteRoutes } from 'utils/route' import App from './app' @@ -32,11 +32,11 @@ const isPublicSiteSubRoute = (location: Location) => { const clientIsElectron = isElectron() const AppOrPublicSite = () => { + const isMobile = useIsMobile() const { history } = useHistoryContext() const [renderPublicSite, setRenderPublicSite] = useState( isPublicSiteRoute(history.location) ) - const isMobileClient = useIsMobile() const { value: foundUser } = useAsync(() => localStorage.getCurrentUserExists() @@ -55,7 +55,7 @@ const AppOrPublicSite = () => { return ( }> diff --git a/packages/web/src/app/ReduxProvider.tsx b/packages/web/src/app/ReduxProvider.tsx index 9f90a510700..fd8e9cfb779 100644 --- a/packages/web/src/app/ReduxProvider.tsx +++ b/packages/web/src/app/ReduxProvider.tsx @@ -5,6 +5,7 @@ import { Persistor, persistStore } from 'redux-persist' import { PersistGate } from 'redux-persist/integration/react' import { configureStore } from 'store/configureStore' +import { useIsMobile } from 'utils/clientUtil' import logger from 'utils/logger' import { useSsrContext } from '../ssr/SsrContext' @@ -14,12 +15,13 @@ import { useHistoryContext } from './HistoryProvider' export const ReduxProvider = ({ children }: { children: ReactNode }) => { const { pageProps } = useSsrContext() const { history } = useHistoryContext() + const isMobile = useIsMobile() const [store, setStore] = useState>() const [persistor, setPersistor] = useState() if (!store) { - const store = configureStore(history, pageProps) + const store = configureStore(history, isMobile, pageProps) setStore(store) const persistor = persistStore(store) setPersistor(persistor) diff --git a/packages/web/src/app/web-player/WebPlayer.jsx b/packages/web/src/app/web-player/WebPlayer.jsx index d638b247c44..95a678de78a 100644 --- a/packages/web/src/app/web-player/WebPlayer.jsx +++ b/packages/web/src/app/web-player/WebPlayer.jsx @@ -98,13 +98,14 @@ import Visualizer from 'pages/visualizer/Visualizer' import { getFeatureEnabled } from 'services/remote-config/featureFlagHelpers' import { remoteConfigInstance } from 'services/remote-config/remote-config-instance' import { initializeSentry } from 'services/sentry' +import { SsrContext } from 'ssr/SsrContext' import { setVisibility as setAppModalCTAVisibility } from 'store/application/ui/app-cta-modal/slice' import { getShowCookieBanner } from 'store/application/ui/cookieBanner/selectors' import { incrementScrollCount as incrementScrollCountAction, decrementScrollCount as decrementScrollCountAction } from 'store/application/ui/scrollLock/actions' -import { isMobile, getClient } from 'utils/clientUtil' +import { getClient } from 'utils/clientUtil' import 'utils/redirect' import { FEED_PAGE, @@ -203,6 +204,8 @@ const includeSearch = (search) => { initializeSentry() class WebPlayer extends Component { + static contextType = SsrContext + state = { mainContent: null, @@ -424,8 +427,8 @@ class WebPlayer extends Component { showRequiresWebUpdate, initialPage } = this.state - const client = getClient() - const isMobileClient = client === Client.MOBILE + + const isMobile = this.context.isMobile if (showRequiresUpdate) return ( @@ -445,7 +448,7 @@ class WebPlayer extends Component { /> ) - const SwitchComponent = isMobile() ? AnimatedSwitch : Switch + const SwitchComponent = this.context.isMobile ? AnimatedSwitch : Switch const noScroll = matchPath(this.state.currentRoute, CHAT_PAGE) return ( @@ -470,7 +473,7 @@ class WebPlayer extends Component { {this.props.isChatEnabled ? : null} -
+
{this.props.showCookieBanner ? : null} @@ -479,12 +482,12 @@ class WebPlayer extends Component { id={MAIN_CONTENT_ID} role='main' className={cn(styles.mainContentWrapper, { - [styles.mainContentWrapperMobile]: isMobileClient, + [styles.mainContentWrapperMobile]: isMobile, [styles.noScroll]: noScroll })} > - {isMobileClient && } - {isMobileClient && } + {isMobile && } + {isMobile && } @@ -507,7 +510,7 @@ class WebPlayer extends Component { ( } /> } /> ( )} @@ -712,13 +715,13 @@ class WebPlayer extends Component { ( ( ( )} @@ -748,56 +751,56 @@ class WebPlayer extends Component { } /> } /> ( )} @@ -805,7 +808,7 @@ class WebPlayer extends Component { ( )} @@ -813,7 +816,7 @@ class WebPlayer extends Component { } /> @@ -899,43 +902,43 @@ class WebPlayer extends Component { {/* Non-mobile */} - {!isMobileClient ? : null} - {!isMobileClient ? : null} - {!isMobileClient ? : null} - {!isMobileClient ? : null} + {!isMobile ? : null} + {!isMobile ? : null} + {!isMobile ? : null} + {!isMobile ? : null} {/* Mobile-only */} - {isMobileClient ? ( + {isMobile ? ( amount > 0) // We shouldn't have any 0 amount challenges, but just in case. + const isMobile = yield* getContext('isMobile') const response: { error?: string; aaoErrorCode?: number } = yield* call( audiusBackendInstance.submitAndEvaluateAttestations, { @@ -277,7 +279,8 @@ function* claimChallengeRewardAsync( AAOEndpoint, parallelization, feePayerOverride, - isFinalAttempt: !retryOnFailure + isFinalAttempt: !retryOnFailure, + source: isMobile ? 'mobile' : isElectron() ? 'electron' : 'web' } ) if (response.error) { diff --git a/packages/web/src/common/store/pages/signon/reducer.js b/packages/web/src/common/store/pages/signon/reducer.js index 616f5e92e19..1afce224f5e 100644 --- a/packages/web/src/common/store/pages/signon/reducer.js +++ b/packages/web/src/common/store/pages/signon/reducer.js @@ -1,4 +1,3 @@ -import { isMobile } from 'utils/clientUtil' import { FEED_PAGE } from 'utils/route' import { @@ -112,7 +111,7 @@ const actionsMap = { page: action.page || state.page } }, - [NEXT_PAGE](state) { + [NEXT_PAGE](state, action) { let newPage switch (state.page) { case Pages.EMAIL: @@ -125,7 +124,7 @@ const actionsMap = { newPage = Pages.FOLLOW break case Pages.FOLLOW: { - if (!isMobile()) { + if (!action.isMobile) { newPage = Pages.APP_CTA } else { newPage = Pages.LOADING diff --git a/packages/web/src/components/add-funds-modal/AddFundsModal.tsx b/packages/web/src/components/add-funds-modal/AddFundsModal.tsx index c8e2cd312c4..dea4e4477ed 100644 --- a/packages/web/src/components/add-funds-modal/AddFundsModal.tsx +++ b/packages/web/src/components/add-funds-modal/AddFundsModal.tsx @@ -15,7 +15,7 @@ import { AddFunds } from 'components/add-funds/AddFunds' import { Text } from 'components/typography' import { USDCManualTransfer } from 'components/usdc-manual-transfer/USDCManualTransfer' import ModalDrawer from 'pages/audio-rewards-page/components/modals/ModalDrawer' -import { isMobile } from 'utils/clientUtil' +import { useIsMobile } from 'utils/clientUtil' import zIndex from 'utils/zIndex' import styles from './AddFundsModal.module.css' @@ -30,7 +30,7 @@ type Page = 'add-funds' | 'crypto-transfer' export const AddFundsModal = () => { const { isOpen, onClose } = useAddFundsModal() const dispatch = useDispatch() - const mobile = isMobile() + const isMobile = useIsMobile() const [page, setPage] = useState('add-funds') @@ -69,9 +69,9 @@ export const AddFundsModal = () => { isFullscreen={false} > (PurchaseMethod.CARD) - const mobile = isMobile() + const isMobile = useIsMobile() const { data: balanceBN } = useUSDCBalance({ isPolling: true }) const balance = USDC(balanceBN ?? new BN(0)).value @@ -49,7 +49,7 @@ export const AddFunds = ({
diff --git a/packages/web/src/components/address-tile/AddressTile.tsx b/packages/web/src/components/address-tile/AddressTile.tsx index f28222f0626..e0fd1de3cf8 100644 --- a/packages/web/src/components/address-tile/AddressTile.tsx +++ b/packages/web/src/components/address-tile/AddressTile.tsx @@ -14,7 +14,7 @@ import { import { BN } from 'bn.js' import { ToastContext } from 'components/toast/ToastContext' -import { isMobile } from 'utils/clientUtil' +import { useIsMobile } from 'utils/clientUtil' import { copyToClipboard } from 'utils/clipboardUtil' const messages = { @@ -35,7 +35,7 @@ export const AddressTile = ({ }: AddressTileProps) => { const { color } = useTheme() const { toast } = useContext(ToastContext) - const mobile = isMobile() + const isMobile = useIsMobile() const { data: balanceBN } = useUSDCBalance({ isPolling: true }) const handleCopyPress = useCallback(() => { @@ -86,7 +86,7 @@ export const AddressTile = ({ }} variant='body' > - {mobile ? shortenSPLAddress(address, 12) : address} + {isMobile ? shortenSPLAddress(address, 12) : address} diff --git a/packages/web/src/components/animated-switch/RouterContextProvider.tsx b/packages/web/src/components/animated-switch/RouterContextProvider.tsx index a0aefba7dcb..c1fbc3ffa6b 100644 --- a/packages/web/src/components/animated-switch/RouterContextProvider.tsx +++ b/packages/web/src/components/animated-switch/RouterContextProvider.tsx @@ -34,7 +34,9 @@ export const RouterContextProvider = memo( SlideDirection.FROM_LEFT ) - if (useIsMobile()) { + const isMobile = useIsMobile() + + if (isMobile) { return ( { onBeforeClickDismissed = () => {} } = props const { history } = useHistoryContext() + const isMobile = useIsMobile() const [isDismissed, setIsDismissed] = useSessionStorage( 'app-redirect-popover', false @@ -108,7 +109,7 @@ export const AppRedirectPopover = (props: AppRedirectPopoverProps) => { !matchPath(window.location.pathname, { path: '/', exact: true }) && animDelay && !isDismissed && - isMobile() && + isMobile && !(navigator.userAgent === 'probers') useEffect(() => { diff --git a/packages/web/src/components/banner/AppBannerWrapper.tsx b/packages/web/src/components/banner/AppBannerWrapper.tsx index ab1ddea2369..ef953e36545 100644 --- a/packages/web/src/components/banner/AppBannerWrapper.tsx +++ b/packages/web/src/components/banner/AppBannerWrapper.tsx @@ -1,6 +1,6 @@ import cn from 'classnames' -import { isMobile } from 'utils/clientUtil' +import { useIsMobile } from 'utils/clientUtil' import styles from './AppBannerWrapper.module.css' @@ -12,8 +12,11 @@ export const AppBannerWrapper = ({ children }: { children: React.ReactNode -}) => ( -
- {children} -
-) +}) => { + const isMobile = useIsMobile() + return ( +
+ {children} +
+ ) +} diff --git a/packages/web/src/components/banner/Web3ErrorBanner.tsx b/packages/web/src/components/banner/Web3ErrorBanner.tsx index d14468748cf..236061ed997 100644 --- a/packages/web/src/components/banner/Web3ErrorBanner.tsx +++ b/packages/web/src/components/banner/Web3ErrorBanner.tsx @@ -1,7 +1,7 @@ import { useCallback, useEffect, useState } from 'react' import { getWeb3Error } from 'common/store/backend/selectors' -import { isMobile } from 'utils/clientUtil' +import { useIsMobile } from 'utils/clientUtil' import { useSelector } from 'utils/reducer' import { CallToActionBanner } from './CallToActionBanner' @@ -23,6 +23,7 @@ const META_MASK_SETUP_URL = export const Web3ErrorBanner = () => { const web3Error = useSelector(getWeb3Error) const [isVisible, setIsVisible] = useState(web3Error) + const isMobile = useIsMobile() const handleAccept = useCallback(() => { const win = window.open(META_MASK_SETUP_URL, '_blank') @@ -42,8 +43,8 @@ export const Web3ErrorBanner = () => { return isVisible ? ( diff --git a/packages/web/src/components/browser-push-confirmation-modal/BrowserPushConfirmationModal.tsx b/packages/web/src/components/browser-push-confirmation-modal/BrowserPushConfirmationModal.tsx index 4065480bd06..8e4365956a8 100644 --- a/packages/web/src/components/browser-push-confirmation-modal/BrowserPushConfirmationModal.tsx +++ b/packages/web/src/components/browser-push-confirmation-modal/BrowserPushConfirmationModal.tsx @@ -20,7 +20,7 @@ import { subscribeSafariPushBrowser, Permission } from 'utils/browserNotifications' -import { isElectron, isMobile } from 'utils/clientUtil' +import { isElectron, useIsMobile } from 'utils/clientUtil' import styles from './BrowserPushConfirmationModal.module.css' const { setVisibility } = modalsActions @@ -61,6 +61,7 @@ const ConnectedBrowserPushConfirmationModal = ({ }: BrowserPushConfirmationModal) => { const { permission } = browserNotificationSettings const [pushPermission] = useState(permission) + const isMobile = useIsMobile() const onEnabled = useCallback(() => { let cancelled = false @@ -123,7 +124,7 @@ const ConnectedBrowserPushConfirmationModal = ({ title={messages.title} titleClassName={styles.title} wrapperClassName={cn(styles.wrapperClassName, { - [styles.mobile]: isMobile() + [styles.mobile]: isMobile })} headerContainerClassName={styles.headerContainerClassName} bodyClassName={styles.modalBody} diff --git a/packages/web/src/components/cookie-banner/CookieBanner.tsx b/packages/web/src/components/cookie-banner/CookieBanner.tsx index 094de747b36..e98f24b79bf 100644 --- a/packages/web/src/components/cookie-banner/CookieBanner.tsx +++ b/packages/web/src/components/cookie-banner/CookieBanner.tsx @@ -8,7 +8,7 @@ import { Dispatch } from 'redux' import IconRemove from 'assets/img/iconRemove.svg' import { dismissCookieBanner } from 'store/application/ui/cookieBanner/actions' import { AppState } from 'store/types' -import { isMobile } from 'utils/clientUtil' +import { useIsMobile } from 'utils/clientUtil' import { COOKIE_POLICY } from 'utils/route' import styles from './CookieBanner.module.css' @@ -24,11 +24,8 @@ const messages = { export type CookieBannerProps = ReturnType & ReturnType -export const CookieBanner = ({ - isMobile, - isPlaying, - dismiss -}: CookieBannerProps) => { +export const CookieBanner = ({ isPlaying, dismiss }: CookieBannerProps) => { + const isMobile = useIsMobile() const goToCookiePolicy = () => { const win = window.open(COOKIE_POLICY, '_blank') if (win) win.focus() @@ -56,7 +53,6 @@ export const CookieBanner = ({ function mapStateToProps(state: AppState) { return { - isMobile: isMobile(), isPlaying: !!getUid(state) } } diff --git a/packages/web/src/components/cover-photo/CoverPhoto.tsx b/packages/web/src/components/cover-photo/CoverPhoto.tsx index a0a308cccf5..7676f8a7c34 100644 --- a/packages/web/src/components/cover-photo/CoverPhoto.tsx +++ b/packages/web/src/components/cover-photo/CoverPhoto.tsx @@ -6,6 +6,7 @@ import { FileWithPreview } from 'react-dropzone' import Lottie from 'react-lottie' import loadingSpinner from 'assets/animations/loadingSpinner.json' +import { ClientOnly } from 'components/client-only/ClientOnly' import DynamicImage from 'components/dynamic-image/DynamicImage' import ImageSelectionButton from 'components/image-selection/ImageSelectionButton' import { useCoverPhoto } from 'hooks/useCoverPhoto' @@ -81,11 +82,17 @@ const CoverPhoto = ({ } const loadingElement = ( -
- -
+ +
+ +
+
) return ( diff --git a/packages/web/src/components/dog-ear/DogEar.tsx b/packages/web/src/components/dog-ear/DogEar.tsx index b2cf7b752c0..e3c6aab4923 100644 --- a/packages/web/src/components/dog-ear/DogEar.tsx +++ b/packages/web/src/components/dog-ear/DogEar.tsx @@ -10,7 +10,7 @@ import cn from 'classnames' import Rectangle from 'assets/img/dogEarRectangle.svg' import IconHidden from 'assets/img/iconHidden.svg' import IconStar from 'assets/img/iconStar.svg' -import { isMobile } from 'utils/clientUtil' +import { useIsMobile } from 'utils/clientUtil' import { isMatrix } from 'utils/theme/theme' import styles from './DogEar.module.css' @@ -41,13 +41,13 @@ const getIcon = (type: DogEarType) => { export const DogEar = (props: DogEarProps) => { const { type, className } = props const isMatrixMode = isMatrix() - const isMobileMode = isMobile() + const isMobile = useIsMobile() const Icon = getIcon(type) return (
diff --git a/packages/web/src/components/header/mobile/HeaderContextProvider.tsx b/packages/web/src/components/header/mobile/HeaderContextProvider.tsx index 2fdead99954..d9837bde33c 100644 --- a/packages/web/src/components/header/mobile/HeaderContextProvider.tsx +++ b/packages/web/src/components/header/mobile/HeaderContextProvider.tsx @@ -25,8 +25,9 @@ export const HeaderContext = createContext({ export const HeaderContextProvider = memo( (props: { children: JSX.Element }) => { const [header, setHeader] = useState(null) + const isMobile = useIsMobile() - if (useIsMobile()) { + if (isMobile) { return ( -type LineupProps = LineupWithoutTile & ReturnType +type LineupProps = LineupWithoutTile /** A lineup renders a LineupProvider, injecting different tiles * depending on the client state. */ const Lineup = (props: LineupProps) => { - const mobile = props.isMobile - const trackTile = mobile ? MobileTrackTile : DesktopTrackTile - const playlistTile = mobile ? MobilePlaylistTile : DesktopPlaylistTile + const isMobile = useIsMobile() + const trackTile = isMobile ? MobileTrackTile : DesktopTrackTile + const playlistTile = isMobile ? MobilePlaylistTile : DesktopPlaylistTile return ( { + static contextType = SsrContext scrollContainer = createRef() constructor(props: any) { @@ -478,7 +479,6 @@ class LineupProvider extends PureComponent { extraPrecedingElement, endOfLineup, lineupContainerStyles, - isMobile, showLeadingElementArtistPick = true, lineup: { isMetadataLoading, page, entries = [] }, numPlaylistSkeletonRows, @@ -486,6 +486,7 @@ class LineupProvider extends PureComponent { showFeedTipTile = false, rankIconCount = 0 } = this.props + const isMobile = this.context.isMobile const status = lineup.status const { loadMoreThreshold, @@ -793,7 +794,6 @@ class LineupProvider extends PureComponent { function mapStateToProps(state: AppState) { return { - isMobile: isMobile(), showTip: getShowTip(state), playing: getPlaying(state), playingUid: getUid(state) diff --git a/packages/web/src/components/lineup/hooks.ts b/packages/web/src/components/lineup/hooks.ts index 7d7402c215a..b49f8cd0d56 100644 --- a/packages/web/src/components/lineup/hooks.ts +++ b/packages/web/src/components/lineup/hooks.ts @@ -10,7 +10,7 @@ import { useDispatch } from 'react-redux' import { LineupVariant } from 'components/lineup/types' import { AppState } from 'store/types' -import { isMobile } from 'utils/clientUtil' +import { useIsMobile } from 'utils/clientUtil' import { useSelector } from 'utils/reducer' const { makeGetCurrent } = queueSelectors @@ -46,6 +46,7 @@ export const useLineupProps = ({ isOrdered }: useLineupPropsProps) => { const dispatch = useDispatch() + const isMobile = useIsMobile() // Create memoized selectors const getLineup = useMemo( @@ -83,7 +84,7 @@ export const useLineupProps = ({ loadMore, numPlaylistSkeletonRows, scrollParent, - isMobile: isMobile(), + isMobile, rankIconCount, isTrending, ordered: isOrdered diff --git a/packages/web/src/components/locked-content-modal/LockedContentModal.tsx b/packages/web/src/components/locked-content-modal/LockedContentModal.tsx index 062453a1e46..ece33fa3412 100644 --- a/packages/web/src/components/locked-content-modal/LockedContentModal.tsx +++ b/packages/web/src/components/locked-content-modal/LockedContentModal.tsx @@ -13,7 +13,8 @@ import { useModalState } from 'common/hooks/useModalState' import { LockedTrackDetailsTile } from 'components/track/LockedTrackDetailsTile' import { PremiumTrackSection } from 'components/track/PremiumTrackSection' import ModalDrawer from 'pages/audio-rewards-page/components/modals/ModalDrawer' -import { isMobile } from 'utils/clientUtil' +import { useSsrContext } from 'ssr/SsrContext' +import { useIsMobile } from 'utils/clientUtil' import styles from './LockedContentModal.module.css' @@ -34,7 +35,7 @@ export const LockedContentModal = () => { dispatch(resetLockedContentId()) }, [setIsOpen, dispatch]) - const mobile = isMobile() + const isMobile = useIsMobile() return ( { useGradientTitle={false} > { export const NavProvider = memo((props: { children: JSX.Element }) => { const contextValue = useNavContext() - if (useIsMobile()) { + const isMobile = useIsMobile() + if (isMobile) { return ( {props.children} diff --git a/packages/web/src/components/notification/Notification/FavoriteNotification.tsx b/packages/web/src/components/notification/Notification/FavoriteNotification.tsx index d79a327066e..b36e64be504 100644 --- a/packages/web/src/components/notification/Notification/FavoriteNotification.tsx +++ b/packages/web/src/components/notification/Notification/FavoriteNotification.tsx @@ -13,7 +13,7 @@ import { setVisibility as openUserListModal } from 'store/application/ui/userListModal/slice' import { UserListType } from 'store/application/ui/userListModal/types' -import { isMobile } from 'utils/clientUtil' +import { useIsMobile } from 'utils/clientUtil' import { useSelector } from 'utils/reducer' import { EntityLink, useGoToEntity } from './components/EntityLink' @@ -55,6 +55,7 @@ export const FavoriteNotification = (props: FavoriteNotificationProps) => { : entityType const dispatch = useDispatch() + const isMobile = useIsMobile() const handleGoToEntity = useGoToEntity(entity, entityType) @@ -68,7 +69,7 @@ export const FavoriteNotification = (props: FavoriteNotificationProps) => { id: id as unknown as number }) ) - if (isMobile()) { + if (isMobile) { dispatch(push(`notification/${id}/users`)) } else { dispatch(openUserListModal(true)) @@ -77,7 +78,7 @@ export const FavoriteNotification = (props: FavoriteNotificationProps) => { handleGoToEntity(event) } }, - [isMultiUser, dispatch, entityType, id, handleGoToEntity] + [isMultiUser, dispatch, entityType, id, handleGoToEntity, isMobile] ) if (!users || !firstUser || !entity) return null diff --git a/packages/web/src/components/notification/Notification/FollowNotification.tsx b/packages/web/src/components/notification/Notification/FollowNotification.tsx index 6b6f10307f6..f40615cf86e 100644 --- a/packages/web/src/components/notification/Notification/FollowNotification.tsx +++ b/packages/web/src/components/notification/Notification/FollowNotification.tsx @@ -15,7 +15,7 @@ import { UserListEntityType, UserListType } from 'store/application/ui/userListModal/types' -import { isMobile } from 'utils/clientUtil' +import { useIsMobile } from 'utils/clientUtil' import { useSelector } from 'utils/reducer' import { profilePage } from 'utils/route' @@ -49,6 +49,7 @@ export const FollowNotification = (props: FollowNotificationProps) => { const otherUsersCount = userIds.length - 1 const isMultiUser = userIds.length > 1 const dispatch = useDispatch() + const isMobile = useIsMobile() const handleClick = useCallback(() => { if (isMultiUser) { @@ -59,7 +60,7 @@ export const FollowNotification = (props: FollowNotificationProps) => { id: id as unknown as number }) ) - if (isMobile()) { + if (isMobile) { dispatch(push(`notification/${id}/users`)) } else { dispatch(openUserListModal(true)) @@ -69,7 +70,7 @@ export const FollowNotification = (props: FollowNotificationProps) => { dispatch(push(profilePage(firstUser.handle))) } } - }, [isMultiUser, dispatch, id, firstUser]) + }, [isMultiUser, dispatch, id, firstUser, isMobile]) if (!users || !firstUser) return null diff --git a/packages/web/src/components/notification/Notification/RepostNotification.tsx b/packages/web/src/components/notification/Notification/RepostNotification.tsx index 4f66af162eb..bc67fd1c529 100644 --- a/packages/web/src/components/notification/Notification/RepostNotification.tsx +++ b/packages/web/src/components/notification/Notification/RepostNotification.tsx @@ -13,7 +13,7 @@ import { setVisibility as openUserListModal } from 'store/application/ui/userListModal/slice' import { UserListType } from 'store/application/ui/userListModal/types' -import { isMobile } from 'utils/clientUtil' +import { useIsMobile } from 'utils/clientUtil' import { useSelector } from 'utils/reducer' import { EntityLink, useGoToEntity } from './components/EntityLink' @@ -56,6 +56,7 @@ export const RepostNotification = (props: RepostNotificationProps) => { : entityType const dispatch = useDispatch() + const isMobile = useIsMobile() const handleGoToEntity = useGoToEntity(entity, entityType) @@ -69,7 +70,7 @@ export const RepostNotification = (props: RepostNotificationProps) => { id: id as unknown as number }) ) - if (isMobile()) { + if (isMobile) { dispatch(push(`notification/${id}/users`)) } else { dispatch(openUserListModal(true)) @@ -78,7 +79,7 @@ export const RepostNotification = (props: RepostNotificationProps) => { handleGoToEntity(event) } }, - [isMultiUser, dispatch, entityType, id, handleGoToEntity] + [isMultiUser, dispatch, entityType, id, handleGoToEntity, isMobile] ) if (!users || !firstUser || !entity) return null diff --git a/packages/web/src/components/notification/Notification/components/UserNameLink.tsx b/packages/web/src/components/notification/Notification/components/UserNameLink.tsx index 435f4a289cc..6d2fee5b5a9 100644 --- a/packages/web/src/components/notification/Notification/components/UserNameLink.tsx +++ b/packages/web/src/components/notification/Notification/components/UserNameLink.tsx @@ -9,7 +9,7 @@ import { make, useRecord } from 'common/store/analytics/actions' import { ArtistPopover } from 'components/artist/ArtistPopover' import UserBadges from 'components/user-badges/UserBadges' import { closeNotificationPanel } from 'store/application/ui/notifications/notificationsUISlice' -import { isMobile } from 'utils/clientUtil' +import { useIsMobile } from 'utils/clientUtil' import { profilePage } from 'utils/route' import styles from './UserNameLink.module.css' @@ -27,6 +27,7 @@ type UserNameLinkProps = { export const UserNameLink = (props: UserNameLinkProps) => { const { className, notification, user } = props const dispatch = useDispatch() + const isMobile = useIsMobile() const record = useRecord() const { type } = notification @@ -79,7 +80,7 @@ export const UserNameLink = (props: UserNameLinkProps) => { ) - if (!isMobile()) { + if (!isMobile) { userNameElement = ( { - const mobile = isMobile() + const isMobile = useIsMobile() const balanceCents = formatUSDCWeiToFloorCentsNumber( (balance ?? new BN(0)) as BNUSDC ) @@ -82,7 +82,7 @@ export const PaymentMethod = ({ icon: IconCreditCard, value: vendorOptions.length > 1 ? ( - mobile ? ( + isMobile ? ( {}} options={vendorOptions} @@ -115,7 +115,7 @@ export const PaymentMethod = ({ const renderBody = () => { const getFlexProps = (id: PurchaseMethod) => { - if (mobile && id === PurchaseMethod.CARD) { + if (isMobile && id === PurchaseMethod.CARD) { return { direction: 'column' as CSSProperties['flexDirection'], justifyContent: 'center', @@ -163,7 +163,7 @@ export const PaymentMethod = ({ {value} diff --git a/packages/web/src/components/play-bar/PlayBarProvider.tsx b/packages/web/src/components/play-bar/PlayBarProvider.tsx index 6285b784e56..3834a9cd2b5 100644 --- a/packages/web/src/components/play-bar/PlayBarProvider.tsx +++ b/packages/web/src/components/play-bar/PlayBarProvider.tsx @@ -4,8 +4,9 @@ import { connect } from 'react-redux' import { RouteComponentProps, withRouter } from 'react-router-dom' import NowPlayingDrawer from 'components/now-playing/NowPlayingDrawer' +import { useSsrContext } from 'ssr/SsrContext' import { AppState } from 'store/types' -import { isMobile } from 'utils/clientUtil' +import { useIsMobile } from 'utils/clientUtil' import styles from './PlayBarProvider.module.css' import DesktopPlayBar from './desktop/PlayBar' @@ -21,11 +22,11 @@ type PlayBarProviderProps = OwnProps & RouteComponentProps const PlayBarProvider = ({ - isMobile, playingUid, collectible, addToPlaylistOpen }: PlayBarProviderProps) => { + const isMobile = useIsMobile() return (
{ const dispatch = useDispatch() + const isMobile = useIsMobile() const { permalink, premium_conditions: { @@ -102,14 +103,12 @@ const RenderForm = ({ dispatch(setPurchasePage({ page: PurchaseContentPage.PURCHASE })) }, [dispatch]) - const mobile = isMobile() - return ( ) : null} - + { const dispatch = useDispatch() + const isMobile = useIsMobile() const { isOpen, onClose, @@ -218,7 +218,6 @@ export const PremiumContentPurchaseModal = () => { if (track && !isValidTrack) { console.error('PremiumContentPurchaseModal: Track is not purchasable') } - const mobile = isMobile() return ( { useGradientTitle={false} dismissOnClickOutside zIndex={zIndex.PREMIUM_CONTENT_PURCHASE_MODAL} - wrapperClassName={mobile ? styles.mobileWrapper : undefined} + wrapperClassName={isMobile ? styles.mobileWrapper : undefined} > {isValidTrack ? ( { + const isMobile = useIsMobile() const wrappedOnClick = () => { !isSelected && onClick() } @@ -29,7 +30,7 @@ const SelectablePill = ({ className={cn(styles.pill, { [styles.selectedPill]: isSelected, [className!]: !!className, - [styles.isMobile]: isMobile() + [styles.isMobile]: isMobile })} > {content} diff --git a/packages/web/src/components/share-modal/ShareModal.tsx b/packages/web/src/components/share-modal/ShareModal.tsx index 2a87e4f4fad..f24380437d2 100644 --- a/packages/web/src/components/share-modal/ShareModal.tsx +++ b/packages/web/src/components/share-modal/ShareModal.tsx @@ -20,7 +20,7 @@ import * as embedModalActions from 'components/embed-modal/store/actions' import { ToastContext } from 'components/toast/ToastContext' import { useFlag } from 'hooks/useRemoteConfig' import { useModalState } from 'pages/modals/useModalState' -import { isMobile } from 'utils/clientUtil' +import { useIsMobile } from 'utils/clientUtil' import { SHARE_TOAST_TIMEOUT_MILLIS } from 'utils/constants' import { useSelector } from 'utils/reducer' import { openTwitterLink } from 'utils/tweet' @@ -42,6 +42,7 @@ export const ShareModal = () => { const { toast } = useContext(ToastContext) const dispatch = useDispatch() + const isMobile = useIsMobile() const record = useRecord() const { content, source } = useSelector(getShareState) const account = useSelector(getAccountUser) @@ -158,6 +159,6 @@ export const ShareModal = () => { content?.type === 'playlist' ? content.playlist.is_private : false } - if (isMobile()) return + if (isMobile) return return } diff --git a/packages/web/src/components/share-sound-to-tiktok-modal/ShareSoundToTikTokModal.tsx b/packages/web/src/components/share-sound-to-tiktok-modal/ShareSoundToTikTokModal.tsx index 7e21b734de4..f4d63281ab7 100644 --- a/packages/web/src/components/share-sound-to-tiktok-modal/ShareSoundToTikTokModal.tsx +++ b/packages/web/src/components/share-sound-to-tiktok-modal/ShareSoundToTikTokModal.tsx @@ -20,7 +20,7 @@ import { useModalState } from 'common/hooks/useModalState' import Drawer from 'components/drawer/Drawer' import LoadingSpinner from 'components/loading-spinner/LoadingSpinner' import { useTikTokAuth } from 'hooks/useTikTokAuth' -import { isMobile } from 'utils/clientUtil' +import { useIsMobile } from 'utils/clientUtil' import styles from './ShareSoundToTikTokModal.module.css' const { getStatus, getTrack } = shareSoundToTiktokModalSelectors @@ -49,7 +49,7 @@ const fileRequirementErrorMessages = { } const ShareSoundToTikTokModal = () => { - const mobile = isMobile() + const isMobile = useIsMobile() const [isOpen, setIsOpen] = useModalState('ShareSoundToTikTok') const dispatch = useDispatch() @@ -148,7 +148,7 @@ const ShareSoundToTikTokModal = () => { } } - return mobile ? ( + return isMobile ? (
diff --git a/packages/web/src/components/subscribe-button/SubscribeButton.tsx b/packages/web/src/components/subscribe-button/SubscribeButton.tsx index da61bf5dfda..a41097119e4 100644 --- a/packages/web/src/components/subscribe-button/SubscribeButton.tsx +++ b/packages/web/src/components/subscribe-button/SubscribeButton.tsx @@ -4,7 +4,7 @@ import cn from 'classnames' import IconNotification from 'assets/img/iconNotification.svg' import IconNotificationOff from 'assets/img/iconNotificationOff.svg' -import { isMobile } from 'utils/clientUtil' +import { useIsMobile } from 'utils/clientUtil' import { isMatrix } from 'utils/theme/theme' import styles from './SubscribeButton.module.css' @@ -24,6 +24,7 @@ const SubscribeButton = ({ }: SubscribeButtonProps) => { const [isHovering, setIsHovering] = useState(false) const [isHoveringClicked, setIsHoveringClicked] = useState(false) + const isMobile = useIsMobile() const onClick = useCallback(() => { onToggleSubscribe() setIsHoveringClicked(true) @@ -39,7 +40,7 @@ const SubscribeButton = ({ [className as string]: !!className, [styles.notFollowing]: !isFollowing, [styles.isSubscribed]: isSubscribed, - [styles.isMobile]: isMobile(), + [styles.isMobile]: isMobile, [styles.isMatrix]: isMatrix() })} onMouseEnter={() => setIsHovering(true)} diff --git a/packages/web/src/components/usdc-manual-transfer/USDCManualTransfer.tsx b/packages/web/src/components/usdc-manual-transfer/USDCManualTransfer.tsx index b3b1bfd4509..c1e9aed8010 100644 --- a/packages/web/src/components/usdc-manual-transfer/USDCManualTransfer.tsx +++ b/packages/web/src/components/usdc-manual-transfer/USDCManualTransfer.tsx @@ -24,7 +24,7 @@ import { Hint } from 'components/withdraw-usdc-modal/components/Hint' import { track as trackAnalytics, make } from 'services/analytics' import { audiusBackendInstance } from 'services/audius-backend/audius-backend-instance' import { getUSDCUserBank } from 'services/solana/solana' -import { isMobile } from 'utils/clientUtil' +import { useIsMobile } from 'utils/clientUtil' import { copyToClipboard } from 'utils/clipboardUtil' import styles from './USDCManualTransfer.module.css' @@ -67,7 +67,7 @@ export const USDCManualTransfer = ({ mint: 'usdc' }) const { toast } = useContext(ToastContext) - const mobile = isMobile() + const isMobile = useIsMobile() const { value: USDCUserBank } = useAsync(async () => { const USDCUserBankPubKey = await getUSDCUserBank() @@ -87,13 +87,13 @@ export const USDCManualTransfer = ({ return ( - - {mobile ? {messages.explainer} : null} + + {isMobile ? {messages.explainer} : null}
{USDCUserBank ? : null}
- {!mobile ? {messages.explainer} : null} + {!isMobile ? {messages.explainer} : null}
{amountInCents === undefined ? ( @@ -113,7 +113,7 @@ export const USDCManualTransfer = ({ - {mobile ? null : ( + {isMobile ? null : ( @@ -121,7 +121,7 @@ export const USDCManualTransfer = ({ ) : ( <> - {mobile ? null : ( + {isMobile ? null : (
diff --git a/packages/web/src/pages/audio-rewards-page/components/ExplainerTile.tsx b/packages/web/src/pages/audio-rewards-page/components/ExplainerTile.tsx index 6a30f1dbaee..1dbac878cb1 100644 --- a/packages/web/src/pages/audio-rewards-page/components/ExplainerTile.tsx +++ b/packages/web/src/pages/audio-rewards-page/components/ExplainerTile.tsx @@ -5,7 +5,7 @@ import cn from 'classnames' import TokenStill from 'assets/img/tokenSpinStill.png' import { useWithMobileStyle } from 'hooks/useWithMobileStyle' -import { isMobile } from 'utils/clientUtil' +import { useIsMobile } from 'utils/clientUtil' import { getTheme, isDarkMode as getIsDarkMode } from 'utils/theme/theme' import styles from './ExplainerTile.module.css' @@ -43,6 +43,7 @@ export const ExplainerTile = ({ className }: { className?: string }) => { const [mouseOver, setMouseOver] = useState(false) const videoRef = useRef(null) const [initialPlaysRemaining, setInitialPlays] = useState(1) + const isMobile = useIsMobile() const handleOnEnded = useCallback(() => { setInitialPlays((p) => p - 1) @@ -59,7 +60,7 @@ export const ExplainerTile = ({ className }: { className?: string }) => { const isDarkMode = getIsDarkMode() const isMatrixMode = getTheme() === Theme.MATRIX - const showSvgToken = isDarkMode || isMatrixMode || isMobile() + const showSvgToken = isDarkMode || isMatrixMode || isMobile const wm = useWithMobileStyle(styles.mobile) return ( diff --git a/packages/web/src/pages/audio-rewards-page/components/WalletManagementTile.tsx b/packages/web/src/pages/audio-rewards-page/components/WalletManagementTile.tsx index 4d6fccefdf3..cb3537b1b0a 100644 --- a/packages/web/src/pages/audio-rewards-page/components/WalletManagementTile.tsx +++ b/packages/web/src/pages/audio-rewards-page/components/WalletManagementTile.tsx @@ -21,6 +21,7 @@ import { push as pushRoute } from 'connected-react-router' import { useDispatch, useSelector } from 'react-redux' import { useAsync } from 'react-use' +import { useHistoryContext } from 'app/HistoryProvider' import IconReceive from 'assets/img/iconReceive.svg' import IconSend from 'assets/img/iconSend.svg' import IconSettings from 'assets/img/iconSettings.svg' @@ -36,7 +37,7 @@ import { ToastContext } from 'components/toast/ToastContext' import Tooltip from 'components/tooltip/Tooltip' import { useFlag, useRemoteVar } from 'hooks/useRemoteConfig' import { getLocation } from 'services/Location' -import { isMobile, getClient } from 'utils/clientUtil' +import { getClient, useIsMobile } from 'utils/clientUtil' import { AUDIO_TRANSACTIONS_PAGE, pushUniqueRoute, @@ -45,8 +46,6 @@ import { import TokenHoverTooltip from './TokenHoverTooltip' import styles from './WalletManagementTile.module.css' -import { useHistory } from 'react-router-dom' -import { useHistoryContext } from 'app/HistoryProvider' const { getHasAssociatedWallets } = tokenDashboardPageSelectors const { pressReceive, pressSend, pressConnectWallets } = tokenDashboardPageActions @@ -88,25 +87,25 @@ const AdvancedWalletActions = () => { const dispatch = useDispatch() const [, openTransferDrawer] = useModalState('TransferAudioMobileWarning') - const mobile = isMobile() + const isMobile = useIsMobile() const { isEnabled: isTransactionsEnabled } = useFlag( FeatureFlags.AUDIO_TRANSACTIONS_HISTORY ) const onClickReceive = useCallback(() => { - if (mobile) { + if (isMobile) { openTransferDrawer(true) } else { dispatch(pressReceive()) } - }, [dispatch, mobile, openTransferDrawer]) + }, [dispatch, isMobile, openTransferDrawer]) const onClickSend = useCallback(() => { - if (mobile) { + if (isMobile) { openTransferDrawer(true) } else { dispatch(pressSend()) } - }, [mobile, dispatch, openTransferDrawer]) + }, [isMobile, dispatch, openTransferDrawer]) const [, setOpen] = useModalState('MobileConnectWalletsDrawer') const onClickTransactions = useCallback(() => { @@ -114,12 +113,12 @@ const AdvancedWalletActions = () => { }, [dispatch]) const onClickConnectWallets = useCallback(() => { - if (mobile) { + if (isMobile) { setOpen(true) } else { dispatch(pressConnectWallets()) } - }, [mobile, setOpen, dispatch]) + }, [isMobile, setOpen, dispatch]) const onCloseConnectWalletsDrawer = useCallback(() => { setOpen(false) @@ -151,7 +150,7 @@ const AdvancedWalletActions = () => { type={ButtonType.GLASS} minWidth={200} /> - {!mobile && isTransactionsEnabled && ( + {!isMobile && isTransactionsEnabled && (
diff --git a/packages/web/src/pages/audio-rewards-page/components/modals/ChallengeRewardsModal/AudioMatchingRewardsModalContent.tsx b/packages/web/src/pages/audio-rewards-page/components/modals/ChallengeRewardsModal/AudioMatchingRewardsModalContent.tsx index 747367dbee3..5e85e7f7468 100644 --- a/packages/web/src/pages/audio-rewards-page/components/modals/ChallengeRewardsModal/AudioMatchingRewardsModalContent.tsx +++ b/packages/web/src/pages/audio-rewards-page/components/modals/ChallengeRewardsModal/AudioMatchingRewardsModalContent.tsx @@ -21,7 +21,7 @@ import LoadingSpinner from 'components/loading-spinner/LoadingSpinner' import { SummaryTable } from 'components/summary-table' import { useNavigateToPage } from 'hooks/useNavigateToPage' import { useWithMobileStyle } from 'hooks/useWithMobileStyle' -import { isMobile } from 'utils/clientUtil' +import { useIsMobile } from 'utils/clientUtil' import { EXPLORE_PREMIUM_TRACKS_PAGE, UPLOAD_PAGE } from 'utils/route' import { ProgressDescription } from './ProgressDescription' @@ -90,6 +90,7 @@ export const AudioMatchingRewardsModalContent = ({ errorContent }: AudioMatchingRewardsModalContentProps) => { const wm = useWithMobileStyle(styles.mobile) + const isMobile = useIsMobile() const navigateToPage = useNavigateToPage() const { fullDescription } = challengeRewardsConfig[challengeName] const { @@ -141,7 +142,7 @@ export const AudioMatchingRewardsModalContent = ({ return (
- {isMobile() ? ( + {isMobile ? ( <> {progressDescription}
diff --git a/packages/web/src/pages/audio-rewards-page/components/modals/ChallengeRewardsModal/ChallengeRewardsModal.tsx b/packages/web/src/pages/audio-rewards-page/components/modals/ChallengeRewardsModal/ChallengeRewardsModal.tsx index 7988a979a05..31bf9ed2647 100644 --- a/packages/web/src/pages/audio-rewards-page/components/modals/ChallengeRewardsModal/ChallengeRewardsModal.tsx +++ b/packages/web/src/pages/audio-rewards-page/components/modals/ChallengeRewardsModal/ChallengeRewardsModal.tsx @@ -38,7 +38,7 @@ import Tooltip from 'components/tooltip/Tooltip' import { ComponentPlacement, MountPlacement } from 'components/types' import { useWithMobileStyle } from 'hooks/useWithMobileStyle' import { getChallengeConfig } from 'pages/audio-rewards-page/config' -import { isMobile } from 'utils/clientUtil' +import { useIsMobile } from 'utils/clientUtil' import { copyToClipboard, getCopyableLink } from 'utils/clipboardUtil' import { CLAIM_REWARD_TOAST_TIMEOUT_MILLIS } from 'utils/constants' import { openTwitterLink } from 'utils/tweet' @@ -226,7 +226,7 @@ const ChallengeRewardsBody = ({ dismissModal }: BodyProps) => { const userHandle = useSelector(getUserHandle) const dispatch = useDispatch() const wm = useWithMobileStyle(styles.mobile) - const displayMobileContent = isMobile() + const isMobile = useIsMobile() const userChallenges = useSelector(getOptimisticUserChallenges) const challenge = userChallenges[modalType] @@ -388,7 +388,7 @@ const ChallengeRewardsBody = ({ dismissModal }: BodyProps) => { /> ) : (
- {displayMobileContent ? ( + {isMobile ? ( <> {progressDescription}
diff --git a/packages/web/src/pages/audio-rewards-page/components/modals/ModalDrawer.tsx b/packages/web/src/pages/audio-rewards-page/components/modals/ModalDrawer.tsx index d9d90cf1a1d..187a86ade36 100644 --- a/packages/web/src/pages/audio-rewards-page/components/modals/ModalDrawer.tsx +++ b/packages/web/src/pages/audio-rewards-page/components/modals/ModalDrawer.tsx @@ -2,7 +2,7 @@ import { Modal, ModalProps } from '@audius/stems' import cn from 'classnames' import Drawer, { DrawerProps } from 'components/drawer/Drawer' -import { isMobile } from 'utils/clientUtil' +import { useIsMobile } from 'utils/clientUtil' import styles from './ModalDrawer.module.css' @@ -16,7 +16,8 @@ type ModalDrawerProps = ModalProps & */ const ModalDrawer = (props: ModalDrawerProps) => { const gradientTitle = props.useGradientTitle ?? true - if (isMobile()) { + const isMobile = useIsMobile() + if (isMobile) { return (