Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate to Vite #101

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
# production
/build

# dev cache
/dev-dist

# misc
.DS_Store
.env.local
Expand Down
28 changes: 18 additions & 10 deletions public/index.html → index.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
<meta property="og:description" content="VTuber Music Player" />

<!-- <meta property="og:image" content="https://www.holodex.net/img/intro-promo.jpg" /> -->
<meta property="og:url" content="%PUBLIC_URL%" />
<meta property="og:url" content="" />
<meta name="og:site_name" property="og:site_name" content="MUSICDEX" />

<meta property="twitter:site" content="@holodex" />
Expand All @@ -58,19 +58,27 @@
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
<link rel="manifest" href="/manifest.json" />
<style>
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
"Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
overflow: hidden;
}

Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
body:not(.chakra-ui-dark) {
background-color: #1a202c;
}
</style>
</head>

<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>
18 changes: 10 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
},
"scripts": {
"analyze": "source-map-explorer 'build/static/js/*.js' & source-map-explorer --gzip 'build/static/js/*.js'",
"build": "react-scripts build",
"dev": "cross-env GENERATE_SOURCEMAP=false react-scripts start",
"dev:local-api": "cross-env API_TARGET=local react-scripts start",
"eject": "react-scripts eject",
"build": "vite build",
"dev": "vite dev",
"preview": "vite preview",
"dev:local-api": "cross-env API_TARGET=local vite dev",
"prepare": "husky install",
"test": "react-scripts test --passWithNoTests",
"test": "vitest run --passWithNoTests",
"i18n": "rimraf -r build/tmp && tsc --jsx preserve --noEmit false --target es2020 --outDir build/tmp && i18next-scanner"
},
"dependencies": {
Expand All @@ -43,7 +43,6 @@
"idb-keyval": "^6.2.0",
"lodash-es": "^4.17.21",
"oauth-open": "^1.0.4",
"querystringify": "^2.2.0",
"react": "^18.2.0",
"react-beautiful-dnd": "^13.1.0",
"react-contexify": "^6.0.0",
Expand All @@ -59,7 +58,6 @@
"react-router": "^6.3.0",
"react-router-dom": "^6.3.0",
"react-router-use-location-state": "^3.0.2",
"react-scripts": "^5.0.1",
"react-snaplist-carousel": "^4.4.2",
"react-table": "^7.8.0",
"react-virtualized": "^9.22.3",
Expand Down Expand Up @@ -99,6 +97,7 @@
"@types/react-window": "^1.8.5",
"@types/runes": "^0.4.1",
"@types/youtube-player": "^5.5.6",
"@vitejs/plugin-react": "^2.1.0",
"bundlewatch": "^0.3.3",
"color-convert": "^2.0.1",
"consistent-shading": "^1.1.0",
Expand All @@ -107,11 +106,14 @@
"http-proxy-middleware": "^2.0.6",
"husky": "^8.0.1",
"i18next-scanner": "^4.0.0",
"patch-package": "^6.4.7",
"prettier": "^2.7.1",
"pretty-quick": "^3.1.3",
"react-git-info": "^2.0.1",
"rimraf": "^3.0.2",
"source-map-explorer": "^2.5.2",
"vite": "^3.1.4",
"vite-plugin-pwa": "^0.13.1",
"vitest": "^0.23.4",
"web-vitals": "^2.1.4"
},
"browserslist": {
Expand Down
10 changes: 10 additions & 0 deletions patches/react-virtualized+9.22.3.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
diff --git a/node_modules/react-virtualized/dist/es/WindowScroller/utils/onScroll.js b/node_modules/react-virtualized/dist/es/WindowScroller/utils/onScroll.js
index d00f0f1..42456dc 100644
--- a/node_modules/react-virtualized/dist/es/WindowScroller/utils/onScroll.js
+++ b/node_modules/react-virtualized/dist/es/WindowScroller/utils/onScroll.js
@@ -71,4 +71,3 @@ export function unregisterScrollListener(component, element) {
}
}
}
-import { bpfrpt_proptype_WindowScroller } from "../WindowScroller.js";
\ No newline at end of file
33 changes: 33 additions & 0 deletions scripts/mem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const { execSync } = require("child_process");

const self_pid = process.pid.toString();
const data = [];
const sum = (/** @type {number[]} */ a) => a.reduce((p, c) => p + c, 0);
const lastLog = Date.now();
const second = 1000; /* ms */

function measure_memory() {
let total = 0;
const tasks = execSync("tasklist").toString().split("\n").slice(3, -1);
for (let i = 0; i < tasks.length; ++i) {
const task = tasks[i];
const [name, pid, , , memory] = task.split(/\s+/);
if (name.toLowerCase().includes("node") && pid !== self_pid) {
total += +memory.replaceAll(/,/g, "");
}
}
data.push(total);

if (Date.now() - lastLog > 2 * second) {
const min = Math.round(data.reduce((min, c) => (c < min ? c : min)) / 1000);
const max = Math.round(data.reduce((max, c) => (c > max ? c : max)) / 1000);
const avg = Math.round(sum(data) / data.length / 1000);
console.log(`avg ${avg} MB, min ${min} MB, max ${max} MB`);
}

if (total !== 0) {
setTimeout(measure_memory, 100);
}
}

setTimeout(measure_memory, 100);
2 changes: 1 addition & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ErrorBoundary } from "react-error-boundary";
import { ErrorFallback } from "./components/common/ErrorFallback";
import usePageTracking from "./modules/common/usePageTracking";
import { useCookieTokenFallback, useTokenRefresh } from "./modules/client";
import { unregister } from "./serviceWorkerRegistration";
import { unregister } from "./utils/serviceWorker";
import { LoadingFullScreen } from "./components/common/GlobalLoadingStatus";
import { useTranslation } from "react-i18next";

Expand Down
2 changes: 1 addition & 1 deletion src/components/common/ErrorFallback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
import { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { useClient } from "../../modules/client";
import { unregister } from "../../serviceWorkerRegistration";
import { unregister } from "../../utils/serviceWorker";

export function ErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
const { t } = useTranslation();
Expand Down
53 changes: 22 additions & 31 deletions src/components/common/ServiceWorkerWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,34 @@
import React, { useEffect } from "react";
import * as serviceWorker from "../../serviceWorkerRegistration";
import { Box, Text, CloseButton, HStack, Button } from "@chakra-ui/react";
import { useTranslation } from "react-i18next";
import { useRegisterSW } from "virtual:pwa-register/react";

const SW_UPDATE_INTERVAL = 15 * 60 * 1000;

const ServiceWorkerWrapper = () => {
const { t } = useTranslation();
const [showReload, setShowReload] = React.useState(false);
const [dismissed, setDismissed] = React.useState(false);
const [waitingWorker, setWaitingWorker] =
React.useState<ServiceWorker | null>(null);

const onSWUpdate = (registration: ServiceWorkerRegistration) => {
if (!registration) return;
setShowReload(true);
setWaitingWorker(registration.waiting);
};

useEffect(() => {
serviceWorker.addUpdateHook(onSWUpdate);
}, []);

const reloadPage = () => {
setShowReload(false);
if (waitingWorker) {
waitingWorker?.postMessage({ type: "SKIP_WAITING" });
waitingWorker?.addEventListener("statechange", (e: any) => {
if (e.target.state === "activated") {
window.location.reload();
}
});
}
};
const {
needRefresh: [needRefresh, setNeedRefresh],
updateServiceWorker,
} = useRegisterSW({
onRegistered(r) {
console.log("SW Registered: " + r);
r &&
setInterval(() => {
r.update();
}, SW_UPDATE_INTERVAL);
},
onRegisterError(error) {
console.log("SW registration error", error);
},
});

return showReload && !dismissed ? (
return needRefresh ? (
<Box
position="absolute"
top="env(safe-area-inset-top)"
bgColor="brand.400"
dropShadow={"dark-lg"}
shadow="dark-lg"
px={4}
py={3}
m={2}
Expand All @@ -49,13 +40,13 @@ const ServiceWorkerWrapper = () => {
<Button
size="sm"
fontSize={"md"}
onClick={reloadPage}
onClick={() => updateServiceWorker(true)}
color="white"
bgColor="n2.400"
>
{t("Reload")}
</Button>
<CloseButton onClick={() => setDismissed(true)} />
<CloseButton onClick={() => setNeedRefresh(false)} />
</HStack>
</Box>
) : null;
Expand Down
7 changes: 2 additions & 5 deletions src/components/layout/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,8 @@ import {
import { FaDiscord, FaGithub, FaTwitter } from "react-icons/fa";
import { SiKofi } from "react-icons/si";
import { ContainerInlay } from "./ContainerInlay";
import GitInfo from "react-git-info/macro";
import { format } from "date-fns";

const gi = GitInfo();

const SocialButton = ({ icon, ...rest }: any) => {
return (
<IconButton
Expand Down Expand Up @@ -43,8 +40,8 @@ export default function Footer() {
<Text>
© 2020 Holodex.{" "}
<small style={{ color: "#445" }}>
Musicdex (beta) build {gi.commit.shortHash}/
{format(new Date(gi.commit.date), "LLL dd HH:mm")}
Musicdex (beta) build {GIT_COMMIT_HASH}/
{format(new Date(GIT_COMMIT_TIMESTAMP), "LLL dd HH:mm")}
</small>
</Text>
<Stack direction={"row"} spacing={6}>
Expand Down
7 changes: 3 additions & 4 deletions src/components/nav/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,9 @@ export interface LinkItemProps {
disabled?: boolean;
}

const HOLODEX_URL =
process.env.NODE_ENV === "production"
? "https://holodex.net"
: "https://staging.holodex.net";
const HOLODEX_URL = import.meta.env.PROD
? "https://holodex.net"
: "https://staging.holodex.net";

export function SidebarContent({
closeOnNav = false,
Expand Down
9 changes: 2 additions & 7 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,9 @@ import "@fontsource/assistant/400.css";
import "@fontsource/assistant/500.css";
import "@fontsource/assistant/600.css";
import { BrowserRouter as Router } from "react-router-dom";
import * as serviceWorkerRegistration from "./serviceWorkerRegistration";
// import * as serviceWorkerRegistration from "./serviceWorkerRegistration";
import { HelmetProvider } from "react-helmet-async";

console.log(
`VERSION: ${process.env.REACT_APP_NAME} ${process.env.REACT_APP_VERSION}`,
);
(window as any)["App_Version"] = process.env.REACT_APP_VERSION;

// https://github.com/ctrlplusb/easy-peasy/issues/741
type Props = StoreProvider["props"] & { children: React.ReactNode };
const StoreProviderReact18Casted =
Expand All @@ -56,4 +51,4 @@ store.persist.resolveRehydration().then(() => {
);
});

serviceWorkerRegistration.register();
// serviceWorkerRegistration.register();
2 changes: 1 addition & 1 deletion src/modules/common/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ i18n
.use(initReactI18next) // passes i18n down to react-i18next
.init({
// resources,
debug: process.env.NODE_ENV === "development",
debug: import.meta.env.DEV,
fallbackLng: "en",
saveMissing: true,
supportedLngs: [
Expand Down
17 changes: 12 additions & 5 deletions src/modules/playlist/useFormatPlaylist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ import { TFunction, useTranslation } from "react-i18next";
import useNamePicker from "../common/useNamePicker";
import { formatters } from "./formatters";

// FIXME: Migrate to URLSearchParams
var qs = require("querystringify");

type PlaylistLike = Partial<PlaylistFull>;

export type SGPTypes =
Expand Down Expand Up @@ -42,6 +39,16 @@ export function isSGPPlaylist(playlistId: string) {

const IDSplitter = /[[\]]/;

function parseParamString(v: string): any {
return Object.fromEntries(
new URLSearchParams(v.split(",").join("&")).entries(),
);
}

function stringifyParams(v: Record<string, any>): string {
return new URLSearchParams(v).toString();
}

/**
* Parses a SGP id
* @param id id string
Expand All @@ -54,7 +61,7 @@ export function parsePlaylistID(id: string): {
const [type, paramString] = id.split(IDSplitter);
return {
type: type as SGPTypes | RadioTypes,
params: paramString ? qs.parse(paramString.split(",").join("&")) : {},
params: paramString ? parseParamString(paramString) : {},
};
}

Expand All @@ -68,7 +75,7 @@ export function formatPlaylistID(
type: SGPTypes | RadioTypes,
params: Record<string, any>,
) {
return `${String(type)}[${qs.stringify(params)}]`;
return `${String(type)}[${stringifyParams(params)}]`;
}

type FormatFunctions =
Expand Down
1 change: 0 additions & 1 deletion src/react-app-env.d.ts

This file was deleted.

Loading