From 78a9b45ffeecc802e2fea1fbd836e58241ce3916 Mon Sep 17 00:00:00 2001 From: elianiva Date: Sun, 1 Jan 2023 06:43:22 +0700 Subject: [PATCH] feat: implement code splitting by routes --- .editorconfig | 4 ++ .eslintignore | 1 + .prettierignore | 1 + CONTRIBUTING.md | 9 +++++ package.json | 1 + pnpm-lock.yaml | 13 +++++-- src/App.css | 0 src/App.tsx | 28 -------------- src/components/Layout.tsx | 17 +++++++++ src/components/Navbar.tsx | 4 +- src/components/PendingFallback.tsx | 28 ++++++++++++++ src/index.css | 6 +++ src/main.tsx | 37 +++++++++++++++---- src/routes/AppRoutes.tsx | 34 +++++++++++++++++ .../CompetitionPage.tsx} | 4 +- src/{pages/Home.tsx => routes/HomePage.tsx} | 5 +-- src/{pages/Idea.tsx => routes/IdeaPage.tsx} | 4 +- src/utils/lazy-import.ts | 23 ++++++++++++ tsconfig.json | 6 ++- vite.config.ts | 6 +++ 20 files changed, 181 insertions(+), 50 deletions(-) create mode 100644 .editorconfig delete mode 100644 src/App.css delete mode 100644 src/App.tsx create mode 100644 src/components/Layout.tsx create mode 100644 src/components/PendingFallback.tsx create mode 100644 src/routes/AppRoutes.tsx rename src/{pages/Competition.tsx => routes/CompetitionPage.tsx} (63%) rename src/{pages/Home.tsx => routes/HomePage.tsx} (88%) rename src/{pages/Idea.tsx => routes/IdeaPage.tsx} (81%) create mode 100644 src/utils/lazy-import.ts diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..ca6870f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +[*] +root = true +indent_size = 2 +indent_style = space diff --git a/.eslintignore b/.eslintignore index fc61e63..8c1c021 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,2 @@ vite.config.ts +dist diff --git a/.prettierignore b/.prettierignore index bd5535a..0730306 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1 +1,2 @@ pnpm-lock.yaml +dist diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 58b343d..9096410 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,27 +18,36 @@ Here's how to contribute a pull request: 1. **Fork the repository**: If you don't already have a copy of the project on your own GitHub account, you'll need to fork the repository to create one. To do this, click the "Fork" button in the top-right corner of the repository page on GitHub. This will create a copy of the repository on your own account. 2. **Clone the repository**: Once you have a copy of the repository on your own account, you'll need to clone it to your local machine. To do this, open a terminal and navigate to the directory where you want to store the project. Then run the following command, replacing [YOUR_USERNAME] with your GitHub username and [YOUR_REPOSITORY] with the name of the repository: + ```sh git clone https://github.com/[YOUR_USERNAME]/[YOUR_REPOSITORY].git ``` + 3. **Create a new branch**: Before you start making changes to the code, it's a good idea to create a new branch. This allows you to work on your changes without affecting the main branch of the repository. To create a new branch, run the following command: + ```sh git checkout -b [BRANCH_NAME] ``` + Replace [BRANCH_NAME] with a descriptive name for your branch, such as "fix-typo" or "add-feature". 4. **Make your changes**: Now you can start making the changes you want to contribute to the project. Make sure to test your changes thoroughly to ensure that they work as intended. 5. Commit your changes: When you're satisfied with your changes, you'll need to commit them to your local repository. To do this, run the following command + ```sh git commit -am "[COMMIT_MESSAGE]" ``` + Replace [COMMIT_MESSAGE] with a brief description of your changes. 6. Push your changes to GitHub: Now that your changes are committed to your local repository, you'll need to push them to your fork on GitHub. To do this, run the following command: + ```sh git push origin [BRANCH_NAME] ``` + 7. **Submit a pull request**: Once your changes are pushed to your fork on GitHub, you can submit a pull request to the project maintainers. To do this, go to the repository page on GitHub and click the "Compare & pull request" button. This will open a form where you can write a brief description of your changes and submit the pull request for review. ## Code of Conduct + We want the Polinema Innovation Tribe project to be an inclusive and welcoming community for everyone. To that end, we have a code of conduct that we ask all contributors to follow. Please make sure you read it before participating. diff --git a/package.json b/package.json index cdd2caa..4ebe2d7 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "devDependencies": { "@iconify-json/heroicons": "^1.1.6", "@svgr/core": "^6.5.1", + "@types/node": "^18.11.18", "@types/react": "^18.0.26", "@types/react-dom": "^18.0.9", "@typescript-eslint/eslint-plugin": "^5.47.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a5efaeb..90f6ac2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3,6 +3,7 @@ lockfileVersion: 5.4 specifiers: '@iconify-json/heroicons': ^1.1.6 '@svgr/core': ^6.5.1 + '@types/node': ^18.11.18 '@types/react': ^18.0.26 '@types/react-dom': ^18.0.9 '@typescript-eslint/eslint-plugin': ^5.47.1 @@ -36,6 +37,7 @@ dependencies: devDependencies: '@iconify-json/heroicons': 1.1.6 '@svgr/core': 6.5.1 + '@types/node': 18.11.18 '@types/react': 18.0.26 '@types/react-dom': 18.0.10 '@typescript-eslint/eslint-plugin': 5.47.1_axni7f4fgvh6tlufnh6hwgsifq @@ -50,7 +52,7 @@ devDependencies: tailwindcss: 3.2.4_postcss@8.4.20 typescript: 4.9.4 unplugin-icons: 0.14.15_@svgr+core@6.5.1 - vite: 4.0.3 + vite: 4.0.3_@types+node@18.11.18 packages: @@ -1029,6 +1031,10 @@ packages: dev: false optional: true + /@types/node/18.11.18: + resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==} + dev: true + /@types/normalize-package-data/2.4.1: resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} dev: true @@ -1199,7 +1205,7 @@ packages: '@babel/plugin-transform-react-jsx-source': 7.19.6_@babel+core@7.20.7 magic-string: 0.27.0 react-refresh: 0.14.0 - vite: 4.0.3 + vite: 4.0.3_@types+node@18.11.18 transitivePeerDependencies: - supports-color dev: true @@ -4173,7 +4179,7 @@ packages: spdx-expression-parse: 3.0.1 dev: true - /vite/4.0.3: + /vite/4.0.3_@types+node@18.11.18: resolution: {integrity: sha512-HvuNv1RdE7deIfQb8mPk51UKjqptO/4RXZ5yXSAvurd5xOckwS/gg8h9Tky3uSbnjYTgUm0hVCet1cyhKd73ZA==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true @@ -4198,6 +4204,7 @@ packages: terser: optional: true dependencies: + '@types/node': 18.11.18 esbuild: 0.16.12 postcss: 8.4.20 resolve: 1.22.1 diff --git a/src/App.css b/src/App.css deleted file mode 100644 index e69de29..0000000 diff --git a/src/App.tsx b/src/App.tsx deleted file mode 100644 index 08e9426..0000000 --- a/src/App.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import "./App.css"; -import { BrowserRouter, Route, Routes } from "react-router-dom"; -import Home from "./pages/Home"; -import Navbar from "./components/Navbar"; -import Idea from "./pages/Idea"; -import Competition from "./pages/Competition"; - -function App() { - return ( - -
-
- -
-
- - } /> - } /> - } /> - } /> - -
-
-
- ); -} - -export default App; diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx new file mode 100644 index 0000000..2f66674 --- /dev/null +++ b/src/components/Layout.tsx @@ -0,0 +1,17 @@ +import { Suspense } from "react"; +import { Outlet } from "react-router-dom"; +import Navbar from "./Navbar"; +import { PendingFallback } from "./PendingFallback"; + +export function Layout() { + return ( + <> + +
+ }> + + +
+ + ); +} diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index 2302d1f..a264700 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -9,9 +9,9 @@ function Navbar() {
- +

Politribe

-
+
+ ); +} diff --git a/src/index.css b/src/index.css index e869973..c5ba5d7 100644 --- a/src/index.css +++ b/src/index.css @@ -8,6 +8,12 @@ @apply font-bold text-white; } + html, + body, + #root { + @apply h-full w-full; + } + body { @apply bg-[#131A22]; } diff --git a/src/main.tsx b/src/main.tsx index 02055fd..d2fdd92 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,10 +1,33 @@ -import React from "react"; -import ReactDOM from "react-dom/client"; -import App from "./App"; +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import { AppRoutes } from "./routes/AppRoutes"; import "./index.css"; -ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( - - - +const root = document.getElementById("root") as HTMLElement; +createRoot(root).render( + + + +); + +const showErrorOverlay = (err: unknown) => { + const elementName = "vite-error-overlay"; + const ErrorOverlay = customElements.get(elementName); + + // prevent double overlay + const isAlreadyAppear = document.body.contains( + document.querySelector(elementName) + ); + const isDev = import.meta.env.DEV; + + if (!ErrorOverlay || isAlreadyAppear || !isDev) { + return; + } + + document.body.appendChild(new ErrorOverlay(err)); +}; + +window.addEventListener("error", showErrorOverlay); +window.addEventListener("unhandledrejection", ({ reason }) => + showErrorOverlay(reason) ); diff --git a/src/routes/AppRoutes.tsx b/src/routes/AppRoutes.tsx new file mode 100644 index 0000000..819c2e2 --- /dev/null +++ b/src/routes/AppRoutes.tsx @@ -0,0 +1,34 @@ +import { + createBrowserRouter, + Navigate, + RouterProvider, +} from "react-router-dom"; +import { Layout } from "~/components/Layout"; +import { PendingFallback } from "~/components/PendingFallback"; +import { lazyImport } from "~/utils/lazy-import"; + +const { CompetitionPage } = lazyImport( + () => import("./CompetitionPage"), + "CompetitionPage" +); +const { HomePage } = lazyImport(() => import("./HomePage"), "HomePage"); +const { IdeaPage } = lazyImport(() => import("./IdeaPage"), "IdeaPage"); + +export function AppRoutes() { + const router = createBrowserRouter([ + { + path: "*", + element: , + children: [ + { index: true, element: }, + { path: "idea", element: }, + { path: "competition", element: }, + { path: "*", element: }, + ], + }, + ]); + + return ( + } router={router} /> + ); +} diff --git a/src/pages/Competition.tsx b/src/routes/CompetitionPage.tsx similarity index 63% rename from src/pages/Competition.tsx rename to src/routes/CompetitionPage.tsx index 6562ea6..d2c3d46 100644 --- a/src/pages/Competition.tsx +++ b/src/routes/CompetitionPage.tsx @@ -1,7 +1,5 @@ import React from "react"; -function Competition() { +export function CompetitionPage() { return
Competition page
; } - -export default Competition; diff --git a/src/pages/Home.tsx b/src/routes/HomePage.tsx similarity index 88% rename from src/pages/Home.tsx rename to src/routes/HomePage.tsx index f0eba05..242841a 100644 --- a/src/pages/Home.tsx +++ b/src/routes/HomePage.tsx @@ -1,10 +1,11 @@ import React, { useEffect } from "react"; import Hero from "../parts/HomePage/Hero"; -function Home() { +export function HomePage() { useEffect(() => { document.title = "Politribe | Home"; }, []); + return (
@@ -12,5 +13,3 @@ function Home() {
); } - -export default Home; diff --git a/src/pages/Idea.tsx b/src/routes/IdeaPage.tsx similarity index 81% rename from src/pages/Idea.tsx rename to src/routes/IdeaPage.tsx index b7000bb..88629a6 100644 --- a/src/pages/Idea.tsx +++ b/src/routes/IdeaPage.tsx @@ -1,10 +1,8 @@ import React, { useEffect } from "react"; -function Idea() { +export function IdeaPage() { useEffect(() => { document.title = "Politribe | Idea"; }, []); return
Idea page
; } - -export default Idea; diff --git a/src/utils/lazy-import.ts b/src/utils/lazy-import.ts new file mode 100644 index 0000000..98e4006 --- /dev/null +++ b/src/utils/lazy-import.ts @@ -0,0 +1,23 @@ +import * as React from "react"; + +/** + * Named imports for React.lazy + * + * @links {@see https://github.com/facebook/react/issues/14603#issuecomment-726551598 GitHub comment} + * + * @usage + * ```tsx + * const { Home } = lazyImport(() => import("./Home"), "Home"); + * ``` + */ +export function lazyImport< + T extends React.ComponentType, + I extends { [K2 in K]: T }, + K extends keyof I +>(factory: () => Promise, name: K): I { + return Object.create({ + [name]: React.lazy(() => + factory().then((module) => ({ default: module[name] })) + ), + }); +} diff --git a/tsconfig.json b/tsconfig.json index 95697bf..e658561 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,7 +15,11 @@ "isolatedModules": true, "noEmit": true, "jsx": "react-jsx", - "types": ["unplugin-icons/types/react"] + "types": ["unplugin-icons/types/react"], + "baseUrl": ".", + "paths": { + "~/*": ["src/*"] + } }, "include": ["src"], "references": [{ "path": "./tsconfig.node.json" }] diff --git a/vite.config.ts b/vite.config.ts index 5bbc3bd..c91fa22 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,8 +1,14 @@ import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; import Icons from "unplugin-icons/vite"; +import path from "node:path"; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react(), Icons({ compiler: "jsx", jsx: "react" })], + resolve: { + alias: { + "~": path.resolve("src"), + }, + }, });