diff --git a/package.json b/package.json
index 71a8501..840475a 100644
--- a/package.json
+++ b/package.json
@@ -8,11 +8,15 @@
"preview": "vite preview"
},
"dependencies": {
+ "@tanstack/react-query": "^4.2.1",
+ "@tanstack/react-query-devtools": "^4.2.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
+ "react-infinite-scroller": "^1.2.6",
"react-router-dom": "^6.3.0",
+ "react-toastify": "^9.0.8",
"swiper": "^8.1.0",
- "swr": "^1.2.2"
+ "uuid": "^8.3.2"
},
"devDependencies": {
"@vitejs/plugin-react": "^1.0.7",
diff --git a/src/App.jsx b/src/App.jsx
deleted file mode 100644
index 2a118fc..0000000
--- a/src/App.jsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import { Fragment, Suspense, lazy } from "react";
-import { Routes, Route } from "react-router-dom";
-import Main from "./components/layout/Main";
-import LoadingComponent from "./components/loading/LoadingComponent";
-
-const HomePage = lazy(() => import("./page/HomePage"));
-const AnimePage = lazy(() => import("./page/AnimePage"));
-const SearchPage = lazy(() => import("./page/SearchPage"));
-const AnimeDetailPage = lazy(() => import("./page/AnimeDetailPage"));
-const CharacterPage = lazy(() => import("./page/CharacterPage"));
-const CharacterDetailPage = lazy(() => import("./page/CharacterDetailPage"));
-const Error404Page = lazy(() => import("./page/Error404Page"));
-
-import "swiper/css";
-
-const App = () => {
- return (
-
- }>
-
- }>
- } />
- } />
- } />
- } />
- }
- />
- } />
-
-
- } />
-
-
-
- );
-};
-
-export default App;
diff --git a/src/apis/apis.jsx b/src/apis/apis.jsx
new file mode 100644
index 0000000..c76f2f9
--- /dev/null
+++ b/src/apis/apis.jsx
@@ -0,0 +1,19 @@
+export const getAnimeDetail = async (id) => {
+ const res = await fetch(`https://api.jikan.moe/v4/anime/${id}`);
+ return res.json();
+};
+
+export const getListAnime = async (type) => {
+ const res = await fetch(`https://api.jikan.moe/v4/${type}`);
+ return res.json();
+};
+
+export const getCharacterDetail = async (id) => {
+ const res = await fetch(`https://api.jikan.moe/v4/characters/${id}`);
+ return res.json();
+};
+
+export const search = async (url) => {
+ const res = await fetch(url);
+ return res.json();
+};
diff --git a/src/components/anime/AnimeList.jsx b/src/components/anime/AnimeList.jsx
index e172fc4..8ea0fed 100644
--- a/src/components/anime/AnimeList.jsx
+++ b/src/components/anime/AnimeList.jsx
@@ -1,25 +1,32 @@
-import useSWR from "swr";
-import { fetcher } from "../../utils/fetcher";
import { Swiper, SwiperSlide } from "swiper/react";
import AnimeItem from "./AnimeItem";
import AnimeItemSkeleton from "./AnimeItemSkeleton";
+import { getListAnime } from "../../apis/apis";
+import { useQuery } from "@tanstack/react-query";
+import { toast } from "react-toastify";
+import { useNavigate } from "react-router-dom";
-const AnimeList = ({ url }) => {
- const { data, error } = useSWR(url, fetcher);
- const loading = !data && !error;
+const AnimeList = ({ type }) => {
+ const { data, isError, isLoading } = useQuery(["list-anime", type], () =>
+ getListAnime(type)
+ );
+ const navigate = useNavigate();
- if (error) console.error(error);
+ if (isError) {
+ toast.error("Something went wrong! Please try again!");
+ return navigate("/");
+ }
return (
- {loading &&
+ {isLoading &&
new Array(10).fill(0).map((item, index) => (
))}
- {!loading &&
+ {!isLoading &&
data &&
data.data.length > 0 &&
data.data.map((anime) => (
diff --git a/src/components/layout/Main.jsx b/src/components/layout/ShareLayout.jsx
similarity index 77%
rename from src/components/layout/Main.jsx
rename to src/components/layout/ShareLayout.jsx
index 84d696d..28d1489 100644
--- a/src/components/layout/Main.jsx
+++ b/src/components/layout/ShareLayout.jsx
@@ -2,7 +2,7 @@ import { Outlet } from "react-router-dom";
import Header from "./Header";
import Footer from "./Footer";
-const Main = () => {
+const ShareLayout = () => {
return (
<>
@@ -12,4 +12,4 @@ const Main = () => {
);
};
-export default Main;
+export default ShareLayout;
diff --git a/src/components/search/SearchContainer.jsx b/src/components/search/SearchContainer.jsx
index 8479df4..83b48bc 100644
--- a/src/components/search/SearchContainer.jsx
+++ b/src/components/search/SearchContainer.jsx
@@ -1,26 +1,42 @@
-import useSWR from "swr";
import AnimeItem from "../anime/AnimeItem";
-import { fetcher } from "../../utils/fetcher";
-import { Swiper, SwiperSlide } from "swiper/react";
import { useEffect, useRef, useState } from "react";
import CharacterItem from "../character/CharacterItem";
import AnimeItemSkeleton from "../anime/AnimeItemSkeleton";
-import CharacterItemSkeleton from "../character/CharacterItemSkeleton";
+import { search } from "../../apis/apis";
+import { toast } from "react-toastify";
+import { useNavigate } from "react-router-dom";
+import { v4 } from "uuid";
+import { useInfiniteQuery } from "@tanstack/react-query";
+import InfiniteScroll from "react-infinite-scroller";
const SearchContainer = ({ type }) => {
+ const navigate = useNavigate();
const [query, setQuery] = useState("naruto");
const inputRef = useRef(null);
const searchBtnRef = useRef(null);
- const url =
- type === "anime"
- ? "https://api.jikan.moe/v4/anime"
- : "https://api.jikan.moe/v4/characters";
+ const url = `https://api.jikan.moe/v4/${type}?q=${query}`;
- const { data, error } = useSWR(`${url}?q=${query}`, fetcher);
+ const { data, hasNextPage, fetchNextPage, isError, isLoading } =
+ useInfiniteQuery(
+ [`search-${type}`, query],
+ ({ pageParam = url }) => search(pageParam),
+ {
+ getNextPageParam: (lastPage, allPages) =>
+ lastPage.pagination.has_next_page
+ ? `${url}&page=${lastPage.pagination.current_page + 1}`
+ : undefined,
+ }
+ );
+
+ if (isLoading) {
+ toast.info("Loading...");
+ }
- if (error) console.error(error);
- const loading = !data && !error;
+ if (isError) {
+ toast.error("Something went wrong! Please try again!");
+ return navigate("/");
+ }
useEffect(() => {
const handlerEnterKeyPress = (e) => {
@@ -36,6 +52,8 @@ const SearchContainer = ({ type }) => {
};
}, []);
+ console.log(data);
+
return (
@@ -57,37 +75,29 @@ const SearchContainer = ({ type }) => {
-
- {loading &&
- new Array(4)
- .fill(0)
- .map((item, index) => (
-
- {type === "anime" ? (
-
- ) : (
-
- )}
-
- ))}
- {!loading &&
- data &&
- data.data.length > 0 &&
- data.data.map((item) => (
-
- {type === "anime" ? (
-
- ) : (
-
- )}
-
+ {isLoading && (
+
+ {new Array(4).fill(0).map(() => (
+
))}
- {data && data.data.length <= 0 && (
-
- Keyword: {query} is empty!
-
- )}
-
+
+ )}
+
+
+ {!isLoading &&
+ data.pages.map((pageData) =>
+ pageData.data.map((item) => (
+ <>
+ {type === "anime" ? (
+
+ ) : (
+
+ )}
+ >
+ ))
+ )}
+
+
diff --git a/src/main.jsx b/src/main.jsx
index 358d9e6..49b4372 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -1,12 +1,58 @@
import { render } from "react-dom";
-import { BrowserRouter } from "react-router-dom";
+import { lazy, Suspense } from "react";
+import { BrowserRouter, Route, Routes } from "react-router-dom";
-import App from "./App";
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
+
+import LoadingComponent from "./components/loading/LoadingComponent";
+import ShareLayout from "./components/layout/ShareLayout";
+
+const HomePage = lazy(() => import("./page/HomePage"));
+const AnimePage = lazy(() => import("./page/AnimePage"));
+const SearchPage = lazy(() => import("./page/SearchPage"));
+const AnimeDetailPage = lazy(() => import("./page/AnimeDetailPage"));
+const CharacterPage = lazy(() => import("./page/CharacterPage"));
+const CharacterDetailPage = lazy(() => import("./page/CharacterDetailPage"));
+const Error404Page = lazy(() => import("./page/Error404Page"));
+
+import "swiper/css";
+import "react-toastify/dist/ReactToastify.css";
import "./index.scss";
+import { ToastContainer } from "react-toastify";
+
+const queryClient = new QueryClient();
render(
-
-
- ,
+
+
+ }>
+
+ }>
+ } />
+ } />
+ } />
+ } />
+ }
+ />
+ } />
+
+
+ } />
+
+
+
+
+ ,
document.getElementById("root")
);
diff --git a/src/page/AnimeDetailPage.jsx b/src/page/AnimeDetailPage.jsx
index 402faec..d36d5bb 100644
--- a/src/page/AnimeDetailPage.jsx
+++ b/src/page/AnimeDetailPage.jsx
@@ -1,6 +1,4 @@
-import { useParams } from "react-router-dom";
-import useSWR from "swr";
-import { fetcher } from "../utils/fetcher";
+import { useNavigate, useParams } from "react-router-dom";
import DetailStatus from "../components/anime-details/DetailStatus";
import IconStar from "../components/icons/IconStar";
@@ -11,16 +9,23 @@ import IconRank from "../components/icons/IconRank";
import { getRating } from "../utils/getRating";
import DetailListItem from "../components/anime-details/DetailListItem";
import LoadingComponent from "../components/loading/LoadingComponent";
+import { useQuery } from "@tanstack/react-query";
+import { getAnimeDetail } from "../apis/apis";
+import { toast } from "react-toastify";
const AnimeDetailPage = () => {
const { animeID } = useParams();
+ const navigate = useNavigate();
- const { data, error } = useSWR(
- `https://api.jikan.moe/v4/anime/${animeID}`,
- fetcher
+ const { data, error, isLoading } = useQuery(["anime", animeID], () =>
+ getAnimeDetail(animeID)
);
- if (error) console.error(error);
- if (!data) return ;
+
+ if (error) {
+ toast.error("Something went wrong! Please try again!");
+ return navigate("/");
+ }
+ if (isLoading) return ;
const {
images,
diff --git a/src/page/AnimePage.jsx b/src/page/AnimePage.jsx
index 4cda532..3a1f268 100644
--- a/src/page/AnimePage.jsx
+++ b/src/page/AnimePage.jsx
@@ -5,17 +5,17 @@ const AnimePage = () => {
);
diff --git a/src/page/CharacterDetailPage.jsx b/src/page/CharacterDetailPage.jsx
index aff22a8..36c81e5 100644
--- a/src/page/CharacterDetailPage.jsx
+++ b/src/page/CharacterDetailPage.jsx
@@ -1,19 +1,24 @@
-import useSWR from "swr";
-import { useParams } from "react-router-dom";
-import { fetcher } from "../utils/fetcher";
+import { useNavigate, useParams } from "react-router-dom";
+import { useQuery } from "@tanstack/react-query";
import IconFavorite from "../components/icons/IconFavorite";
import IconEmail from "../components/icons/IconEmail";
import LoadingComponent from "../components/loading/LoadingComponent";
+import { getCharacterDetail } from "../apis/apis";
+import { toast } from "react-toastify";
const CharacterDetailPage = () => {
+ const navigate = useNavigate();
const { characterID } = useParams();
- const { data, error } = useSWR(
- `https://api.jikan.moe/v4/characters/${characterID}`,
- fetcher
+ const { data, isError, isLoading } = useQuery(
+ ["character", characterID],
+ () => getCharacterDetail(characterID)
);
- if (error) console.error(error);
- if (!data) return ;
+ if (isError) {
+ toast.error("Something went wrong! Please try again!");
+ return navigate("/");
+ }
+ if (isLoading) return ;
const { images, name, name_kanji, nicknames, favorites, about, url } =
data.data;
diff --git a/src/page/Error404Page.jsx b/src/page/Error404Page.jsx
index 5260217..5fac6bb 100644
--- a/src/page/Error404Page.jsx
+++ b/src/page/Error404Page.jsx
@@ -8,11 +8,7 @@ const Error404Page = () => {
-
+
Oops!
You need map!
diff --git a/yarn.lock b/yarn.lock
index d8cd0b3..2ed25ae 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -310,6 +310,41 @@
estree-walker "^2.0.1"
picomatch "^2.2.2"
+"@tanstack/match-sorter-utils@^8.0.0-alpha.82":
+ version "8.1.1"
+ resolved "https://registry.yarnpkg.com/@tanstack/match-sorter-utils/-/match-sorter-utils-8.1.1.tgz#895f407813254a46082a6bbafad9b39b943dc834"
+ integrity sha512-IdmEekEYxQsoLOR0XQyw3jD1GujBpRRYaGJYQUw1eOT1eUugWxdc7jomh1VQ1EKHcdwDLpLaCz/8y4KraU4T9A==
+ dependencies:
+ remove-accents "0.4.2"
+
+"@tanstack/query-core@^4.0.0-beta.1":
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.2.1.tgz#21ff3a33f27bf038c990ea53af89cf7c7e8078fc"
+ integrity sha512-UOyOhHKLS/5i9qG2iUnZNVV3R9riJJmG9eG+hnMFIPT/oRh5UzAfjxCtBneNgPQZLDuP8y6YtRYs/n4qVAD5Ng==
+
+"@tanstack/react-query-devtools@^4.2.1":
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-4.2.1.tgz#decee3d1d174b253fa303d5baaa478fb0e2c0e63"
+ integrity sha512-k7Ch3qvs8U74aRMMRvNisxcxZFTzk8FDdvpQKXxSZ8fsD4ZwpM0MoUSqKsCXbfTvUI7MJiGxavy1YlvImPNO+Q==
+ dependencies:
+ "@tanstack/match-sorter-utils" "^8.0.0-alpha.82"
+ "@types/use-sync-external-store" "^0.0.3"
+ use-sync-external-store "^1.2.0"
+
+"@tanstack/react-query@^4.2.1":
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.2.1.tgz#1f00f03573b35a353e62fa64f904bbb0286a1808"
+ integrity sha512-w02oTOYpoxoBzD/onAGRQNeLAvggLn7WZjS811cT05WAE/4Q3br0PTp388M7tnmyYGbgOOhFq0MkhH0wIfAKqA==
+ dependencies:
+ "@tanstack/query-core" "^4.0.0-beta.1"
+ "@types/use-sync-external-store" "^0.0.3"
+ use-sync-external-store "^1.2.0"
+
+"@types/use-sync-external-store@^0.0.3":
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43"
+ integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==
+
"@vitejs/plugin-react@^1.0.7":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-1.3.2.tgz#2fcf0b6ce9bcdcd4cec5c760c199779d5657ece1"
@@ -432,6 +467,11 @@ chalk@^2.0.0:
optionalDependencies:
fsevents "~2.3.2"
+clsx@^1.1.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
+ integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
+
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
@@ -784,7 +824,7 @@ lilconfig@^2.0.5:
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.5.tgz#19e57fd06ccc3848fd1891655b5a447092225b25"
integrity sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==
-loose-envify@^1.1.0:
+loose-envify@^1.1.0, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -917,6 +957,15 @@ postcss@^8.4.12, postcss@^8.4.13, postcss@^8.4.14:
picocolors "^1.0.0"
source-map-js "^1.0.2"
+prop-types@^15.5.8:
+ version "15.8.1"
+ resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
+ integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
+ dependencies:
+ loose-envify "^1.4.0"
+ object-assign "^4.1.1"
+ react-is "^16.13.1"
+
queue-microtask@^1.2.2:
version "1.2.3"
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
@@ -936,6 +985,18 @@ react-dom@^17.0.2:
object-assign "^4.1.1"
scheduler "^0.20.2"
+react-infinite-scroller@^1.2.6:
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/react-infinite-scroller/-/react-infinite-scroller-1.2.6.tgz#8b80233226dc753a597a0eb52621247f49b15f18"
+ integrity sha512-mGdMyOD00YArJ1S1F3TVU9y4fGSfVVl6p5gh/Vt4u99CJOptfVu/q5V/Wlle72TMgYlBwIhbxK5wF0C/R33PXQ==
+ dependencies:
+ prop-types "^15.5.8"
+
+react-is@^16.13.1:
+ version "16.13.1"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
+ integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
+
react-refresh@^0.13.0:
version "0.13.0"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.13.0.tgz#cbd01a4482a177a5da8d44c9755ebb1f26d5a1c1"
@@ -956,6 +1017,13 @@ react-router@6.3.0:
dependencies:
history "^5.2.0"
+react-toastify@^9.0.8:
+ version "9.0.8"
+ resolved "https://registry.yarnpkg.com/react-toastify/-/react-toastify-9.0.8.tgz#3876c89fc6211a29027b3075010b5ec39ebe4f7e"
+ integrity sha512-EwM+teWt49HSHx+67qI08yLAW1zAsBxCXLCsUfxHYv1W7/R3ZLhrqKalh7j+kjgPna1h5LQMSMwns4tB4ww2yQ==
+ dependencies:
+ clsx "^1.1.1"
+
react@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
@@ -983,6 +1051,11 @@ regenerator-runtime@^0.13.4:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
+remove-accents@0.4.2:
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.4.2.tgz#0a43d3aaae1e80db919e07ae254b285d9e1c7bb5"
+ integrity sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==
+
resolve@^1.1.7, resolve@^1.22.0:
version "1.22.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198"
@@ -1068,11 +1141,6 @@ swiper@^8.1.0:
dom7 "^4.0.4"
ssr-window "^4.0.2"
-swr@^1.2.2:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/swr/-/swr-1.3.0.tgz#c6531866a35b4db37b38b72c45a63171faf9f4e8"
- integrity sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==
-
tailwindcss@^3.0.23:
version "3.1.2"
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.1.2.tgz#b5607d17adb6cbb11a13738cc5fdf3e5527dcd7a"
@@ -1113,11 +1181,21 @@ to-regex-range@^5.0.1:
dependencies:
is-number "^7.0.0"
+use-sync-external-store@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
+ integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
+
util-deprecate@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
+uuid@^8.3.2:
+ version "8.3.2"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
+ integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
+
vite@^2.9.0:
version "2.9.12"
resolved "https://registry.yarnpkg.com/vite/-/vite-2.9.12.tgz#b1d636b0a8ac636afe9d83e3792d4895509a941b"