- π Running Locally
- π Goals
- 𧱠Architecture
- π Pre-rendering
- π€ Show your support
- β Author
-
Prerequisites
-
Clone the repository
git clone https://github.com/YashTotale/portfolio-v2.git cd portfolio-v2
-
Install dependencies
npm install
-
Set up environment variables
Please reach out to me at [email protected] for these π. Paste them into
.env
. Use.env.example
as an example:CONTENTFUL_ACCESS_TOKEN= CONTENTFUL_SPACE_ID= CONTENTFUL_MANAGEMENT_ACCESS_TOKEN= REACT_APP_RECAPTCHA_KEY=
-
Fetch data
npm run data
-
Start local development
npm start
-
(Optional) Start local Firebase emulators
This step is only required if you plan to change any features involving Firebase services like authentication, storage, Firestore, and Cloud Functions. If you wish to run the Cloud Functions emulator, ensure that you are using
[email protected]
.Steps:
-
npm run emulate
-
Uncomment the
useEmulator()
call in the Firebase config file. -
To edit Cloud Functions, refer to the functions directory for steps.
-
As you may have noticed, this is my second attempt at a portfolio website. The first one was ... a total failure. 600+ commits in, I realized that I had overcomplicated and under-planned the project. Instead of focusing on a clean and intuitive UI, I had gotten bogged down in adding relatively useless features that I thought were cool (like dynamic Wikipedia & LinkedIn integration). So, to avoid another failure, I set a few goals ahead of time:
I used Figma to design almost all of the website's pages before I even created the GitHub repo. This helped me quickly build an MVP of the entire website. From there, I was able to optimize and improve specific areas without losing sight of the overall picture.
I used Contentful as my headless CMS. This allowed me to separate out my website's layout and its content, reducing the amount of changes I would need to make to the code over time. Also, Contentful was a much better alternative to Google Sheets (which I used for my first portfolio website).
If you browse through the Components, Pages, or Utils folders, you'll see quite a few patterns in each. This is on purpose: by "patternizing" my code, I was able to quickly add new features/pages or make edits to existing UI.
Components are divided into 4 folders: Atomic, Content, Custom, and Static
Atomic components can be used essentially anywhere. They are meant to be building blocks for layouts, with specific styling/UI to make the website consistent.
Content components are meant to be UI for a specific type of content. They can be further divided into Main, Preview, Overlay/Mini/Associated.
- Main content components are to be displayed on that specific content's own page. For example, on the route
/experience/<slug>
, the Main component for that specific experience will be displayed. - Preview content components are to be displayed on the content type's page. For example, on the route
/experience
, the Preview components for all experiences will be displayed. - The other content components such as Overlay, Mini, and Associated are to be displayed anywhere else as "supporting" components. For example, on a specific tag's page (
/tags/<slug>
), the related experience, articles, and projects of the tag will also be displayed via Overlay components.
Custom components are extensively configured components (like a Rich Text renderer) that can be used in multiple areas of the application. They are generally not atomic as they are meant for a very specific purpose.
Static components are rendered only once. These include elements like the Navbar, Footer, Sidebar, etc.
Each page of the website is a folder in the Pages directory (except the NotFound and Error pages which are just files). Each folder contains an index.tsx
file for the UI of that page.
- Every page calls a
useAnalytics
hook, which logs apage_view
event to Google Analytics. - Every page updates the
<head>
of the HTML using React Helmet.
Any utilities such as functions, types, constants, etc. are located in the Utils folder.
Additionally, content utilities are located in the Content subdirectory. Each file in this folder contains utilities to get, resolve, filter, and sort a specific content type.
Pre-rendering is a way to generate static HTML files for a SPA. I used pre-rendering largely to boost page-load times and SEO. Learn more about its benefits on the react-snap GitHub page.
Sounds pretty simple, but there are a few caveats with pre-rendering that took a little while for me to debug.
react-snap and other pre-rendering libraries use puppeteer to launch a headless Chrome browser to crawl your site's web pages and generate HTML files.
This works great locally, but if you're pre-rendering in a CI/CD step, you have to include some extra configuration for puppeteer to work properly. Here is what you need to include in your project's package.json
:
"reactSnap": {
"puppeteerArgs": [
"--no-sandbox",
"--disable-setuid-sandbox",
"--disable-gpu"
]
}
If you attempt to pre-render your website with API requests or something similar (ex. Google Analytics event logging) enabled, you'll likely face Navigation Timeout Exceeded
or Protocol Error
issues. There's a simple fix for this: just don't make those calls during the pre-rendering stage. Here's how:
if (navigator.userAgent !== "ReactSnap") {
// Do your requests here
}
Give a βοΈ if this project helped you! Since this project is licensed under the MIT License, you can use my code in your own projects or portfolio websites π
Feel free to reach out to me via email or through the contact form of this site!
Yash Totale
- Github: @YashTotale
- LinkedIn: @yash-totale
- Email: [email protected]