MAD Study Hub

Home / MAD2 / Week 3

Week 3 · The web frontend: SPAs, browser storage and tooling

Official syllabus line: Introduction to Web Frontend
About 90 minQuiz 1 material (see exam radar)BSCS2006 (+ project BSCS2006P) · Thejesh G N, Nitin Chandrachoodan
Before you start: MAD2 weeks 1 and 2 (JavaScript basics, promises, fetch). From MAD1, know that HTTP is request and response.

The one-minute story

Think of it like this

A paper form versus a whiteboard. An old-style website is a stack of paper forms: to change anything you hand the form back to the clerk (the server), who prints a whole new page and gives it to you. A single-page application (SPA) is a whiteboard on your desk: the clerk gives you the board once, and from then on you rub out and rewrite only the part that changed. You only call the clerk when you need fresh facts (an API call, with fetch from week 2).

But a whiteboard needs care. If your notes are only on the board (in the page's memory) and someone refreshes the page, they vanish. So you decide where each fact lives: on the clerk's shelf (server database), in your pocket (browser storage), on the whiteboard (memory), or written on the address (the URL). And keeping the board in sync with your notes by hand gets painful, which is why frameworks such as Vue exist. Lastly there is the toolbox (npm, bundlers, dev server) that builds and runs all this.

By the end of this week you can:

  • compare multi-page and single-page apps and explain client-side routing;
  • choose between cookies, localStorage, sessionStorage and IndexedDB and predict storage code;
  • explain what a service worker and a PWA are;
  • explain why frameworks and the virtual DOM exist, and what package.json, node_modules, Vite or webpack and Babel do;
  • say where the state of a web application lives, and why HTTP being stateless matters.

Words you need

Words you need
  • MPA (multi-page app) - every click asks the server for a new full HTML page.
  • SPA (single-page app) - one HTML page is loaded once; JavaScript redraws parts and fetches data.
  • Client-side routing - changing the URL and the view in the browser without asking the server for a new page.
  • Origin - scheme + host + port, such as http://localhost:8080. Storage is separated per origin.
  • Cookie - a tiny named value the server (or script) stores in the browser; it travels with every request to that site.
  • Web Storage - localStorage and sessionStorage: key-value text in the browser.
  • IndexedDB - a bigger, asynchronous database in the browser for objects and files.
  • Service worker - a background script that sits between page and network and can serve cached files offline.
  • PWA - a web app made installable and offline-capable with a manifest and a service worker.
  • Virtual DOM - a light copy of the page in memory used to work out the smallest real change.
  • npm - Node's package manager; reads package.json and fills node_modules.
  • Bundler - a tool (webpack, Vite) that combines your many files into a few optimized ones.
  • Transpiling - converting new JavaScript into older JavaScript old browsers understand (Babel).
  • Hot reload - the dev server updates the page when you save, without a full refresh.
  • Stateless - the server does not remember you between requests by itself.

Idea 1: Multi-page apps, single-page apps and routing

MPA (traditional)SPA
Click on a linkfull page request, white flashJavaScript swaps the view, no reload
What the server sendsfinished HTML for each pageone HTML shell + JS once, then JSON from APIs
Speed after first loadslower (whole page again)fast, smooth, app-like
First loadquick (just HTML)slower (download the JS bundle first)
SEO / search engineseasy: the HTML already has the contentharder: content is built by JS (fixed by server-side rendering)
Server loadhigher (renders every page)lower (only data)
Examplea classic shopping site, a Flask app with Jinja templatesGmail-style apps, your Vue project
The idea

Client-side routing: the SPA watches the URL and shows the matching component, without a request for a new page. Vue Router 3 has two modes:

  • hash mode (default): http://localhost:8080/#/records/2. The part after # never goes to the server, so the server needs no special setup.
  • history mode: http://localhost:8080/records/2, clean URLs, but the server must send the same index.html for every path, or a refresh gives a 404.

This is why exam questions give both .../records/1 and .../#/records/1 and ask which one renders: in hash mode the router only reads what is after #. In history mode /#/inventory/102 does not match the route /inventory/:id, because the path is then just /.

A SPA still talks to a backend: your Flask API returns JSON and the Vue code draws it (week 2's fetch).

Watch out - real exam trap
  • SPAs do not load the whole page on every click; that is the MPA behaviour.
  • "The idea of an SPA is to improve SEO" is false. SEO is normally the SPA's weak spot.
  • gmail.com is SPA-like; amazon.in is a classic multi-page site. "Both are SPAs" is false.
  • Papers disagree on one claim: "client-side routing gives better SEO by default" is marked correct in one End Term and wrong in another. Safe, agreed benefits: faster navigation, no full reload, less load on the backend.
Your turn: 1. SPA or MPA

Which of these describe an SPA? (a) The server returns finished HTML for every click. (b) After the first load only JSON travels. (c) The URL can change without a page reload. (d) It works best for search-engine visibility without extra work.

Need a hint?

Think about what the server sends.

Show the full solution

(b) and (c). (a) is MPA behaviour. (d) is not an SPA strength; it needs server-side rendering or similar help.

Idea 2: Browser storage

A web page can keep data in the browser in four main ways. Know their differences cold; the papers ask matching and "which statement is true" questions.

CookielocalStoragesessionStorageIndexedDB
Size (about)about 4 KB eachabout 5 MB per originabout 5 MB per originvery large (a share of the disk)
Lifetimeuntil its expiry date (or end of session if none)forever until cleared by code or useruntil the tab is closed (survives reload)until cleared
Sent to the serveryes, on every request to that sitenonono
Shared across tabsyes (same site)yes (same origin)no, each tab has its ownyes (same origin)
Who can readthe server, and JS (unless HttpOnly)JS of the same originJS of that tab, same originJS of the same origin
Data typesmall texttext only (strings)text only (strings)objects, blobs, files, audio, video
APIdocument.cookie, Set-Cookie headergetItem, setItem, removeItem, clearthe same fourasynchronous, with requests or promises

All storage is per origin and per browser: nothing is shared across devices or across different websites. Storage is not secure: any script on the page can read it, so never keep passwords there (tokens are stored there in practice, with that risk).

// browser
localStorage.setItem("theme", "dark");           // value becomes the string "dark"
localStorage.getItem("theme");                   // "dark"
localStorage.getItem("missing");                 // null   (getItem returns null if absent)
localStorage.missing;                            // undefined   (property style returns undefined)
localStorage.setItem("n", 5);                    // stored as "5"
typeof localStorage.getItem("n");                // "string"
localStorage.setItem("user", JSON.stringify({ id: 1 }));
JSON.parse(localStorage.getItem("user")).id;     // 1    objects need JSON both ways
localStorage.removeItem("theme"); localStorage.clear();
The idea

Everything in Web Storage is a string. setItem("n", 5) stores "5"; getItem("n") + 1 is "51"; getItem("n") * 2 is 10. Objects need JSON.stringify to store and JSON.parse to read.

Solved example: 1. Predict the storage output
// browser
localStorage.setItem('counter', '0');
sessionStorage.setItem('total', '5');
for (let i = 0; i < 3; i++) {
  let counter = localStorage.getItem('counter');
  let total = sessionStorage.getItem('total');
  counter += 2;
  total *= 2;
  localStorage.setItem('counter', counter);
  sessionStorage.setItem('total', total);
}
sessionStorage.clear();
console.log(localStorage.getItem('counter'));
console.log(sessionStorage.getItem('total'));

counter is the string "0", so counter += 2 joins: "02", then "022", then "0222". total is "5", and *= converts to a number: 10, 20, 40. Then sessionStorage.clear() removes everything, so the last line is null (not undefined: getItem returns null). Printed: 0222 and null.

A sibling question starts with score = '10' and multiplier = '3', runs the loop twice with score + 5 and multiplier * 2: "105", "1055" and 6, 12. The printed 1055 and 12 appeared as "None of these" among the options.

Solved example: 2. "Refresh the page N times"

A very common long question: a Vue-style component whose mounted() reads storage, then writes it back changed. The skill is to trace the storage after each refresh.

// browser: runs on every page load
let name, age;
try {
  const parts = localStorage.getItem("name").split(" ");   // fails with TypeError on null
  name = parts[0];
  age = parts[1];
  localStorage.setItem("name", parts[0] + " " + name);     // writes back
} catch {
  name = "Default"; age = "Default";
}

Suppose the user types IIT Madras and a button saves it to localStorage.name.

  • First ever load, storage empty: getItem returns null, .split throws, the catch sets Default, Default.
  • Refresh 1: reads "IIT Madras". name = "IIT", age = "Madras". Shows IIT, Madras. Writes back "IIT" + " " + "IIT" = "IIT IIT".
  • Refresh 2: reads "IIT IIT". Shows IIT, IIT. Writes "IIT IIT" again. It stays that way forever.

Always ask: what was in storage before this load, what did the code show, and what did it write after?

Watch out - real exam trap
  • localStorage.getItem(missing) is null; localStorage.missing is undefined.
  • Values come back as strings: "3" + 2 is "32".
  • sessionStorage is per tab: a fresh new tab does not see it; localStorage is shared by all tabs of the origin and survives closing the browser.
  • A reload does not clear sessionStorage; closing the tab does.
  • Storage does not travel between devices and is not sent to the server (unlike cookies).
Your turn: 2. Match the storage

Which storage fits: (a) the user's dark-mode choice, kept after the browser restarts; (b) a half-filled form that should vanish when the tab closes; (c) a login cookie the server must receive on every request; (d) 200 MB of cached video for offline use.

Need a hint?

Think about lifetime and size.

Show the full solution

(a) localStorage. (b) sessionStorage. (c) a cookie (the only one sent to the server automatically). (d) IndexedDB (the only one built for large data and files).

Your turn: 3. Predict
// browser
sessionStorage.setItem("username", "course_user");
const a = sessionStorage.getItem("username");
sessionStorage.removeItem("username");
const b = sessionStorage.getItem("username");
sessionStorage.clear();
const c = sessionStorage.username;

What are a, b, c?

Need a hint?

getItem and property access differ for missing keys.

Show the full solution

a is 'course_user', b is null, c is undefined.

Idea 3: Statelessness and where state lives

HTTP is stateless: each request stands alone, and the server does not automatically remember the previous one. Yet apps remember you are logged in and what is in your cart. The state is kept somewhere and explicitly sent along with requests.

WhereExamplesSurvives reload?Shared with others?
Server (database, cache)users, products, ordersyesyes, the source of truth
Client memory (JS variables, Vue data)which tab is open, loading flag, text typed so farnono
Browser storagetheme, token, saved draftyesno (this browser only)
URL (path, ?query, #)current page, search text, page numberyes, and bookmarkableyes, by sharing the link
Cookie / tokensession id, login tokenyessent with each request
  • UI state (ephemeral state): short-lived interface facts such as a loading spinner, which tab is selected, a dropdown open or closed. It lives in the component and can be lost.
  • Application state: real data (users, products), usually owned by the server, and cached in the frontend (week 4's Vuex).
The idea

Rule of thumb. Truth lives on the server. Convenience copies live in the client. What should survive a reload, or be shared by link, goes in storage or in the URL. Because HTTP is stateless, the client or server holds the state and sends it in each request (cookie, token, query string).

Your turn: 4. Where does it live?

Where would you keep: (a) the list of all students; (b) whether a modal is open; (c) the page number of a table you want to bookmark; (d) the login token?

Need a hint?

Ask: who needs it, and must it survive reload?

Show the full solution

(a) the server (database), fetched through the API. (b) component memory (UI state). (c) the URL query (?page=3). (d) browser storage (or a cookie), sent with each request.

Idea 4: Why frameworks exist

With plain JavaScript you change the page by hand:

// browser: the manual way
let count = 0;
document.querySelector("#plus").addEventListener("click", () => {
  count++;
  document.querySelector("#out").textContent = count;      // you must remember to update the page
});

With ten pieces of data shown in five places, you will forget one, and the page and the data drift apart. A framework makes the page a function of the state: change the data and the framework updates the page.

<div id="app">{{ count }} <button @click="count++">+</button></div>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
  new Vue({ el: "#app", data: { count: 0 } });    // Vue 2: click changes data, page follows
</script>
  • Virtual DOM. Touching the real DOM is slow. The framework keeps a light JavaScript copy of the page. When data changes it builds a new virtual tree, compares it to the old one (the "diff") and patches only the real nodes that differ. So Vue "detects the change and updates efficiently"; it does not reload the page or rebuild everything.
  • Components. The page is built from reusable pieces (a navbar, a card), each with its own template, data and methods. Advantages: reusability, maintainability, easier UI management.
  • Reactivity (Vue 2). Vue wraps your data properties so it knows when they change. A limit: a property added later, or arr[0] = x, is not noticed; use this.$set(...) or array methods like push. (Vue 3 uses Proxies and has no such limit.)
VueReactAngular
Kindprogressive frameworkUI libraryfull framework
Made byEvan You and communityMetaGoogle
TemplatesHTML-like templates, optional single-file componentsJSX (HTML inside JS)HTML templates + TypeScript
Learning curvegentle; can be added with one script tagmoderatesteep, many built-in parts

The course uses Vue 2 with Vue Router 3 and Vuex 3. In newer Vue (3) the same ideas apply, with Pinia replacing Vuex.

Idea 5: Tooling, npm, bundlers and dev servers

Two ways to start with Vue:

CDN script tagVue CLI / build tools
Setupone script tag, no installnpm + a generated project
Templatescompiled in the browsercompiled at build time (faster)
.vue single-file componentsnoyes
Modern syntax, minify, tree-shakingnoyes (via Babel and the bundler)
Best fordemos, small pages, learningreal projects, teams

npm and package.json. npm downloads packages. The project's package.json lists them. npm install reads it and fills the node_modules folder (huge; never commit it, it is rebuilt from package.json and package-lock.json).

{
  "name": "my-vue-app",
  "version": "0.1.0",
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": { "vue": "^2.6.14" },
  "devDependencies": { "@vue/cli-service": "^5.0.0", "babel-eslint": "^10.1.0" }
}
  • dependencies are needed by the running app; devDependencies only while developing and building.
  • ^2.6.14 means "2.6.14 or any newer 2.x" (same major version); ~2.6.14 allows only newer patches.
  • scripts are run with npm run name. npm run serve starts the dev server (usually localhost:8080) with hot reload. npm run build makes the optimized production files in the dist folder and does not start a server.
  • npm install vue@2 adds a dependency; npm install -D pkg adds a dev dependency; npx runs a tool without installing it globally.
Solved example: 3. Which command?

A developer creates a Vue 2 project and runs npm run build hoping to see the app in the browser. What happens?

build compiles and bundles the app for production into dist/. It starts nothing. She should run npm run serve for the local dev server with hot reload. The same two scripts exist in every Vue CLI project because package.json defines them.

What the build tools do.

  • Bundler (webpack inside Vue CLI; Vite in the newer Vue starter): follows your imports, joins many files into a few, minifies them, removes unused code (tree-shaking) and handles .vue files, CSS and images. Webpack bundles first and is configuration-heavy; Vite serves your modules directly during development, so it starts and updates very fast.
  • Transpiling (Babel): rewrites new syntax (arrow functions, ?., classes) into older JavaScript so old browsers can run it.
  • Dev server + hot reload (HMR): save a file and the changed part is swapped into the open page, often keeping your current state.
Watch out - real exam trap
  • npm run build does not start the app; npm run serve does (in Vue CLI projects).
  • node_modules is not committed and not edited by hand.
  • Vue can be installed through npm (a False-statement question said "it cannot be").
  • A CDN script is fine for a demo; a real project uses the build tools.

Idea 6: Service workers, PWAs, responsive design and accessibility

Web worker: runs JavaScript on a separate thread so heavy work does not freeze the page. It cannot touch the DOM; it talks to the page with postMessage.

Service worker: a special worker that sits between your page and the network. It can intercept requests, answer from a cache, work offline, and receive push notifications. It runs only on HTTPS (and localhost for development).

// browser
if ("serviceWorker" in navigator) {
  navigator.serviceWorker.register("/sw.js");        // sw.js decides what to cache and serve
}

PWA (Progressive Web App): an ordinary web app plus

  • a web app manifest (a JSON file: name, icons, start URL, display mode), which lets it be installed on the home screen and look like a native app;
  • a service worker, giving offline support and fast loads;
  • served over HTTPS.

It needs no app store and no native code, and it can work with a poor or no connection.

Responsive design: one page that adapts to any screen size. Tools: the viewport tag, CSS media queries, flexbox and grid, relative units.

<meta name="viewport" content="width=device-width, initial-scale=1">
.card { width: 30%; }
@media (max-width: 600px) { .card { width: 100%; } }   /* on a phone, cards go full width */

Accessibility reminder: use real elements (button, label, headings), give images alt text, make everything usable with a keyboard, keep good colour contrast, and let screen readers understand the page (ARIA only when plain HTML is not enough).

Your turn: 5. True or false

(a) A PWA must be downloaded from an app store. (b) A service worker lets a PWA show cached pages offline. (c) PWAs can be added to the home screen. (d) A web worker can change the DOM directly.

Need a hint?

Recall what each piece does.

Show the full solution

(a) False. (b) True. (c) True. (d) False; workers have no DOM access.

Idea 7: Debugging the frontend with dev tools

Press F12. The tabs you use:

TabUse
Elementssee and edit the live DOM and CSS
Consoleread errors and console.log, run JavaScript
Networksee every request: URL, method, status code, request and response, timing (check your fetch here)
Applicationinspect and edit cookies, localStorage, sessionStorage, IndexedDB, service workers and the manifest
Sourcesset breakpoints and step through code
Device toolbartest a phone-sized screen (responsive design)

The Vue devtools extension adds a tab showing components, their data, and Vuex state. Debug order: Console for the error message, Network for what the server answered (status, response body), Application for what is stored.

In your project

Be ready to demo this in the viva: open the Network tab and show your API call and its status code; open Application and show the token in storage; change a store value and show the page update. Also be ready for "why is your project an SPA, and what happens on refresh?".

Exam radar

Exam radar

The keyword scan finds about 32 distinct questions for this week (about 7 in Quiz 1, 57 in Quiz 2 and 39 in the End Term by keyword, so approximate). Most are storage questions; they are also the easiest to get right:

  • Predict the storage output (string joining with +, null after clear), and "refresh the page N times" traces.
  • True/false on Web Storage (localStorage never expires; sessionStorage is per tab, not shared across tabs).
  • SPA/PWA statements (client-side routing, service workers, home screen, offline).
  • Client-side storage advantages (preferences, offline documents, IndexedDB for audio/video; not "data stored across devices").
  • Tooling: npm run build versus npm run serve; "Vue cannot be used through npm" (false); component advantages; virtual DOM.
  • State: UI (ephemeral) state; HTTP is stateless so state is exchanged in requests.
Watch out - real exam trap
  • A new tab: localStorage yes, sessionStorage no.
  • getItem of a missing key is null.
  • Stored numbers come back as strings.
  • Client-side storage never syncs across devices.

Quick quiz

Quick quiz

Tab 1 runs localStorage.setItem("theme","dark"); sessionStorage.setItem("cart","3-items");. A fresh Tab 2 on the same site then reads both. What do they return?

  • both values
  • both null
  • "dark" for theme, null for cart
  • null for theme, "3-items" for cart
localStorage is shared by all tabs of an origin; sessionStorage belongs to one tab.

localStorage.setItem('c','0'); let c = localStorage.getItem('c'); c += 2; console.log(c) prints...

  • 2
  • 02
  • 0
  • NaN
The stored value is the string "0", so += joins text.

Which are advantages of client-side storage? (Select all) (select all that apply)

  • Storing personalised site preferences
  • IndexedDB can hold large files such as audio and video
  • Saving generated documents for offline use
  • The data is shared across all your devices
Browser storage is local to one browser on one device.

Select all TRUE statements about SPAs and PWAs. (select all that apply)

  • SPAs often use client-side routing to update content without full reloads.
  • PWAs use service workers for offline use.
  • PWAs always need an internet connection.
  • SPAs load a whole new page from the server on each interaction.
The last two describe the opposite of the real behaviour.

In a Vue CLI project, which command makes the production files in dist without starting a server?

  • npm run serve
  • npm run build
  • npm start dev
  • npm install
serve starts the dev server; build compiles for production.

In Vue 2, what happens when you change a data property?

  • The page reloads
  • Nothing until you refresh
  • The virtual DOM finds the difference and updates only what changed
  • The whole page is rebuilt from scratch
Efficient diffing is the point of the virtual DOM.

Viva: say it out loud

Viva: say it out loud
What is a single-page application and why did you choose one?

An SPA loads one HTML page and JavaScript once, then changes the view in the browser and gets only data (JSON) from the API. It gives fast, app-like navigation and puts less load on the server, and it fits a Vue frontend over a Flask API.

What is client-side routing?

The browser, not the server, decides which view to show for a URL. Vue Router changes the component when the URL changes, in hash mode (after #) or history mode, so there is no full page reload.

Where is the login token stored in your project, and what are the risks?

It is kept in localStorage (or a cookie) and sent in the Authorization header with each request. Any script on the page can read localStorage, so XSS is a risk, and the token is lost if the user clears the browser data.

What is the difference between localStorage and sessionStorage?

localStorage stays until cleared and is shared across tabs of the same origin. sessionStorage lives only as long as that one tab and is not shared. Both hold strings and are about 5 MB.

What does the virtual DOM do?

It is a lightweight copy of the page in memory. When the data changes, the framework builds a new copy, compares it with the old one, and applies only the real differences to the page.

What are package.json and node_modules?

package.json lists the project's name, scripts and dependencies. npm install downloads those packages into node_modules, which is large and not committed.

What is a PWA?

A web app with a manifest and a service worker (over HTTPS). It can be installed on the home screen and work offline, without an app store.

Recap

Remember this
  • MPA: new full page per click. SPA: one shell, JavaScript redraws, JSON from APIs. SPA is fast and light on the server, weaker for SEO.
  • Client-side routing: hash mode (/#/path) needs no server setup; history mode needs a fallback to index.html.
  • Cookies (4 KB, sent to server), localStorage (persistent, shared by tabs), sessionStorage (per tab), IndexedDB (large, async, files).
  • Web Storage holds strings: "0" + 2 is "02"; missing key gives null.
  • HTTP is stateless; state lives on the server, in memory, in storage or in the URL, and is sent explicitly.
  • Frameworks keep UI in sync with state; the virtual DOM patches only differences; components give reuse.
  • package.json + npm install fill node_modules; npm run serve for development, npm run build for dist/; bundlers (webpack, Vite) and Babel prepare the code.
  • PWA = manifest + service worker + HTTPS. Responsive = viewport + media queries. Use dev tools (Network, Application).
Code and facts to keep
  • localStorage.setItem(k, v), getItem(k) (null if missing), removeItem(k), clear(); sessionStorage has the same API
  • JSON.stringify(obj) before storing, JSON.parse(str) after reading
  • Sizes: cookie about 4 KB; web storage about 5 MB per origin
  • npm install, npm run serve (dev, hot reload), npm run build (to dist/)
  • ^2.6.14 = same major, newer minor and patch allowed
  • <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>; new Vue({ el: "#app", data: {} })
  • navigator.serviceWorker.register("/sw.js"); manifest = name, icons, start_url, display
  • <meta name="viewport" content="width=device-width, initial-scale=1">
Connected weeks (learn them together)

Practise with real exam questions

These come straight from past papers (with the real figures and the official answer key). Open 60 real questions on this week   All Quiz 1 papers