Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/apursley2012/magical/llms.txt

Use this file to discover all available pages before exploring further.

Once you’ve run npm run build and confirmed the output looks right with npm run preview, you’re ready to ship. Magical Portfolio’s dist/ folder is pure static output — HTML, CSS, and JavaScript with no server-side dependencies — which means it can be deployed to virtually any hosting platform in minutes. The three options below cover the most common paths: GitHub Pages for free hosting tied to your GitHub account, Netlify for zero-config continuous deployment with a generous free tier, and Vercel for the same one-click flow with excellent edge performance. Pick the one that fits your workflow.
GitHub Pages hosts static sites directly from a GitHub repository branch. You can deploy by pushing the dist/ folder to a gh-pages branch manually using the gh-pages npm package, or you can automate the entire process with a GitHub Actions workflow that builds and deploys on every push to main.

Option A — Deploy with the gh-pages package

1

Install the gh-pages package

Add gh-pages as a development dependency:
npm install --save-dev gh-pages
2

Add deploy scripts to package.json

Open package.json and add two entries to the "scripts" block:
{
  "scripts": {
    "predeploy": "npm run build",
    "deploy": "gh-pages -d dist"
  }
}
predeploy runs automatically before deploy, so the bundle is always fresh before it’s pushed.
3

Set the homepage field

Also in package.json, add a "homepage" field pointing to your GitHub Pages URL. Replace <username> and <repo> with your GitHub username and repository name:
{
  "homepage": "https://<username>.github.io/<repo>"
}
4

Run the deploy command

Push the built dist/ folder to the gh-pages branch:
npm run deploy
The command builds the project, then uses the gh-pages CLI to force-push the contents of dist/ to the gh-pages branch of your remote repository. GitHub Pages picks up the change within a minute or two.
5

Enable GitHub Pages in repo settings

In your repository on GitHub, go to Settings → Pages and set the source branch to gh-pages with the root folder (/) as the publish directory. Your site will be live at https://<username>.github.io/<repo>.

Option B — Deploy with GitHub Actions

For a fully automated pipeline that builds and deploys on every push to main, add the following workflow file to your repository:
# .github/workflows/deploy.yml
name: Deploy to GitHub Pages

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 18
      - run: npm ci
      - run: npm run build
      - uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./dist
Commit this file to .github/workflows/deploy.yml, push to main, and the Actions runner will install dependencies, build the project, and push the freshly compiled dist/ folder to the gh-pages branch automatically. No local npm run deploy needed.
The .nojekyll file already present in the repository root is important here. When GitHub Pages serves your site, it normally runs the content through Jekyll first. Jekyll would attempt to process the HTML shims and could interfere with Vite’s ES module <script> tags. The empty .nojekyll file signals GitHub Pages to skip Jekyll entirely and serve the files exactly as built. Without it, your routes might load a blank page or throw a 404 on assets.

After deployment

Verify all routes load correctly

Once the site is live, click through every page to confirm the hash routing shims are working end-to-end:
  • Visit the root URL (e.g. https://yoursite.example.com) — confirms index.html and the #/ route work.
  • Navigate directly to each page shim by appending the path:
    • /pages/About.html → should redirect to /pages/About.html#/about and render the About page
    • /pages/Projects.html → should render the Projects page
    • /pages/Skills.html, /pages/Writing.html, /pages/CaseStudies.html, /pages/Contact.html — same pattern
  • Hard-refresh on each page (Ctrl+Shift+R / Cmd+Shift+R) to confirm the shim script fires on a cold load.
  • Check your browser’s DevTools console for any 404 errors on assets.

Custom domain

All three platforms support custom domains:
  • GitHub Pages — go to Settings → Pages → Custom domain in your repository.
  • Netlify — go to Site settings → Domain management → Add custom domain.
  • Vercel — go to Project Settings → Domains → Add domain.
All three also provision a free TLS certificate automatically via Let’s Encrypt once DNS is pointed at their nameservers or records.
Set cache headers to maximise performance. Vite outputs JavaScript and CSS files with content-hashed filenames (e.g. main-a1b2c3d4.js), meaning the filename changes whenever the content changes. You can safely tell browsers to cache these files for a very long time. The HTML shims, on the other hand, must not be cached aggressively because they’re the files that bootstrap the correct bundle version on every deploy.Recommended cache strategy:
Path patternCache-Control value
assets/*public, max-age=31536000, immutable
components/*public, max-age=31536000, immutable
*.htmlpublic, max-age=0, must-revalidate
On Netlify, add a netlify.toml to the repository root:
[[headers]]
  for = "/assets/*"
  [headers.values]
    Cache-Control = "public, max-age=31536000, immutable"

[[headers]]
  for = "/components/*"
  [headers.values]
    Cache-Control = "public, max-age=31536000, immutable"

[[headers]]
  for = "/*.html"
  [headers.values]
    Cache-Control = "public, max-age=0, must-revalidate"
On Vercel, add a vercel.json to the repository root:
{
  "headers": [
    {
      "source": "/assets/(.*)",
      "headers": [{ "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }]
    },
    {
      "source": "/components/(.*)",
      "headers": [{ "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }]
    },
    {
      "source": "/(.*).html",
      "headers": [{ "key": "Cache-Control", "value": "public, max-age=0, must-revalidate" }]
    }
  ]
}

Build docs developers (and LLMs) love