<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <generator>Persumi - Level up your writing and blogging with AI</generator>
  <link href="http://persumi.com/u/menglim"/>
  <link href="http://persumi.com/u/menglim/feed/rss"/>
  <link rel="self" href="http://persumi.com/u/menglim/feed/atom"/>
  <author>
    <name>Meng Lim</name>
    <email>menglim.life@gmail.com</email>
    <uri>http://persumi.com/u/menglim</uri>
  </author>
  <subtitle>Coder by day, Judoka by night</subtitle>
  <id>http://persumi.com/u/menglim</id>
  <title>Meng Lim (@menglim)</title>
  <updated>2026-04-17T05:53:36.259780Z</updated>
  <entry>
    <content type="html">&lt;![CDATA[&lt;h1&gt;
Learning to Fall: The Beginning of My Judo Journey&lt;/h1&gt;
&lt;p&gt;
I still remember my first day on the tatami. I walked into the dojo, not knowing what to expect. The room was full of young children—toddlers, really—laughing and gleefully throwing each other around. Watching them tumble and roll with such carefree joy was &lt;strong&gt;both hilarious and oddly mesmerizing&lt;/strong&gt;.  &lt;/p&gt;
&lt;p&gt;
Among the other first-timers, I met our sensei for the first time. He kindly lent us Judo Gis and patiently taught us how to wear them properly: &lt;strong&gt;left side over right&lt;/strong&gt;. In Japanese tradition, crossing the right side over the left is reserved specifically for the deceased. He then showed us how to tie our belts, and without much further instruction, we followed along with running—forwards, backwards, and sideways—rolling our wrists and neck, and stretching our chests.  &lt;/p&gt;
&lt;p&gt;
Being no stranger to the gym, I initially thought the warm-up felt manageable—until we reached the next stage. Forward rolls, backward rolls, handstand rolls, backward handstand rolls, cartwheels, and a host of other movements that, while not entirely foreign, I had never attempted. Even a year later, the &lt;strong&gt;15-minute warm-up still humbles me&lt;/strong&gt;. No matter how many times I repeat it, the spinning, rolling, and tumbling always leaves me a dizzy.  &lt;/p&gt;
&lt;p&gt;
The first real lesson was &lt;strong&gt;&lt;a href=&quot;https://www.judo-ch.jp/english/dictionary/terms/ukemi/&quot;&gt;ukemi&lt;/a&gt;&lt;/strong&gt;, or break-falling—the art of falling safely. For the next 45 minutes, we practiced all types of ukemi, slapping the mat repeatedly, unsure at first how it would actually reduce the impact. By the end, though, I could feel my body slowly learning to absorb the falls.  &lt;/p&gt;
&lt;p&gt;
Eventually, we progressed to our first throw: &lt;strong&gt;O-Goshi (Major Hip Throw)&lt;/strong&gt;. The sensei demonstrated it, and as the Uke (the partner receiving the throw) hit the mat with a satisfying thud, awe spread across everyone’s faces. Quiet murmurs of “ooooh” and “wow” rippled through the group. The throw looked smooth, effortless—and yet utterly devastating.  &lt;/p&gt;
&lt;p&gt;
Breaking down the technique revealed its true complexity. There are four main principles in any Judo throw, simplified here:  &lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;
&lt;strong&gt;Kumi-kata (Establishing Grips):&lt;/strong&gt; Securing a dominant grip on the opponent’s gi to control posture and movement.    &lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;Kuzushi (Breaking Balance):&lt;/strong&gt; Using the grips and body movement to off-balance the opponent, making them vulnerable.    &lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;Tsukuri (Entry/Positioning):&lt;/strong&gt; Positioning the body correctly for the throw while the opponent remains off-balance.    &lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;Kake (Execution):&lt;/strong&gt; Completing the throw using leverage and momentum to bring the opponent to the mat.    &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
If you are keen to see the breakdown for Ogoshi - watch this Youtube tutorial &lt;a href=&quot;https://www.youtube.com/watch?v=VLYKx-Fwhxg&quot;&gt;Watch O-goshi tutorial&lt;/a&gt; or watch it from the official Kodokan archives &lt;a href=&quot;https://www.youtube.com/watch?v=yhu1mfy2vJ4&quot;&gt;Watch Kodokan Ogoshi&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
If you like to see it competition environment aka in the Olympics - &lt;a href=&quot;https://www.youtube.com/shorts/I5PYk8Q-x8g&quot;&gt;Watch here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
At the end of class, one of the senior judoka threw us onto a thick padded mattress to practice break-falls before experiencing a full throw on the mat. Nervous anticipation mixed with exhilaration—it was the first real taste of Judo’s blend of &lt;strong&gt;discipline, respect, and controlled chaos&lt;/strong&gt;.  &lt;/p&gt;
&lt;p&gt;
Looking back, that first day taught me more than technique. It taught me humility, patience, and the importance of showing up—even when the mats feel intimidating, the drills exhausting, or the throws impossible. Judo, I realized, isn’t just about throwing—it’s about &lt;strong&gt;learning to fall, getting back up, and embracing every moment in between&lt;/strong&gt;.  &lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Takeaway:&lt;/strong&gt; Embrace the falls, focus on learning, and celebrate every small step forward.&lt;/p&gt;
]]&gt;</content>
    <published>2025-09-11T10:43:15.591582Z</published>
    <link href="http://persumi.com/u/menglim/judo/e/learning-to-fall-the-beginning-of-my-judo-journey/p/learning-to-fall-the-beginning-of-my-judo-journey"/>
    <author>
      <name>Meng Lim</name>
      <email>menglim.life@gmail.com</email>
      <uri>http://persumi.com/u/menglim</uri>
    </author>
    <id>http://persumi.com/u/menglim/judo/e/learning-to-fall-the-beginning-of-my-judo-journey/p/learning-to-fall-the-beginning-of-my-judo-journey</id>
    <title>Learning to Fall: The Beginning of My Judo Journey</title>
    <updated>2025-09-11T10:43:15.591582Z</updated>
  </entry>
  <entry>
    <content type="html">&lt;![CDATA[&lt;h1&gt;
Designing a Modern Data Platform: Integrating AWS AppFlow, Fivetran, Snowflake, dbt, and Alation&lt;/h1&gt;
&lt;h2&gt;
Why Modern Data Platforms Matter&lt;/h2&gt;
&lt;p&gt;
Data isn’t just an asset — it powers &lt;strong&gt;smarter decisions&lt;/strong&gt;, drives &lt;strong&gt;operational efficiency&lt;/strong&gt;, enhances &lt;strong&gt;customer experiences&lt;/strong&gt;, and enables &lt;strong&gt;strategic growth&lt;/strong&gt;. Companies generate vast amounts of information daily, from customer records and marketing campaigns to app usage logs. But &lt;strong&gt;raw data alone isn’t enough&lt;/strong&gt;; turning it into insights that are &lt;strong&gt;trustworthy, actionable, and strategically valuable&lt;/strong&gt; is what drives real business impact. This is where a modern data platform comes in.&lt;/p&gt;
&lt;p&gt;
Modern platforms unify fragmented data, enabling organizations to extract value efficiently, govern information responsibly, and operationalize insights across teams. They go beyond centralized storage to create an ecosystem where analytics can drive &lt;strong&gt;real-time, data-informed decisions&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
The Big Picture&lt;/h2&gt;
&lt;p&gt;
A modern data platform is more than a collection of tools — it’s a framework built around five pillars:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
&lt;strong&gt;Data Ingestion&lt;/strong&gt; – &lt;em&gt;Fivetran, AWS AppFlow, Amazon DMS&lt;/em&gt;: Centralize raw data from SaaS apps, Postgres databases, APIs, and streams.    &lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;Storage &amp; Modeling&lt;/strong&gt; – &lt;em&gt;Snowflake&lt;/em&gt;: Structure and organize data for performance, clarity, and trust.    &lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;Transformation &amp; Quality&lt;/strong&gt; – &lt;em&gt;dbt&lt;/em&gt;: Transform raw data into reliable, analytics-ready datasets while enforcing quality.    &lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;Governance &amp; Discovery&lt;/strong&gt; – &lt;em&gt;Alation&lt;/em&gt;: Build trust, ensure lineage, and support self-service discovery.    &lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;Operational Activation&lt;/strong&gt; – &lt;em&gt;AWS AppFlow (Reverse ETL / Census ETL)&lt;/em&gt;: Push insights back into business systems, including &lt;strong&gt;AI/ML-driven predictions and recommendations&lt;/strong&gt;, enabling both real-time and predictive decision-making.  &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
&lt;/h3&gt;
&lt;a id=&quot;figure-1&quot;&gt;&lt;/a&gt;&lt;p&gt;
  &lt;img src=&quot;https://raw.githubusercontent.com/mengopudding/mengopudding.github.io/ff85b25cc15a197545f96d1d9276c52d79e81c5b/persumi/EDP.png&quot; alt=&quot;modern data platform architecture&quot; /&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;Figure-1  Modern Data Platform Architecture&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
Where Insights Meet Action&lt;/h2&gt;
&lt;p&gt;
The real value of a modern platform emerges when all components &lt;strong&gt;interact seamlessly&lt;/strong&gt;. Data flows from &lt;strong&gt;Snowflake&lt;/strong&gt; into &lt;strong&gt;dbt&lt;/strong&gt; for &lt;em&gt;refinement&lt;/em&gt;, is cataloged and governed through &lt;strong&gt;Alation&lt;/strong&gt;, and can ultimately be &lt;em&gt;operationalized&lt;/em&gt; back into business systems.  &lt;/p&gt;
&lt;p&gt;
Insights aren’t just visualized for human decision-making — they can trigger &lt;strong&gt;automated, real-time actions&lt;/strong&gt; across the organization. Dashboards remain valuable for monitoring &lt;em&gt;trends&lt;/em&gt;, &lt;strong&gt;KPIs&lt;/strong&gt;, and business metrics, but the bigger vision is to move insights closer to &lt;strong&gt;action&lt;/strong&gt;, turning data into tangible impact.&lt;/p&gt;
&lt;h3&gt;
Scenario: Sales Opportunity Prioritization&lt;/h3&gt;
&lt;p&gt;
&lt;strong&gt;Traditional dashboard approach:&lt;/strong&gt;  &lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
Sales managers review a Tableau or Salesforce dashboard showing opportunity scores, deal stages, and lead engagement.    &lt;/li&gt;
  &lt;li&gt;
They manually decide which leads or accounts to prioritize.  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;strong&gt;Bigger vision / operationalized approach:&lt;/strong&gt;  &lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
A predictive scoring model evaluates every lead daily for likelihood to close.    &lt;/li&gt;
  &lt;li&gt;
Scores are automatically pushed into Salesforce via Reverse ETL.    &lt;/li&gt;
  &lt;li&gt;
High-priority leads trigger automated workflows:      &lt;ul&gt;
      &lt;li&gt;
Route leads to the appropriate reps.        &lt;/li&gt;
      &lt;li&gt;
Send automated emails or follow-ups.        &lt;/li&gt;
      &lt;li&gt;
Schedule reminders in Salesforce for timely engagement.      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Sales dashboards still exist for monitoring pipeline health, but the platform moves the most promising leads into action, reducing response time and improving close rates.  &lt;br /&gt;
&lt;em&gt;This illustrates how a modern data platform transforms static insights into automated, actionable workflows.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
The Heart of the Platform&lt;/h2&gt;
&lt;p&gt;
At the core is &lt;strong&gt;Snowflake&lt;/strong&gt;, which stores raw ingested data following the layered design shown in &lt;a href=&quot;#figure-1&quot;&gt;Figure 1&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
&lt;strong&gt;Bronze Layer (Raw / Landing):&lt;/strong&gt; Raw ingested data preserved for traceability.    &lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;Silver Layer (Curated / Staged):&lt;/strong&gt; Cleansed, harmonized, and validated data forming a reliable foundation.    &lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;Gold Layer (Mart / Analytics-ready):&lt;/strong&gt; Fully refined datasets for insights, dashboards, operational use, and ready for &lt;strong&gt;data marts&lt;/strong&gt; or secure sharing with internal/external teams (e.g., private shares or Snowflake Marketplace).  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
While Snowflake provides the backbone, &lt;strong&gt;dbt is where the real magic happens&lt;/strong&gt;. It &lt;em&gt;transforms, tests, and models&lt;/em&gt; raw data into trusted, actionable intelligence. Both dbt and &lt;strong&gt;Schemachange&lt;/strong&gt; are version-controlled in GitHub for &lt;strong&gt;collaboration, reproducibility, and auditability&lt;/strong&gt;. dbt handles transformations, testing, and modeling, while Schemachange generates traceable &lt;strong&gt;DDL/DML scripts&lt;/strong&gt;. Deployment automation is managed separately via &lt;strong&gt;GitHub Actions&lt;/strong&gt;, keeping the platform reliable and consistent.&lt;/p&gt;
&lt;h2&gt;
Orchestration, Observability, and Security&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;
&lt;strong&gt;Orchestration:&lt;/strong&gt; Workflows managed through &lt;strong&gt;dbt Cloud Jobs&lt;/strong&gt; to handle scheduling, dependencies, and retries.    &lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;Observability:&lt;/strong&gt; Logs from dbt and AWS services flow into &lt;strong&gt;Splunk&lt;/strong&gt; and &lt;strong&gt;AWS CloudWatch&lt;/strong&gt;, with &lt;strong&gt;Slack alerts&lt;/strong&gt; for anomalies.    &lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;Security &amp; Compliance:&lt;/strong&gt; RBAC, dynamic masking, IAM roles, CloudFormation provisioning, and Docker ensure secure, auditable, and consistent environments.  &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
Fivetran and AWS AppFlow: Data Ingestion&lt;/h2&gt;
&lt;p&gt;
Fivetran and AWS AppFlow ensure &lt;strong&gt;continuous, reliable data flow&lt;/strong&gt; into the platform. Fivetran provides managed connectors for apps like Salesforce and Marketo, while AppFlow supports flexible integrations, reverse ETL, and data from relational sources like Postgres.&lt;/p&gt;
&lt;h2&gt;
Alation: Governance and Discovery&lt;/h2&gt;
&lt;p&gt;
Alation enables trust and compliance with:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
Automated dataset cataloging    &lt;/li&gt;
  &lt;li&gt;
Lineage tracking across ingestion and transformations    &lt;/li&gt;
  &lt;li&gt;
Stewardship workflows for critical datasets  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Employees can explore datasets confidently, understanding the meaning and context of each column, supporting self-service analytics.&lt;/p&gt;
&lt;h2&gt;
Operational Activation: Reverse ETL&lt;/h2&gt;
&lt;p&gt;
Curated insights become actionable when fed into operational systems. AWS AppFlow moves them into CRMs, marketing platforms, or support tools. For example, &lt;strong&gt;customer lifetime value metrics&lt;/strong&gt; synced into Salesforce enable &lt;strong&gt;real-time, data-driven decisions&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
Delivering Value Across the Organization&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;
&lt;strong&gt;Seamless flow:&lt;/strong&gt; Systems connected end-to-end, minimizing friction.    &lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;Trust and governance:&lt;/strong&gt; Quality checks, lineage tracking, and RBAC ensure reliability.    &lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;Scalability:&lt;/strong&gt; New sources, transformations, and destinations can be added without disruption.    &lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;Operational impact:&lt;/strong&gt; Verified data reaches the right teams, enabling informed, timely decisions.  &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
Trade-offs and Lessons Learned&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;
&lt;strong&gt;Performance vs. Cost in Snowflake:&lt;/strong&gt;      &lt;br /&gt;
Initially, all warehouses defaulted to &lt;strong&gt;M size&lt;/strong&gt;, and data retention was set to maximum days, which resulted in high costs. Most workloads could have run on &lt;strong&gt;XS or S warehouses&lt;/strong&gt;, and data retention could be tuned per use case.      &lt;br /&gt;
&lt;strong&gt;Lesson:&lt;/strong&gt; Balancing &lt;strong&gt;performance and cost&lt;/strong&gt; requires deliberate warehouse sizing, retention policies, and monitoring usage patterns.    &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
&lt;strong&gt;Fivetran Ingestion vs. Cost and Source Load:&lt;/strong&gt;      &lt;br /&gt;
Frequent ingestion from the main Postgres database caused load spikes and increased cost due to &lt;strong&gt;MARR&lt;/strong&gt; and high volumes. Switching to an &lt;strong&gt;in-house ingestion strategy&lt;/strong&gt; using &lt;strong&gt;AWS DMS or AppFlow&lt;/strong&gt; reduced costs and lessened strain on source systems.      &lt;br /&gt;
&lt;strong&gt;Lesson:&lt;/strong&gt; Evaluate ingestion frequency, revisit ingestion patterns, and impact on source systems to optimize cost and reliability.    &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
&lt;strong&gt;Query Performance vs. Model Complexity in dbt:&lt;/strong&gt;      &lt;br /&gt;
dbt transformations prioritized &lt;strong&gt;clarity and modularity&lt;/strong&gt;, which sometimes slowed queries on large datasets. Using &lt;strong&gt;materialized views&lt;/strong&gt; improved performance but increased maintenance overhead.      &lt;br /&gt;
&lt;strong&gt;Lesson:&lt;/strong&gt; Balance &lt;strong&gt;maintainable, modular data models&lt;/strong&gt; with &lt;strong&gt;runtime performance&lt;/strong&gt;, and profile models for production workloads.    &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
&lt;strong&gt;RBAC Ownership vs. Cross-team Integration:&lt;/strong&gt;      &lt;br /&gt;
Snowflake integrates with &lt;strong&gt;OKTA&lt;/strong&gt;, managed by a separate security team. Initially, duplicating groups and roles for quick access became difficult to manage.      &lt;br /&gt;
&lt;strong&gt;Lesson:&lt;/strong&gt; Define &lt;strong&gt;clear ownership boundaries&lt;/strong&gt;, specifying which teams manage which roles and groups, reducing duplication and complexity.      &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
&lt;strong&gt;Code Visibility vs. Ad-hoc Workarounds:&lt;/strong&gt;      &lt;br /&gt;
Team members unfamiliar with Git workflows sometimes manually ran queries to unblock others, which caused the RBAC source of truth to go out of alignment.      &lt;br /&gt;
&lt;strong&gt;Lesson:&lt;/strong&gt; Emphasize &lt;strong&gt;code visibility, version control, and peer review&lt;/strong&gt;, ensuring all changes are tracked and auditable.    &lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;hr class=&quot;thin&quot; /&gt;
&lt;p&gt;
&lt;strong&gt;In summary&lt;/strong&gt;, a modern data platform is more than technology — it’s an enabler of &lt;strong&gt;trust, efficiency, and operational impact&lt;/strong&gt;. By combining ingestion, transformation, governance, observability, and secure operations, organizations can unlock the full potential of their data and turn it into a &lt;strong&gt;strategic advantage&lt;/strong&gt;.&lt;/p&gt;
]]&gt;</content>
    <published>2025-09-11T02:06:40.286724Z</published>
    <link href="http://persumi.com/c/persumi/u/menglim/p/designing-a-modern-data-platform-integrating-aws-appflow-fivetran-snowflake-dbt-and-alation"/>
    <author>
      <name>Meng Lim</name>
      <email>menglim.life@gmail.com</email>
      <uri>http://persumi.com/u/menglim</uri>
    </author>
    <id>http://persumi.com/c/persumi/u/menglim/p/designing-a-modern-data-platform-integrating-aws-appflow-fivetran-snowflake-dbt-and-alation</id>
    <title>Designing a Modern Data Platform: Integrating AWS AppFlow, Fivetran, Snowflake, dbt, and Alation</title>
    <updated>2025-09-11T02:06:40.286724Z</updated>
  </entry>
  <entry>
    <content type="html">&lt;![CDATA[&lt;p&gt;
This guide will walk you through how to Deploy a React app using Vite and Github Pages, which you can serve on your &lt;code class=&quot;inline&quot;&gt;githubUsername.github.io&lt;/code&gt; domain for Free 😉, or on a custom domain you own.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;My use case&lt;/strong&gt;: A personal website, but this works for any single-page application.&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;Note:&lt;/em&gt; I initially built this website with a static HTML and CSS, but after the code grew to over 1,000 lines (yikes! I know), I decided to relive my days as a software engineer and write it in React. This guide highlights some of the key challenges I faced deploying React and Vite on Github Pages.&lt;/p&gt;
&lt;h3&gt;
Step 1: Naming Your Repository&lt;/h3&gt;
&lt;p&gt;
As trivial as it is, this first step is more important than it sounds. The name of your GitHub repository directly determines your final URL. To have your website served from &lt;code class=&quot;inline&quot;&gt;https://githubUsername.github.io&lt;/code&gt; without a sub-folder, you must name your repository exactly &lt;code class=&quot;inline&quot;&gt;githubUsername.github.io&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;
For example, if I want the final URL to be &lt;code class=&quot;inline&quot;&gt;https://mengopudding.github.io&lt;/code&gt; and my username is &lt;code class=&quot;inline&quot;&gt;mengopudding&lt;/code&gt;, I must name my repository &lt;code class=&quot;inline&quot;&gt;mengopudding.github.io&lt;/code&gt;. Had I named the repo &lt;code class=&quot;inline&quot;&gt;portfolio&lt;/code&gt;, the final URL would be &lt;code class=&quot;inline&quot;&gt;https://mengopudding.github.io/portfolio&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
Step 2: Create a React App with Vite&lt;/h3&gt;
&lt;p&gt;
While it has been many moons since I’ve written any JavaScript. While I still remember the gist of things (so I thought), the only one command I knew &lt;code class=&quot;inline&quot;&gt;create-react-app&lt;/code&gt;, is now considered outdated and there is a new kid on the block: &lt;code class=&quot;inline&quot;&gt;Vite&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
To get started, open your terminal and run the following command. Choose “React” and choose your flavor when prompted. ~ I went with TypeScript.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;bash language-bash&quot;&gt;npm create vite@latest my-app — —template react-ts&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
To verify things are working, navigate into your new project and run the standard dev commands:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;bash language-bash&quot;&gt;cd my-app
npm install
npm run dev&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
You should also see a &lt;code class=&quot;inline&quot;&gt;vite.config.ts&lt;/code&gt; file&lt;/p&gt;
&lt;h3&gt;
Step 3: Configure Tailwind CSS&lt;/h3&gt;
&lt;p&gt;
I never used Tailwind in production environment before, the last design system I used was Braid by Seek — but Tailwind seems to be the go-to in the recent years.&lt;/p&gt;
&lt;p&gt;
You can also follow the official &lt;a href=&quot;https://tailwindcss.com/docs/installation/using-vite&quot;&gt;Get started with Vite &amp; Tailwind documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
First, install the necessary dependencies for Tailwind CSS. &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;bash language-bash&quot;&gt;npm install tailwindcss @tailwindcss/vite&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Next, configure the Vite plugin in your vite. See &lt;a href=&quot;https://vite.dev/config/&quot;&gt;Official docs&lt;/a&gt; for configuring your vite plugin.&lt;/p&gt;
&lt;p&gt;
Your &lt;code class=&quot;inline&quot;&gt;vite.config.ts&lt;/code&gt; should look like this.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;typescript language-typescript&quot;&gt;//vite.config.ts

import { defineConfig } from &apos;vite&apos;
import react from &apos;@vitejs/plugin-react&apos;
import tailwindcss from &apos;@tailwindcss/vite&apos; // &lt;- added this import

export default defineConfig({
  plugins: [react(),tailwindcss()], // &lt;- added tailwindcss() to the array
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Next, add the Tailwind directives to your main CSS file. This is often src/index.css or src/App.css. &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;css language-css&quot;&gt; /* App.css or index.css */
@import &quot;tailwindcss&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Tailwind uses a Just-in-Time (JIT) compiler to scan your code and generate only the CSS you need, resulting in much smaller, more efficient CSS files.&lt;/p&gt;
&lt;p&gt;
To verify Tailwind is working, try adding a class like &lt;code class=&quot;inline&quot;&gt;text-red-500&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;html language-html&quot;&gt;&lt;h1 className=&quot;text-red-500&quot;&gt;Vite + React&lt;/h1&gt; &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
To verify, run &lt;code class=&quot;inline&quot;&gt;npm run dev&lt;/code&gt;, visit the localhost and you should see the changes.&lt;/p&gt;
&lt;h3&gt;
Step 4: Configure Vite for Github Pages&lt;/h3&gt;
&lt;p&gt;
This is a &lt;strong&gt;critical&lt;/strong&gt; step that you must get right. By default, Github Pages serves your site from a sub-path &lt;code class=&quot;inline&quot;&gt;(/&lt;your-repo-name&gt;/)&lt;/code&gt;, but a standard Vite app assumes it’s served from the root &lt;code class=&quot;inline&quot;&gt;(/)&lt;/code&gt;. You need to tell Vite to build your project with the correct base URL.&lt;/p&gt;
&lt;p&gt;
Edit your &lt;code class=&quot;inline&quot;&gt;vite.config.ts&lt;/code&gt; file and add the &lt;code class=&quot;inline&quot;&gt;base&lt;/code&gt; property. See &lt;a&gt;docs&lt;/a&gt; for more info.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;typescript language-typescript&quot;&gt;// vite.config.ts

// If my repo was named https://github.com/mengopudding/mengopudding.github.io
import { defineConfig } from &apos;vite&apos;
import react from &apos;@vitejs/plugin-react&apos;
import tailwindcss from &apos;@tailwindcss/vite&apos;

export default defineConfig({
  base: &apos;/&apos;, // &lt;- added line
  plugins: [react(), tailwindcss()],
})

// If my repo was named https://github.com/mengopudding/my-app
import { defineConfig } from &apos;vite&apos;
import react from &apos;@vitejs/plugin-react&apos;

export default defineConfig({
  base: &apos;/my-app/&apos;, // &lt;- remember to include both slashes wrapped in strings
  plugins: [react(), tailwindcss()],
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
The key here is the &lt;code class=&quot;inline&quot;&gt;base&lt;/code&gt; property. If your repository is named &lt;code class=&quot;inline&quot;&gt;my-app&lt;/code&gt;, your base path would be &lt;code class=&quot;inline&quot;&gt;&apos;/my-app/&apos;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;
For a &lt;code class=&quot;inline&quot;&gt;username.github.io&lt;/code&gt; repository, the &lt;code class=&quot;inline&quot;&gt;base&lt;/code&gt; path is simply &lt;code class=&quot;inline&quot;&gt;/&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
Step 5: Add a Deploy Script&lt;/h2&gt;
&lt;p&gt;
We’ll use a helpful package called &lt;code class=&quot;inline&quot;&gt;gh-pages&lt;/code&gt; to automate the build and deployment. First, install the package as a development dependency:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;bash language-bash&quot;&gt;npm install -D gh-pages&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Next, add a &lt;code class=&quot;inline&quot;&gt;homepage&lt;/code&gt; property and the &lt;code class=&quot;inline&quot;&gt;predeploy&lt;/code&gt; and &lt;code class=&quot;inline&quot;&gt;deploy&lt;/code&gt; scripts to your package.json. Make sure to replace the URL with your own.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;json language-json&quot;&gt;&quot;homepage&quot;: &quot;https://mengopudding.github.io&quot;, // &lt;- lets Github Pages know what the main landing page is
&quot;scripts&quot;: {
  &quot;dev&quot;: &quot;vite&quot;,
  &quot;build&quot;: &quot;vite build&quot;,
  &quot;preview&quot;: &quot;vite preview&quot;,
  &quot;predeploy&quot;: &quot;npm run build&quot;,
  &quot;deploy&quot;: &quot;gh-pages -d dist&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;
The &lt;code class=&quot;inline&quot;&gt;npm run build&lt;/code&gt; command takes all of your code and transforms it into a highly efficient bundle,called &lt;code class=&quot;inline&quot;&gt;dist&lt;/code&gt;.    &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
The &lt;code class=&quot;inline&quot;&gt;gh-pages -d dist&lt;/code&gt; command essentially says, “use the gh-pages tool to deploy the contents of the dist directory to a new branch called gh-pages in my repository.”    &lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
Step 6: Build and Deploy&lt;/h3&gt;
&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;
Ensure all your code is committed to your &lt;code class=&quot;inline&quot;&gt;main&lt;/code&gt; branch or that your feature branch is merged into main.     &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
Bundle up &lt;code class=&quot;inline&quot;&gt;dist&lt;/code&gt; folder with the necessary files.     &lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;bash language-bash&quot;&gt;npm run build&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
&lt;em&gt;Note:&lt;/em&gt; You will need to fix any issues like linting or TS complaints. The &lt;strong&gt;build must succeed!&lt;/strong&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
  &lt;li&gt;
Now, you can run the deploy script. This will build your app and publish the &lt;code class=&quot;inline&quot;&gt;dist&lt;/code&gt; directory to the &lt;code class=&quot;inline&quot;&gt;gh-pages&lt;/code&gt; branch on GitHub  &lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;bash language-bash&quot;&gt;npm run deploy&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
&lt;em&gt;Note&lt;/em&gt;: This will automatically create a new branch called &lt;code class=&quot;inline&quot;&gt;gh-pages&lt;/code&gt; in your repo, it will publish &lt;strong&gt;only&lt;/strong&gt; the &lt;code class=&quot;inline&quot;&gt;dist&lt;/code&gt; folder into the &lt;code class=&quot;inline&quot;&gt;gh-pages&lt;/code&gt; branch. Verify this by going to your repo.&lt;/p&gt;
&lt;h3&gt;
Step 7: Finalize Github Pages Configuration&lt;/h3&gt;
&lt;p&gt;
Go to your Github repo &lt;/p&gt;
&lt;p&gt;
Navigate to &lt;code class=&quot;inline&quot;&gt;Settings&lt;/code&gt; &gt; &lt;code class=&quot;inline&quot;&gt;Pages&lt;/code&gt; &gt; &lt;code class=&quot;inline&quot;&gt;Build and deployment&lt;/code&gt; &gt; Source: &lt;code class=&quot;inline&quot;&gt;Deploy from a branch&lt;/code&gt; &gt; select &lt;code class=&quot;inline&quot;&gt;gh-pages&lt;/code&gt; branch &lt;code class=&quot;inline&quot;&gt;/ (root)&lt;/code&gt; &gt; &lt;code class=&quot;inline&quot;&gt;Save&lt;/code&gt; &lt;/p&gt;
&lt;p&gt;
— See Github official docs for &lt;a href=&quot;https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site&quot;&gt;publishing source for your Github Pages site&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
Finally! The app will start to deploy, you can track its deployment through the Actions tab. Once deployed it will provide you with a URL to your app and… &lt;strong&gt;VOILA! CONGRATULATIONS&lt;/strong&gt;🎉 &lt;/p&gt;
&lt;h3&gt;
Troubleshooting&lt;/h3&gt;
&lt;p&gt;
All these issues can cause your app to not render once it has been deployed.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Check your build&lt;/strong&gt;: The most common issue is a failed build. The npm run deploy command will fail if your npm run build command fails. Make sure you don’t have any TypeScript errors or other issues.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Incorrect vite.config.js&lt;/strong&gt;: Have you correctly set the &lt;code class=&quot;inline&quot;&gt;base&lt;/code&gt; property?&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Missing scripts in package.json&lt;/strong&gt;: &lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
Have you set the &lt;code class=&quot;inline&quot;&gt;homepage&lt;/code&gt; key to your repo?  &lt;/li&gt;
  &lt;li&gt;
Have you added the &lt;code class=&quot;inline&quot;&gt;predeploy&lt;/code&gt; and &lt;code class=&quot;inline&quot;&gt;deploy&lt;/code&gt; script?  &lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
If you see errors like MIME type or 404&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;
&lt;strong&gt;Wait a few minutes&lt;/strong&gt;: It can take a few minutes for Github Pages to process and deploy the new changes to their servers.    &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
&lt;strong&gt;Check paths to assets&lt;/strong&gt;:  Assets are kept in the &lt;code class=&quot;inline&quot;&gt;public/assets&lt;/code&gt; folder, to reference these assets it’s best to use &lt;code class=&quot;inline&quot;&gt;relative path&lt;/code&gt;, eg.&lt;code class=&quot;inline&quot;&gt;/assets/media/hello_world.png&lt;/code&gt;    &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
&lt;strong&gt;Cache issue&lt;/strong&gt;: Sometimes, the browser caches the old version of your site. Clear your site cache and then perform a hard refresh.    &lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Right Click &gt; Inspect &gt; Application &gt; Clear site data &gt; Hard refresh&lt;/p&gt;
]]&gt;</content>
    <summary>This guide details deploying a React app (Vite) to GitHub Pages for free. Key steps include: naming your repository `username.github.io` for a root URL, creating the Vite app, configuring `vite.config.ts` with the correct `base` path, adding `gh-pages` scripts to `package.json`, running `npm run deploy`, and finally, setting GitHub Pages&apos; source to the `gh-pages` branch.</summary>
    <published>2025-09-06T02:16:31.773808Z</published>
    <link href="http://persumi.com/c/persumi/u/menglim/p/from-zero-to-deployed-a-guide-to-vite-react-and-github-pages"/>
    <author>
      <name>Meng Lim</name>
      <email>menglim.life@gmail.com</email>
      <uri>http://persumi.com/u/menglim</uri>
    </author>
    <id>http://persumi.com/c/persumi/u/menglim/p/from-zero-to-deployed-a-guide-to-vite-react-and-github-pages</id>
    <title>From Zero to Deployed: A guide to Vite, React, and Github Pages</title>
    <updated>2025-09-06T02:16:31.773808Z</updated>
  </entry>
</feed>