Webbo3 Level 2 · JavaScript Development · Day 18 of 20
Shipping It
Getting your project off your laptop and onto a URL you can send to somebody who has never met you.
By the end of today you can
- Deploy a static site to a real URL over https
- Say what a build step actually does and why it exists
- Keep configuration out of code and secrets out of the repository
- Write a README a stranger can follow
- Read a Lighthouse report and fix what it finds
"It works on my laptop" is not a finished project. Until somebody else can open it on their own phone, on their own connection, you do not actually know that it works: you know that it works in the one environment where every file is local, every path is right and the network is perfect.
1. Development and production are different places
| Development | Production | |
|---|---|---|
| Where | Your machine, localhost | A server, a real domain |
| Files | Separate and readable | Often bundled and minified |
| Errors | Full detail in your console | Logged, never shown to the user |
| Data | Test records you invented | Real people's real data |
| Network | Instant | Whatever the user has |
| Who sees a crash | You | Everybody |
The bugs that only appear in production, in order of frequency
A path that works locally and not when served (/css/style.css against css/style.css). A file name whose capitalisation differs, which your laptop forgives and Linux does not. A mixed-content block because one asset is http on an https page. And an API that allowed localhost but not your new domain.
2. Deploying a static site
Your projects are HTML, CSS and JavaScript with no server. That is the easiest thing in the world to host, and all three of these are free.
| Host | How | Good for |
|---|---|---|
| GitHub Pages | Repository Settings, Pages, choose the branch | Simplest. Already where your code is |
| Netlify | Connect the repository, or drag the folder in | Redirects, forms, previews of every pull request |
| Vercel | Connect the repository | Same idea, strong with frameworks later |
# GitHub Pages, from scratch
git add .
git commit -m "Add README and deploy configuration"
git push
# then: repo -> Settings -> Pages -> Source: deploy from branch -> main -> / (root)
# your site appears at https://<username>.github.io/<repo>/ within a minute or twoThe first deploy is nearly always broken, and nearly always the same way
A blank page with 404 errors in the console means your paths are absolute. /css/style.css means "the root of the domain", which on GitHub Pages is not your project folder. Use relative paths: css/style.css and ./js/app.js. This single issue accounts for most first deployments.
- Check every path is relative, including images and imports.
- Check capitalisation on every filename.
Logo.PNGandlogo.pngare the same file on your laptop and two different files on the server. - Open the deployed site on your phone, on mobile data, not on your wifi.
- Open the Console on the deployed site. It is not the same as your local one.
3. What a build step is
You have not needed one yet, and it is worth knowing what it would do before Level 3 hands you one.
| Stage | What happens | Why |
|---|---|---|
| Bundle | Many modules become few files | Fewer requests |
| Minify | Whitespace, names and comments stripped | Smaller download |
| Transpile | Newer syntax rewritten to older | Older browsers |
| Hash | app.js becomes app.8f3c1d.js | Cache safely: a new name is always fetched fresh |
| Inline env | import.meta.env.X replaced by its value at build time | Configuration without editing code |
A build step does not make a secret secret
Values inlined at build time end up in the bundle, which is a text file anybody can read. VITE_API_KEY in a frontend bundle is exactly as public as writing it in your HTML. The build step moved it; it did not hide it.
4. Configuration that changes between places
// config.js - one place, no magic strings scattered through the code
const isLocal = window.location.hostname === 'localhost'
|| window.location.hostname === '127.0.0.1';
export const config = {
apiBase: isLocal ? 'http://localhost:3000' : 'https://api.webbo3.com',
pageSize: 10,
debug: isLocal
};Then nothing else in your codebase contains a URL. When the API moves, you change one line. When you deploy, the right value is chosen for you. And config.debug is how you keep your noisy logs locally without shipping them.
5. The README
This is the part students skip and employers read first. Yours is often the only thing somebody looks at before deciding whether to open your code.
# Job Application Tracker
Track job applications and see at a glance which ones need chasing.
**Live:** https://chidinma.github.io/job-tracker/

## Why I built it
I was losing track of which applications I had heard back from. Everything
lived in my head and in a WhatsApp message to myself.
## Features
- Add, edit and delete applications
- Filter by status, search by company
- Flags anything still "applied" after 14 days
- Saves in the browser, so it survives a refresh
- Works with a keyboard only; Lighthouse accessibility 100
## Running it locally
```
git clone https://github.com/chidinma/job-tracker.git
cd job-tracker
# any static server, e.g.
npx serve .
```
Needs a server rather than opening the file directly, because it uses ES modules.
## Built with
Vanilla JavaScript, no frameworks. ES modules, localStorage, CSS Grid.
## What I would do next
- Move storage to a backend so it syncs between devices
- Export to CSV
- Email reminders, which need a server
## What is deliberately out of scope
No accounts, no backend, no file uploads. One person, one browser.- The live link goes at the top. Most readers will click it and never scroll.
- A screenshot. Somebody scrolling twenty repositories will look at a picture and not read a paragraph.
- "What I would do next" signals that you know what is missing, which reads as judgement rather than as a gap.
6. Lighthouse before you call it done
DevTools, Lighthouse tab, tick all four categories, run it against your deployed URL rather than localhost.
| Category | Aim for | Usually caused by |
|---|---|---|
| Performance | 90+ | Unresized images, render-blocking scripts |
| Accessibility | 95+ | Contrast, missing labels, missing alt |
| Best Practices | 95+ | Console errors, mixed content |
| SEO | 90+ | Missing title, description, or viewport meta |
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Job Application Tracker</title>
<meta name="description" content="Track job applications and see which need chasing.">
<!-- what appears when the link is shared -->
<meta property="og:title" content="Job Application Tracker">
<meta property="og:description" content="Track job applications and see which need chasing.">
<meta property="og:image" content="https://chidinma.github.io/job-tracker/docs/preview.png">
</head>Why the og: tags are worth five minutes
They are what renders when you paste your link into WhatsApp, LinkedIn or Slack. Without them your portfolio project appears as a bare URL. With them it appears as a card with a title and a picture. You will be pasting these links into applications, so this is not decoration.
Do this now
- Deploy your Day 15 project. Get a real https URL.
- Fix the first deploy. Expect broken paths and at least one capitalisation problem.
- Open it on your phone, on mobile data, and use it properly for two minutes.
- Write the README to the shape above, screenshot included.
- Run Lighthouse on the deployed URL. Get Accessibility above 95 and fix every console error.
- Send the link to somebody who has never seen it and watch them use it without helping. Write down every moment they hesitate.
That last one is the whole exercise
Watching one person use your project without your commentary will teach you more than any checklist on this page. Every hesitation is a design problem you could not see because you already knew the answer.
Checkpoint
Q1. Your deployed site is blank with 404s in the console. Most likely cause?
Absolute paths. /css/style.css points at the domain root, which is not your project folder on GitHub Pages. Use relative paths.
Q2. It works locally but an image 404s on the server. Why?
Capitalisation. Your laptop's filesystem is usually case-insensitive and the server's is not, so Logo.PNG and logo.png are two different files there.
Q3. Does a build step make an API key safe?
No. Values inlined at build time are in the bundle, which is a text file anybody can read. It moved the key; it did not hide it.
Q4. Why run Lighthouse against the deployed URL rather than localhost?
Because localhost has no real network, no compression and no caching headers, so the performance numbers are meaningless. Some best-practice checks also depend on https.
Tick before you move on
- ☐ My project is deployed and I have opened it on my phone on mobile data
- ☐ Every path is relative and every filename matches its capitalisation
- ☐ README has the live link, a screenshot and a what-next section
- ☐ Lighthouse Accessibility above 95, and zero console errors
- ☐ Somebody else used it in front of me without my help
Quick recap
Not finished until a stranger can open it on their own phone · Relative paths and exact capitalisation, or the first deploy is blank · A build step bundles and inlines; it does not create secrets · The README is read before the code, so put the live link and a screenshot first · Lighthouse on the deployed URL, never on localhost
Tomorrow, Day 19: turning four projects into something an employer can read in ninety seconds.